Reputation: 11
I want to cut out a part of a postscript page from C#, rotate the result and save it as a new postscript page.
My source file is a Postscript page in A4, in portrait format. The page consists of four quadrants, each quadrant is an A6 in portrait format. I want to cut out the upper left quadrant. This results in an A6 format page. At the end I want to turn this A6 page 90° clockwise and output it as a postscript file again.
I would like to call this process from a C# application under Windows, for this I would like to use a .Net-wrapper for Ghostscript.
I can perform the task from the command line with the following code:
"c:\Program Files (x86)\gs\gs9.50\bin\gswin32c.exe" ^
-o output_A6_upper_left_quadrant.ps ^
-sDEVICE=ps2write ^
-g4210x2970 ^
-c "<</Install {-421 297 translate 270 rotate}>> setpagedevice" ^
-f input_4_Quadrants_A4.ps
(I have also tried a variant with PageOffset and Orientation, but that did not work for me under Windows.)
To do the task from C#, I tried Ghostscript.Net and GhostscriptSharp. Unfortunately both were unsuccessful.
I tried this code with Ghostscript.net, inspired by the includes samples:
namespace Ghostscript.NET.Samples
{
public class ProcessorSample3 : ISample
{
public void Start()
{
string inputFile = @"C:\Users\plehn\test\input_4_Quadrants_A4.ps";
string outputFile = @"C:\Users\plehn\test\output_A6_upper_left_quadrant.ps";
using (GhostscriptProcessor ghostscript = new GhostscriptProcessor())
{
ghostscript.Processing += new GhostscriptProcessorProcessingEventHandler(ghostscript_Processing);
List<string> switches = new List<string>();
switches.Add("-empty");
switches.Add("-dBATCH");
switches.Add("-dNOPAUSE");
switches.Add("-sOutputFile=" + outputFile);
switches.Add("-sDEVICE=ps2write");
switches.Add("-g4210x2970");
// the following switch seems to be ignored…
switches.Add(@"-c ""<</Install {-421 297 translate 270 rotate}>> setpagedevice""");
switches.Add("-f");
switches.Add(inputFile);
ghostscript.Process(switches.ToArray());
}
}
void ghostscript_Processing(object sender, GhostscriptProcessorProcessingEventArgs e)
{
Console.WriteLine(e.CurrentPage.ToString() + " / " + e.CurrentPage.ToString());
}
}
}
And this is the code I tried with GhostscriptSharp:
Using this call:
GhostscriptWrapper.CropPage(@"C:\Users\plehn\test\input_4_Quadrants_A4.ps", @"C:\Users\plehn\test\output_A6_upper_left_quadrant.ps", 421, 297, -421, 297, 270);
and I added another function in the public class GhostscriptWrapper
/// <summary>
/// Crops a document using the parameters
/// </summary>
/// <param name="inputPath">file to crop</param>
/// <param name="outputPath">Destination file</param>
/// <param name="cropX">Cropping width</param>
/// <param name="cropY">Cropping height</param>
/// <param name="translateX">Optional x-position if cropping rectangle</param>
/// <param name="translateY">Optional y-position if cropping rectangle</param>
/// <param name="rotate">Optional rotation angle, counterclockwise</param>
public static void CropPage(string inputPath, string outputPath, int cropX, int cropY, int translateX = 0, int translateY = 0, int rotate = 0)
{
GhostscriptSettings settings = new GhostscriptSettings();
settings.Device = Settings.GhostscriptDevices.ps2write;
if (IntPtr.Size == 4)
API.GhostScript32.CallAPI(GetArgs(inputPath, outputPath, cropX, cropY, translateX, translateY, rotate));
else
API.GhostScript64.CallAPI(GetArgs(inputPath, outputPath, cropX, cropY, translateX, translateY, rotate));
}
/// <summary>
/// Returns an array of arguments to be sent to the Ghostscript API
/// </summary>
private static string[] GetArgs(string inputPath, string outputPath, int cropX, int cropY, int translateX = 0, int translateY = 0, int rotate = 0)
{
//System.Collections.ArrayList args = new System.Collections.ArrayList(ARGS);
System.Collections.ArrayList args = new System.Collections.ArrayList(); // test wihout standards...
args.Add("-q"); // First parameter is ignored
args.Add("-dBATCH");
args.Add("-dNOPAUSE");
args.Add(String.Format("-sOutputFile={0}", outputPath));
args.Add("-sDEVICE=ps2write");
args.Add("-dAutoRotatePages=/None");
args.Add(String.Format("-g{0}0x{1}0", cropX, cropY)); // is equal to -dDEVICEWIDTHPOINTS=cropX & -dDEVICEHEIGHTPOINTS=CropY & -dFIXEDMEDIA
// the following arg seems to be ignored...
args.Add("-c \"<</Install {" + String.Format("{0} {1} translate {2} rotate", translateX, translateY, rotate) + "}>> setpagedevice\"");
args.Add(String.Format("-f\u0022{0}\u0022", inputPath));
return (string[])args.ToArray(typeof(string));
}
With both approaches I can successfully cut an A6 page out of an A4 page, but neither the translation nor the rotation is done. The cutout is done at the lower left corner of the coordinate origin.
It seems to me that the "-c" command cannot be passed as an argument to the DLL function gsapi_init_with_args, but I'm not sure about that.
An example from Ghostscrip.Net suggests that the function gsapi_run_string could be used for this instead of init_with_args. In the viewer example the string is included with %%BeginPageSetup and %%EndPageSetup. However, I have not been able to build a working call of gsapi_init_with_args in combination with gsapi_run_string.
Any hint for one of the two wrappers or even another one would be highly appreciated.
Upvotes: 1
Views: 323