Aurelon Open API 8.1.1
Loading...
Searching...
No Matches
ghostscript.cpp
1#include <ACPL/FileStream.h>
2#include "ghostscript.h"
3#include <Common/ghostscript_api.h>
4#include <PDFEngine/GInstance.h>
5#include <ACPL/Utilities.h>
6#if ACPL_MAC
7# include <dlfcn.h>
8#endif
9#include "../../Common/EPSSupportFile.cpp"
10#define APPNAME "AOI"
11static const char* const kEncapsulateJobStart = "\
12.setpdfwrite\r\
13% .EndJob to handle the job encapsulation. It has to be defined as an operator\r\
14/.endjob\r\
15{\r\
16 clear\r\
17 serverdict /.jobsave get dup null eq\r\
18 {\r\
19 pop\r\
20 }\r\
21 {\r\
22 restore\r\
23 }\r\
24 ifelse\r\
25 serverdict /.jobsave null put\r\
26} def\r\
27false 0 startjob pop\r\
28";
29static const char* const kEncapsulateJobEnd = ".endjob";
30static const char* const kEPSPrefixTemplate = "\
31<< /PageSize[%.4f %.4f] /ImagingBBox null >> setpagedevice\r\
32%.4f %.4f translate\r\
33";
34static const char* const kArguments2[] =
35{
36 APPNAME,
37 "-sDEVICE=pdfwrite",
38 "-r600x600",
39 "-dNOPAUSE",
40 "-dNOPLATFONTS",
41 "-dSHORTERRORS",
42 "-dPDFSETTINGS=/prepress",
43 "-dCompatibilityLevel=1.4",
44 "-dProcessColorModel=/DeviceCMYK",
45 "-dEmbedAllFonts=true",
46 "-dSubsetFonts=true",
47 "-dConvertCMYKImagesToRGB=false",
48 "-dDownsampleColorImages=false",
49 "-dDownsampleGrayImages=false",
50 "-dDownsampleMonoImages=false",
51 "-dPreserveOverprintSettings=true",
52 "-dTransferFunctionInfo=/Preserve"
53// "-dCompressPages=false",
54};
55
56using namespace aur;
57
58static int gFontMessageCount = 0;
59
60static int GSDLLCALL gsdll_stdin( void *, char *, int )
61{
62 return 0;
63}
64
65static int GSDLLCALL gsdll_stdout(void *caller_handle, const char *messageText, int len )
66{
67 ACPL::String hh( messageText, len );
68 const char* strStart = ::strstr( hh, "%%[" );
69 if( strStart != NULL )
70 {
71 const char* end = strStart;
72 while( *end && *end != ' ' )
73 end++;
74 if( ::strncmp( end, " not found, substituting ", 25 ) )
75 return len;
76
77 ACPL::String* psFontStr = (ACPL::String*)caller_handle;
78 ++gFontMessageCount;
79 if( gFontMessageCount == 4 )
80 {
81 (*psFontStr) += "Fonts missing";
82 return len;
83 }
84 else if( gFontMessageCount > 4 )
85 return len;
86 if( psFontStr->GetLength() == 0 )
87 (*psFontStr) = "Fonts missing";
88
89 char s[256];
90 ::memcpy( s, strStart + 3, end - strStart - 3 );
91 s[ end - strStart - 3 ] = 0;
92 (*psFontStr) += s;
93 (*psFontStr) += " > ";
94
95 const char* end2 = end + 1;
96 while( *end2 != ']' )
97 ++end2;
98 const char* end3 = end2;
99 while( *end2 != ' ' )
100 --end2;
101 ++end2;
102 ::memcpy( s, end2, end3 - end2 );
103 s[ end3 - end2 ] = 0;
104 (*psFontStr) += s;
105#if ACPL_WIN
106 (*psFontStr) += "\n";
107#else
108 (*psFontStr) += "\r";
109#endif
110 }
111 return len;
112}
113
114typedef const char* CCharPtr;
115
116void PS2PDF( const ACPL::FileSpec& ps, const ACPL::FileSpec& pdf, ACPL::String& errorStr, ACPL::String& fontStr, PDF::Instance* instance )
117{
118#if ACPL_MAC
119 (void)FilterNoDistill; // Silence warning by referencing the routine pointer
120#endif
121
122 gFontMessageCount = 0;
123 //
124 // Locate and load GhostScript
125 //
126#if ACPL_WIN
127 ACPL::UString path = PDF::Instance::sDefault->ResourceDirectory().GetPOSIXPath() + "\\gsdll64.dll";
128 HMODULE dll = ::LoadLibraryW( path.w_str() );
129#else
130 CFURLRef refFmwkURL = ::CFBundleCopyPrivateFrameworksURL( ::CFBundleGetMainBundle() );
131 char utf8path[POSIX_PATH_LEN];
132 ::CFURLGetFileSystemRepresentation( refFmwkURL, true, (uint8_t*)utf8path, POSIX_PATH_LEN );
133 ::CFRelease( refFmwkURL );
134 ACPL::String path = ACPL::String( utf8path ) + "/libgs.dylib";
135
136 void* dll = dlopen( path, RTLD_LAZY );
137#endif
138 ThrowIf( dll == NULL );
139
140 ExceptionCode r = NoError;
141 char* buffer = NULL;
142 bool hasBeenInited = false;
143 bool hasBeenStarted = false;
144 std::vector<ColorName> list;
145 try
146 {
147 //
148 // Load DLL and procs
149 //
150 PFN_gsapi_revision GSRevision;
151 PFN_gsapi_new_instance GSNewInstance;
152 PFN_gsapi_delete_instance GSDelInstance;
153 PFN_gsapi_set_stdio GSSetIO;
154 PFN_gsapi_init_with_args GSInit;
155 PFN_gsapi_run_string_begin GSBegin;
156 PFN_gsapi_run_string_continue GSCont;
157 PFN_gsapi_run_string_end GSEnd;
158 PFN_gsapi_exit GSExit;
159#if ACPL_MAC
160 GSRevision = (PFN_gsapi_revision)dlsym( dll, "gsapi_revision" );
161 GSNewInstance = (PFN_gsapi_new_instance)dlsym( dll, "gsapi_new_instance" );
162 GSDelInstance = (PFN_gsapi_delete_instance)dlsym( dll, "gsapi_delete_instance" );
163 GSSetIO = (PFN_gsapi_set_stdio)dlsym( dll, "gsapi_set_stdio" );
164 GSInit = (PFN_gsapi_init_with_args)dlsym( dll, "gsapi_init_with_args" );
165 GSBegin = (PFN_gsapi_run_string_begin)dlsym( dll, "gsapi_run_string_begin" );
166 GSCont = (PFN_gsapi_run_string_continue)dlsym( dll, "gsapi_run_string_continue" );
167 GSEnd = (PFN_gsapi_run_string_end)dlsym( dll, "gsapi_run_string_end" );
168 GSExit = (PFN_gsapi_exit)dlsym( dll, "gsapi_exit" );
169#else
170 GSRevision = (PFN_gsapi_revision)::GetProcAddress( dll, "gsapi_revision" );
171 GSNewInstance = (PFN_gsapi_new_instance)::GetProcAddress( dll, "gsapi_new_instance" );
172 GSDelInstance = (PFN_gsapi_delete_instance)::GetProcAddress( dll, "gsapi_delete_instance" );
173 GSSetIO = (PFN_gsapi_set_stdio)::GetProcAddress( dll, "gsapi_set_stdio" );
174 GSInit = (PFN_gsapi_init_with_args)::GetProcAddress( dll, "gsapi_init_with_args" );
175 GSBegin = (PFN_gsapi_run_string_begin)::GetProcAddress( dll, "gsapi_run_string_begin" );
176 GSCont = (PFN_gsapi_run_string_continue)::GetProcAddress( dll, "gsapi_run_string_continue" );
177 GSEnd = (PFN_gsapi_run_string_end)::GetProcAddress( dll, "gsapi_run_string_end" );
178 GSExit = (PFN_gsapi_exit)::GetProcAddress( dll, "gsapi_exit" );
179#endif
180 ThrowIf( GSNewInstance == NULL );
181
182 gs_main_instance* gsHandle = NULL;
183 int exit_code;
184 try
185 {
186 //
187 // Load EPS info
188 //
189 char epsPrefix[256];
190 int64_t start, end;
191 PDF::FRectangle bounds;
192 GetEPSInfo( ps, bounds, start, end );
193 if( bounds.left < bounds.right && bounds.bottom < bounds.top )
194 {
195 float pageWidth = bounds.Width();
196 float pageHeight = -bounds.Height();
197 ::snprintf( epsPrefix, sizeof(epsPrefix), kEPSPrefixTemplate, pageWidth, pageHeight, -bounds.left, -bounds.bottom );
198 }
199 else
200 *epsPrefix = 0;
201 //
202 // Check version; v9.04 minimum
203 //
204 gsapi_revision_t gs_info;
205 ThrowIfError( GSRevision( &gs_info, sizeof(gs_info) ) );
206 if( gs_info.revision < 904 )
207 ThrowErr( 904 );
208 //
209 // Init GhostScript with settings
210 //
211 const char** argv;
212 int numArgum = sizeof(kArguments2)/sizeof(char*);
213 argv = new CCharPtr[ numArgum + 3 ];
214 // fill argv arguments part
215 int i;
216 for( i = 0; i != numArgum; ++i )
217 argv[i] = kArguments2[i];
218 ACPL::String oarg = "-sOutputFile=";
219 char opath[POSIX_PATH_LEN];
220 pdf.GetPOSIXPath( opath );
221 oarg += opath;
222
223 argv[i++] = oarg;
224 numArgum += 1;
225
226 ThrowIfError( GSNewInstance( &gsHandle, &fontStr ) );
227 ThrowIfError( GSSetIO( gsHandle, gsdll_stdin, gsdll_stdout, gsdll_stdout ) );
228 ThrowIfError( GSInit( gsHandle, numArgum, (char **)argv ) );
229 delete[] argv;
230
231 hasBeenInited = true;
232 //
233 // Open file and start interpreting
234 //
235 static const int32_t kBufferSize = 51200;
236 buffer = new char[ kBufferSize ];
237 ACPL::FileStream file( ps, ACPL::eReadPermission );
238 file.SetMarker( start, ACPL::eFromStart );
239 // Set progression bar
240 instance->Progress( float( start ) / end );
241 //
242 // Load file and stream into GhostScript
243 //
244 int gs_result;
245 gs_result = GSBegin( gsHandle, 0, &exit_code );
246 if( gs_result != 0 && gs_result != -106 )
247 ThrowErr( exit_code );
248 gs_result = GSCont( gsHandle, kEncapsulateJobStart, (int)::strlen(kEncapsulateJobStart), 0, &exit_code );
249 if( gs_result != 0 && gs_result != -106 )
250 ThrowErr( exit_code );
251 if( *epsPrefix != 0 )
252 {
253 gs_result = GSCont( gsHandle, epsPrefix, (int)::strlen( epsPrefix ), 0, &exit_code );
254 if( gs_result != 0 && gs_result != -106 )
255 ThrowErr( exit_code );
256 }
257 hasBeenStarted = true;
258
259 ColorName regel;
260 int searchIndex = 0;
261 int curPage = -1;
262 int pageNum = 0;
263 char PlateFileString[] = "%%PlateFile:";
264 int searchIndex2 = 0;
265 char plateFileName[ 256 ];
266
267 int64_t bigBound = end - start;
268 if( bigBound > kBufferSize )
269 bigBound = kBufferSize;
270 int32_t bcount = int32_t (bigBound );
271 file.ReadBlock( buffer, bcount );
272 start += bcount;
273
274 std::vector<DCSInfo> DCS;
275 if( SearchKeyword( buffer, bcount, PlateFileString, searchIndex2, plateFileName )
276 && plateFileName[ 0 ]
277 && ReadDCSInfo( DCS, buffer, bcount ) )
278 {
279 int64_t totalSize = start;
280 int64_t totalDone = start;
281 if( DCS[ 0 ].offset != -1 )
282 {
283 for( const auto& dcs : DCS )
284 totalSize += dcs.size;
285
286 instance->Progress( float( 0 ) / totalSize );
287
288 for( const auto& dcs : DCS )
289 {
290 file.SetMarker( dcs.offset, ACPL::eFromStart );
291 uint32_t toDo = dcs.size;
292 while( toDo )
293 {
294 bigBound = toDo;
295 if( bigBound > kBufferSize )
296 bigBound = kBufferSize;
297 bcount = int32_t (bigBound );
298 file.ReadBlock( buffer, bcount );
299 gs_result = GSCont( gsHandle, buffer, bcount, 0, &exit_code );
300 if( gs_result != 0 && gs_result != -106 )
301 ThrowErr( exit_code );
302 toDo -= bcount;
303 totalDone += bcount;
304
305 instance->Progress( float( totalDone ) / totalSize );
306 }
307 gs_result = GSCont( gsHandle, "showpage\n", 9, 0, &exit_code );
308 if( gs_result != 0 && gs_result != -106 )
309 ThrowErr( exit_code );
310 }
311 }
312 else
313 {
314 auto parentDir = ps.ParentDirectory();
315 for( const auto& dcs : DCS )
316 {
317 ACPL::FileSpec spec;
318 spec.Make( parentDir, dcs.fileName );
319 ACPL::FileStream stream( spec, ACPL::eReadPermission );
320 totalSize += stream.GetLength();
321 }
322 instance->Progress( float( 0 ) / totalSize );
323 for( const auto& dcs : DCS )
324 {
325 ACPL::FileSpec spec;
326 spec.Make( parentDir, dcs.fileName );
327 ACPL::FileStream stream( spec, ACPL::eReadPermission );
328
329 start = 0;
330 end = stream.GetLength();
331 int64_t toDo = end;
332 while( toDo )
333 {
334 bigBound = toDo;
335 if( bigBound > kBufferSize )
336 bigBound = kBufferSize;
337 bcount = int32_t (bigBound );
338 stream.ReadBlock( buffer, bcount );
339 gs_result = GSCont( gsHandle, buffer, bcount, 0, &exit_code );
340 if( gs_result != 0 && gs_result != -106 )
341 ThrowErr( exit_code );
342 toDo -= bcount;
343 totalDone += bcount;
344 instance->Progress( float( totalDone ) / totalSize );
345 }
346 gs_result = GSCont( gsHandle, "showpage\n", 9, 0, &exit_code );
347 if( gs_result != 0 && gs_result != -106 )
348 ThrowErr( exit_code );
349 }
350 }
351 for( const auto& dcs : DCS )
352 {
353 ColorName cn;
354 cn.firstPlateOfPage = false;
355 ::strcpy( cn.name, dcs.colorName );
356 uint32_t nr = 0;
357 switch( dcs.plateType )
358 {
359 case DCSProcess :
360 cn.space = PDF::NoSpace;
361 break;
362 case DCSRGB :
363 cn.space = PDF::RGBSpace;
364 nr = 3;
365 break;
366 case DCSCMYK :
367 nr = 4;
368 cn.space = PDF::CMYKSpace;
369 break;
370 case DCSNotDefinedJet :
371 ;
372 }
373 for( uint32_t f = 0 ; f != nr ; ++f )
374 cn.colors[ f ] = dcs.colors[ f ];
375 list.push_back( cn );
376 }
377 }
378 else
379 {
380 bool pageFound = false;
381
382 ReadDCSInfo( DCS, buffer, bcount );
383 bool skipBecauseFirst = true;
384 bool stop = false;
385 do
386 {
387 if( skipBecauseFirst == false )
388 {
389 bigBound = end - start;
390 if( bigBound > kBufferSize )
391 bigBound = kBufferSize;
392 bcount = int32_t (bigBound );
393 file.ReadBlock( buffer, bcount );
394 start += bcount;
395 }
396 else
397 skipBecauseFirst = false;
398 SearchPlateColor( buffer, bcount, list, regel, searchIndex, pageFound, curPage, pageNum, end == start );
399 stop = instance->Progress( float( start ) / end );
400 gs_result = GSCont( gsHandle, buffer, bcount, 0, &exit_code );
401 if( gs_result != 0 && gs_result != -106 )
402 ThrowErr( exit_code );
403 }
404 while( start < end && stop == false );
405 if( !list.empty() )
406 {
407 int32_t jj, kk = -1, nr;
408 for( const auto& dcs : DCS )
409 if( dcs.colorName[0] && kk < (int)list.size() )
410 {
411 kk++;
412 switch( dcs.plateType )
413 {
414 case DCSProcess :
415 list[kk].space = PDF::NoSpace;
416 nr = 0;
417 break;
418 case DCSRGB :
419 list[kk].space = PDF::RGBSpace;
420 nr = 3;
421 break;
422 case DCSCMYK :
423 list[kk].space = PDF::CMYKSpace;
424 nr = 4;
425 break;
426 case DCSNotDefinedJet :
427 ;
428 }
429 for (jj = 0; jj != nr; jj ++)
430 list[kk].colors[jj] = dcs.colors[jj];
431 }
432 }
433 }
434
435 //
436 // Stop interpreter
437 //
438 hasBeenStarted = false;
439 gs_result = GSEnd( gsHandle, 0, &exit_code );
440 if( gs_result != 0 && gs_result != -106 )
441 ThrowErr( exit_code );
442 gs_result = GSBegin( gsHandle, 0, &exit_code );
443 if( gs_result != 0 && gs_result != -106 )
444 ThrowErr( exit_code );
445 gs_result = GSCont( gsHandle, kEncapsulateJobEnd, (int)::strlen( kEncapsulateJobEnd ), 0, &exit_code );
446 if( gs_result != 0 && gs_result != -106 )
447 ThrowErr( exit_code );
448 gs_result = GSEnd( gsHandle, 0, &exit_code );
449 if( gs_result != 0 && gs_result != -106 )
450 ThrowErr( exit_code );
451 //
452 // Uninitialize GhostScript
453 //
454 hasBeenInited = false;
455 ThrowIfError( GSExit( gsHandle ) );
456 GSDelInstance( gsHandle );
457 //
458 // Clean up
459 //
460/* if( bar->UserCanceled() )
461 {
462 pdf.Delete();
463 r = ErrUserCanceled;
464 }*/
465 }
466 catch( ExceptionCode err )
467 {
468 r = err;
469 if( hasBeenStarted )
470 {
471 GSEnd( gsHandle, 0, &exit_code ) ;
472 if( r != -101 )
473 {
474 GSBegin( gsHandle, 0, &exit_code );
475 GSCont( gsHandle, kEncapsulateJobEnd, (int)::strlen( kEncapsulateJobEnd ), 0, &exit_code );
476 GSEnd( gsHandle, 0, &exit_code );
477 }
478 }
479 if( hasBeenInited )
480 GSExit( gsHandle );
481 if( hasBeenStarted )
482 pdf.Delete();
483 else
484 {
485 // Reset r to 0 when the error occured during GSEnd.
486 // This patch allows Photoshop 7 EPS files to work
487 // See bug# 944
488 r = 0;
489 }
490 int errind = -1 - err;
491 if( errind >= 0 && errind < (int)(sizeof(kPSErrorNames)/sizeof(kPSErrorNames[0])) )
492 {
493 errorStr = "PostScript error \"";
494 errorStr += kPSErrorNames[errind];
495#if ACPL_WIN
496 errorStr += "\" occured.\nThe PostScript job is canceled.";
497#else
498 errorStr += "\" occured.\rThe PostScript job is canceled.";
499#endif
500 }
501 GSDelInstance( gsHandle );
502 }
503 }
504 catch(...)
505 {
506 }
507#if ACPL_WIN
508 ::FreeLibrary( dll );
509#else
510 dlclose( dll );
511#endif
512 delete[] buffer;
513 // add new xref for platecolors:
514 if( r == NoError && !list.empty() )
515 AddPlateInfoToPDF( pdf, list );
516 if( r )
517 throw r;
518 // damage pdf file for Aurelon use only
519#if !defined(debugging) && !defined(_DEBUG) && !defined(ICISS)
520// if( ALS::License::SerialNumber() == 0 )
521// DamagePDF( pdf );
522#endif
523}