Bug #687915 -dEPSCrop doesn't work if %%BoundingBox (atend)
"Russell Lang" <[email protected]> Mon, 04 Apr 2005 23:13:55 +1000
| Newsgroups | gmane.comp.printing.ghostscript.patches |
|---|---|
| Message-ID | <4251CA33.16946.CF79A64C@localhost> |
Fixes bug #687915 -dEPSCrop doesn't work if %%BoundingBox (atend). When processing EPSF files, allow the %%BoundingBox to be found in the trailer as well as the header. DETAILS: If "%%BoundingBox: (atend)" is found, or "%%BoundingBox:" is not found in the first 1kbytes of an EPS file, assume that it is in the trailer. The entire EPSF file is then copied to a temporary file while scanning for DSC comments. After copying is complete, the bounding box is extracted from the DSC structure and used by EPSCrop or EPSFitPage. Two new operators are needed for parsing DSC comments. The first new operator ".parse_dsc" allows the PostScript file to be scanned for DSC comments in large chunks. The results of scanning are put in the DSC structure but not the dictionary. The existing ".parse_dsc_comments" required that a file be read a line at a time which made copying slower. The second new operator ".update_dsc" is used to copy some details from the DSC structure to the dictionary for use by PostScript code. Only BoundingBox and HiResBoundingBox are used at the moment, but others are also copied for completeness. If the bounding box is found in the trailer, it is used and the exisiting processing of header bounding box comments is disabled. Russell Lang [email protected] Ghostgum Software Pty Ltd http://www.ghostgum.com.au/ diff -u l:\cvs\gs\doc/Use.htm doc/Use.htm --- l:\cvs\gs\doc/Use.htm Sat Mar 26 22:12:03 2005 +++ doc/Use.htm Mon Apr 04 12:53:50 2005 @@ -615,9 +616,9 @@ rectangle in which it will draw, must not use PostScript commands which will interfere with the document importing the EPS, and can have either zero pages or one page. -Ghostscript has support for handling EPS files, but requires -that the <b><tt>%%BoundingBox</tt></b> be in the header, -not the trailer. +Ghostscript has support for handling EPS files. If the +<b><tt>%%BoundingBox</tt></b> is not in the header, Ghostscript +will buffer the entire file to look for it in the trailer. To customize EPS handling, see <a href="#EPS_parameters">EPS parameters</a>. <p> diff -u l:\cvs\gs\src/zdscpars.c src/zdscpars.c --- l:\cvs\gs\src/zdscpars.c Thu Nov 18 07:42:02 2004 +++ src/zdscpars.c Mon Apr 04 12:50:57 2005 @@ -206,6 +206,27 @@ return param_write_int_array(plist, keyname, &va); } +/* Return a HiResBoundingBox value. */ +private int +dsc_put_hires_bounding_box(gs_param_list *plist, const char *keyname, + const CDSCFBBOX *pbbox) +{ + /* pbbox is NULL iff the bounding box values was "(atend)". */ + float values[4]; + gs_param_float_array va; + + if (!pbbox) + return 0; + values[0] = pbbox->fllx; + values[1] = pbbox->flly; + values[2] = pbbox->furx; + values[3] = pbbox->fury; + va.data = values; + va.size = 4; + va.persistent = false; + return param_write_float_array(plist, keyname, &va); +} + /* ------ Return values for individual comment types ------ */ /* @@ -249,6 +270,13 @@ } private int +dsc_hires_bounding_box(gs_param_list *plist, const CDSC *pData) +{ + return dsc_put_hires_bounding_box(plist, "HiResBoundingBox", + pData->hires_bbox); +} + +private int dsc_page(gs_param_list *plist, const CDSC *pData) { int page_num = pData->page_count; @@ -362,6 +390,7 @@ { CDSC_TITLE, "Title", dsc_title }, { CDSC_FOR, "For", dsc_for }, { CDSC_BOUNDINGBOX, "BoundingBox", dsc_bounding_box }, + { CDSC_HIRESBOUNDINGBOX, "HiResBoundingBox", dsc_hires_bounding_box }, { CDSC_ORIENTATION, "Orientation", dsc_orientation }, { CDSC_BEGINDEFAULTS, "BeginDefaults", NULL }, { CDSC_ENDDEFAULTS, "EndDefaults", NULL }, @@ -475,10 +504,87 @@ return name_enter_string(imemory, pCmdList->comment_name, opString); } +/* ----- Parser interface used for finding EPS Bounding Box in trailer ----- */ + +/* Parse PostScript for DSC comments */ +/* This phase scans for DSC comments and stores the results in dsc_data */ +/* <dict> <string> .parse_dsc */ +private int +zparse_dsc(i_ctx_t *i_ctx_p) +{ + os_ptr const opString = osp; + os_ptr const opDict = opString - 1; + int code; + CDSC * dsc_data = NULL; + ref * pvalue; + + check_type(*opString, t_string); + + code = dict_find_string(opDict, dsc_dict_name, &pvalue); + if (code < 0) + return code; + dsc_data = r_ptr(pvalue, dsc_data_t)->dsc_data_ptr; + dsc_scan_data(dsc_data, (const char *)(opString->value.bytes), + r_size(opString)); + + pop(2); + return code; +} + + +/* Copy DSC data from DSC structure to dictionary */ +/* This phase copies some of the results from dsc_data to the dictionary */ +/* <dict> .update_dsc */ +private int +zupdate_dsc(i_ctx_t *i_ctx_p) +{ + os_ptr const opDict = osp; + CDSC * dsc_data = NULL; + dict_param_list list; + ref * pvalue; + int code; + + check_dict_write(*opDict); + code = dict_find_string(opDict, dsc_dict_name, &pvalue); + dsc_data = r_ptr(pvalue, dsc_data_t)->dsc_data_ptr; + if (code < 0) + return code; + + code = dict_param_list_write(&list, opDict, NULL, iimemory); + if (code < 0) + return code; + + if ((code == 0) && dsc_data->dsc) + code = dsc_adobe_header((gs_param_list *)&list, dsc_data); + if ((code == 0) && dsc_data->dsc_creator) + code = dsc_creator((gs_param_list *)&list, dsc_data); + if ((code == 0) && dsc_data->dsc_date) + code = dsc_creation_date((gs_param_list *)&list, dsc_data); + if ((code == 0) && dsc_data->dsc_title) + code = dsc_title((gs_param_list *)&list, dsc_data); + if ((code == 0) && dsc_data->dsc_for) + code = dsc_for((gs_param_list *)&list, dsc_data); + if ((code == 0) && dsc_data->bbox) + code = dsc_bounding_box((gs_param_list *)&list, dsc_data); + if ((code == 0) && dsc_data->hires_bbox) + code = dsc_hires_bounding_box((gs_param_list *)&list, dsc_data); + if ((code == 0) && (dsc_data->page_orientation != CDSC_ORIENT_UNKNOWN)) + code = dsc_orientation((gs_param_list *)&list, dsc_data); + if ((code == 0) && dsc_data->dsc) + code = dsc_pages((gs_param_list *)&list, dsc_data); + + iparam_list_release(&list); + pop(1); + return code; +} + + /* ------ Initialization procedure ------ */ const op_def zdscpars_op_defs[] = { {"1.initialize_dsc_parser", zinitialize_dsc_parser}, {"2.parse_dsc_comments", zparse_dsc_comments}, + {"2.parse_dsc", zparse_dsc}, + {"1.update_dsc", zupdate_dsc}, op_def_end(0) }; diff -u l:\cvs\gs\lib/gs_epsf.ps lib/gs_epsf.ps --- l:\cvs\gs\lib/gs_epsf.ps Sat Apr 12 22:02:39 2003 +++ lib/gs_epsf.ps Mon Apr 04 12:50:12 2005 @@ -36,6 +36,12 @@ % Parse 4 numbers for a bounding box /EPSBoundingBoxParse { % (llx lly urx ury) -- llx lly urx ury true OR false + % OR [llx lly urx ury] -- llx lly urx ury true OR false + dup type /arraytype eq { + % We got the bounding box after scanning entire file + aload pop true + } { + % We got the bounding box while scanning header comments mark exch token {exch token {exch token {exch token {exch pop} if} if} if} if counttomark @@ -45,6 +51,7 @@ } { cleartomark false } ifelse + } ifelse } bind def % Rescale and translate to fit the BoundingBox on the page @@ -76,7 +83,8 @@ } bind def -/EPSBoundingBoxProcess { % (llx lly urx ury) state -- +/EPSBoundingBoxProcess { % (llx lly urx ury) state -- + % OR [llx lly urx ury] state -- //systemdict /EPSBoundingBoxState get 1 index lt { exch EPSBoundingBoxParse { @@ -111,7 +119,7 @@ } ifelse } bind def -/ProcessEPSComment { % file comment -- file comment +/ProcessEPSComment { % comment -- comment //systemdict /EPSBoundingBoxState get 3 lt { dup (%%EndComments) anchorsearch { @@ -150,13 +158,98 @@ /.runNoEPS /run load def +% When the %%BoundingBox is in the trailer, we need to buffer +% the entire file while scanning for DSC comments. +/.runEPSbuffered { % file1 -- file2 + % read file1, scan for %%BoundingBox, and buffer to a temporary file2 + EPSDEBUG {(runEPS: Did not find %%BoundingBox in header, buffering file\n) + print flush} if + currentglobal false setglobal + userdict /epsf_dsc_dict null put + true setglobal + /epsf_dsc_dict 50 dict store epsf_dsc_dict .initialize_dsc_parser + setglobal + % Copy EPSF from stdin to temporary file then run it. + null (w+) //systemdict /.tempfile get exec exch 3 1 roll + epsf_dsc_dict 64000 string + % stack: tempname stdin tempfile dsc_dict string + { + 3 index 1 index readstring + 3 index 2 index .parse_dsc + exch 4 index exch writestring + not { exit } if + } + loop + pop pop exch closefile + currentglobal true setglobal epsf_dsc_dict .update_dsc setglobal + % stack: tempname tempfile + dup 0 setfileposition + epsf_dsc_dict /HiResBoundingBox known + { + EPSDEBUG { (gs_epsf.ps: using %%HiResBoundingBox\n) print flush } if + epsf_dsc_dict /HiResBoundingBox get + 3 EPSBoundingBoxProcess + } + { + epsf_dsc_dict /BoundingBox known + { + EPSDEBUG { (gs_epsf.ps: using %%BoundingBox\n) print flush } if + epsf_dsc_dict /BoundingBox get + 3 EPSBoundingBoxProcess + } + if + } + ifelse + dup .runNoEPS + closefile deletefile +} def + /.runEPS { % file OR string -- + dup type /filetype ne { (r) file } if /runEPS_save save def /runEPS_dict_count countdictstack def /runEPS_op_count count 2 sub def /runEPS_page_count currentpagedevice /PageCount get def 0 EPSBoundingBoxSetState - .runNoEPS + % Check if %%BoundingBox is in header + dup 1024 string + { .peekstring } stopped { + % probably rangecheck because buffer too large for .peekstring + pop pop % file string + .runNoEPS + } { + % .peekstring succeeded in reading something + { + % .peekstring returned full string + (%%BoundingBox:) search { + % bbox appears in first 1024 characters + pop pop % post-string + (atend) search { + EPSDEBUG + { (gs_epsf.ps: %%BoundingBox is (atend)\n) print flush } if + % bbox is in the trailer so buffer entire file first. + pop pop pop % post-string string pre-string + .runEPSbuffered + } + { + % Assume that bbox is in header + pop + .runNoEPS + } ifelse + } + { + % bbox not in first 1024 characters + % Assume bbox is in the trailer so buffer entire file first. + pop + .runEPSbuffered + } ifelse + } { + % .peekstring reach EOF before reading 1024 characters + % Assume that file is short and bbox is in header. + pop + .runNoEPS + } ifelse + } ifelse currentpagedevice /PageCount get runEPS_page_count sub 0 eq { /showpage load exec } if count runEPS_op_count sub {pop} repeat _______________________________________________ gs-code-review mailing list [email protected] http://www.ghostscript.com/mailman/listinfo/gs-code-review