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>
9#include "../../Common/EPSSupportFile.cpp"
11static const char*
const kEncapsulateJobStart =
"\
13% .EndJob to handle the job encapsulation. It has to be defined as an operator\r\
17 serverdict /.jobsave get dup null eq\r\
25 serverdict /.jobsave null put\r\
27false 0 startjob pop\r\
29static const char*
const kEncapsulateJobEnd =
".endjob";
30static const char*
const kEPSPrefixTemplate =
"\
31<< /PageSize[%.4f %.4f] /ImagingBBox null >> setpagedevice\r\
34static const char*
const kArguments2[] =
42 "-dPDFSETTINGS=/prepress",
43 "-dCompatibilityLevel=1.4",
44 "-dProcessColorModel=/DeviceCMYK",
45 "-dEmbedAllFonts=true",
47 "-dConvertCMYKImagesToRGB=false",
48 "-dDownsampleColorImages=false",
49 "-dDownsampleGrayImages=false",
50 "-dDownsampleMonoImages=false",
51 "-dPreserveOverprintSettings=true",
52 "-dTransferFunctionInfo=/Preserve"
58static int gFontMessageCount = 0;
60static int GSDLLCALL gsdll_stdin(
void *,
char *,
int )
65static int GSDLLCALL gsdll_stdout(
void *caller_handle,
const char *messageText,
int len )
67 ACPL::String hh( messageText, len );
68 const char* strStart = ::strstr( hh,
"%%[" );
69 if( strStart != NULL )
71 const char* end = strStart;
72 while( *end && *end !=
' ' )
74 if( ::strncmp( end,
" not found, substituting ", 25 ) )
77 ACPL::String* psFontStr = (ACPL::String*)caller_handle;
79 if( gFontMessageCount == 4 )
81 (*psFontStr) +=
"Fonts missing";
84 else if( gFontMessageCount > 4 )
86 if( psFontStr->GetLength() == 0 )
87 (*psFontStr) =
"Fonts missing";
90 ::memcpy( s, strStart + 3, end - strStart - 3 );
91 s[ end - strStart - 3 ] = 0;
93 (*psFontStr) +=
" > ";
95 const char* end2 = end + 1;
98 const char* end3 = end2;
102 ::memcpy( s, end2, end3 - end2 );
103 s[ end3 - end2 ] = 0;
106 (*psFontStr) +=
"\n";
108 (*psFontStr) +=
"\r";
114typedef const char* CCharPtr;
116void PS2PDF(
const ACPL::FileSpec& ps,
const ACPL::FileSpec& pdf, ACPL::String& errorStr, ACPL::String& fontStr, PDF::Instance* instance )
119 (void)FilterNoDistill;
122 gFontMessageCount = 0;
127 ACPL::UString path = PDF::Instance::sDefault->ResourceDirectory().GetPOSIXPath() +
"\\gsdll64.dll";
128 HMODULE dll = ::LoadLibraryW( path.w_str() );
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";
136 void* dll = dlopen( path, RTLD_LAZY );
138 ThrowIf( dll == NULL );
140 ExceptionCode r = NoError;
142 bool hasBeenInited =
false;
143 bool hasBeenStarted =
false;
144 std::vector<ColorName> list;
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;
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" );
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" );
180 ThrowIf( GSNewInstance == NULL );
182 gs_main_instance* gsHandle = NULL;
191 PDF::FRectangle bounds;
192 GetEPSInfo( ps, bounds, start, end );
193 if( bounds.left < bounds.right && bounds.bottom < bounds.top )
195 float pageWidth = bounds.Width();
196 float pageHeight = -bounds.Height();
197 ::snprintf( epsPrefix,
sizeof(epsPrefix), kEPSPrefixTemplate, pageWidth, pageHeight, -bounds.left, -bounds.bottom );
204 gsapi_revision_t gs_info;
205 ThrowIfError( GSRevision( &gs_info,
sizeof(gs_info) ) );
206 if( gs_info.revision < 904 )
212 int numArgum =
sizeof(kArguments2)/
sizeof(
char*);
213 argv =
new CCharPtr[ numArgum + 3 ];
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 );
226 ThrowIfError( GSNewInstance( &gsHandle, &fontStr ) );
227 ThrowIfError( GSSetIO( gsHandle, gsdll_stdin, gsdll_stdout, gsdll_stdout ) );
228 ThrowIfError( GSInit( gsHandle, numArgum, (
char **)argv ) );
231 hasBeenInited =
true;
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 );
240 instance->Progress(
float( start ) / end );
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 )
253 gs_result = GSCont( gsHandle, epsPrefix, (
int)::strlen( epsPrefix ), 0, &exit_code );
254 if( gs_result != 0 && gs_result != -106 )
255 ThrowErr( exit_code );
257 hasBeenStarted =
true;
263 char PlateFileString[] =
"%%PlateFile:";
264 int searchIndex2 = 0;
265 char plateFileName[ 256 ];
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 );
274 std::vector<DCSInfo> DCS;
275 if( SearchKeyword( buffer, bcount, PlateFileString, searchIndex2, plateFileName )
276 && plateFileName[ 0 ]
277 && ReadDCSInfo( DCS, buffer, bcount ) )
279 int64_t totalSize = start;
280 int64_t totalDone = start;
281 if( DCS[ 0 ].offset != -1 )
283 for(
const auto& dcs : DCS )
284 totalSize += dcs.size;
286 instance->Progress(
float( 0 ) / totalSize );
288 for(
const auto& dcs : DCS )
290 file.SetMarker( dcs.offset, ACPL::eFromStart );
291 uint32_t toDo = dcs.size;
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 );
305 instance->Progress(
float( totalDone ) / totalSize );
307 gs_result = GSCont( gsHandle,
"showpage\n", 9, 0, &exit_code );
308 if( gs_result != 0 && gs_result != -106 )
309 ThrowErr( exit_code );
314 auto parentDir = ps.ParentDirectory();
315 for(
const auto& dcs : DCS )
318 spec.Make( parentDir, dcs.fileName );
319 ACPL::FileStream stream( spec, ACPL::eReadPermission );
320 totalSize += stream.GetLength();
322 instance->Progress(
float( 0 ) / totalSize );
323 for(
const auto& dcs : DCS )
326 spec.Make( parentDir, dcs.fileName );
327 ACPL::FileStream stream( spec, ACPL::eReadPermission );
330 end = stream.GetLength();
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 );
344 instance->Progress(
float( totalDone ) / totalSize );
346 gs_result = GSCont( gsHandle,
"showpage\n", 9, 0, &exit_code );
347 if( gs_result != 0 && gs_result != -106 )
348 ThrowErr( exit_code );
351 for(
const auto& dcs : DCS )
354 cn.firstPlateOfPage =
false;
355 ::strcpy( cn.name, dcs.colorName );
357 switch( dcs.plateType )
360 cn.space = PDF::NoSpace;
363 cn.space = PDF::RGBSpace;
368 cn.space = PDF::CMYKSpace;
370 case DCSNotDefinedJet :
373 for( uint32_t f = 0 ; f != nr ; ++f )
374 cn.colors[ f ] = dcs.colors[ f ];
375 list.push_back( cn );
380 bool pageFound =
false;
382 ReadDCSInfo( DCS, buffer, bcount );
383 bool skipBecauseFirst =
true;
387 if( skipBecauseFirst ==
false )
389 bigBound = end - start;
390 if( bigBound > kBufferSize )
391 bigBound = kBufferSize;
392 bcount = int32_t (bigBound );
393 file.ReadBlock( buffer, bcount );
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 );
404 while( start < end && stop ==
false );
407 int32_t jj, kk = -1, nr;
408 for(
const auto& dcs : DCS )
409 if( dcs.colorName[0] && kk < (int)list.size() )
412 switch( dcs.plateType )
415 list[kk].space = PDF::NoSpace;
419 list[kk].space = PDF::RGBSpace;
423 list[kk].space = PDF::CMYKSpace;
426 case DCSNotDefinedJet :
429 for (jj = 0; jj != nr; jj ++)
430 list[kk].colors[jj] = dcs.colors[jj];
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 );
454 hasBeenInited =
false;
455 ThrowIfError( GSExit( gsHandle ) );
456 GSDelInstance( gsHandle );
466 catch( ExceptionCode err )
471 GSEnd( gsHandle, 0, &exit_code ) ;
474 GSBegin( gsHandle, 0, &exit_code );
475 GSCont( gsHandle, kEncapsulateJobEnd, (
int)::strlen( kEncapsulateJobEnd ), 0, &exit_code );
476 GSEnd( gsHandle, 0, &exit_code );
490 int errind = -1 - err;
491 if( errind >= 0 && errind < (
int)(
sizeof(kPSErrorNames)/
sizeof(kPSErrorNames[0])) )
493 errorStr =
"PostScript error \"";
494 errorStr += kPSErrorNames[errind];
496 errorStr +=
"\" occured.\nThe PostScript job is canceled.";
498 errorStr +=
"\" occured.\rThe PostScript job is canceled.";
501 GSDelInstance( gsHandle );
508 ::FreeLibrary( dll );
514 if( r == NoError && !list.empty() )
515 AddPlateInfoToPDF( pdf, list );
519#if !defined(debugging) && !defined(_DEBUG) && !defined(ICISS)