Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * psio2.c 00018 * 00019 * |=============================================================| 00020 * | Important note | 00021 * |=============================================================| 00022 * | Some of these functions require libtiff, libjpeg and libz. | 00023 * | If you do not have these libraries, you must set | 00024 * | #define USE_PSIO 0 | 00025 * | in environ.h. This will link psio2stub.c | 00026 * |=============================================================| 00027 * 00028 * These are lower-level functions that implement a PostScript 00029 * "device driver" for wrapping images in PostScript. The images 00030 * can be rendered by a PostScript interpreter for viewing, 00031 * using evince or gv. They can also be rasterized for printing, 00032 * using gs or an embedded interpreter in a PostScript printer. 00033 * And they can be converted to a pdf using gs (ps2pdf). 00034 * 00035 * For uncompressed images 00036 * l_int32 pixWritePSEmbed() 00037 * l_int32 pixWriteStreamPS() 00038 * char *pixWriteStringPS() 00039 * char *generateUncompressedPS() 00040 * void getScaledParametersPS() 00041 * l_int32 convertByteToHexAscii() 00042 * 00043 * For jpeg compressed images (use dct compression) 00044 * l_int32 convertJpegToPSEmbed() 00045 * l_int32 convertJpegToPS() 00046 * l_int32 convertJpegToPSString() 00047 * char *generateJpegPS() 00048 * L_COMPRESSED_DATA *pixGenerateJpegData() 00049 * L_COMPRESSED_DATA *l_generateJpegData() 00050 * void compressed_dataDestroy() 00051 * 00052 * For g4 fax compressed images (use ccitt g4 compression) 00053 * l_int32 convertG4ToPSEmbed() 00054 * l_int32 convertG4ToPS() 00055 * l_int32 convertG4ToPSString() 00056 * char *generateG4PS() 00057 * L_COMPRESSED_DATA *pixGenerateG4Data() 00058 * L_COMPRESSED_DATA *l_generateG4Data() 00059 * 00060 * For multipage tiff images 00061 * l_int32 convertTiffMultipageToPS() 00062 * 00063 * For flate (gzip) compressed images (e.g., png) 00064 * l_int32 convertFlateToPSEmbed() 00065 * l_int32 convertFlateToPS() 00066 * l_int32 convertFlateToPSString() 00067 * char *generateFlatePS() 00068 * L_COMPRESSED_DATA *l_generateFlateData() 00069 * L_COMPRESSED_DATA *pixGenerateFlateData() 00070 * 00071 * Write to memory 00072 * l_int32 pixWriteMemPS() 00073 * 00074 * Converting resolution 00075 * l_int32 getResLetterPage() 00076 * l_int32 getResA4Page() 00077 * 00078 * Utility for encoding and decoding data with ascii85 00079 * char *encodeAscii85() 00080 * l_int32 *convertChunkToAscii85() 00081 * l_uint8 *decodeAscii85() 00082 * 00083 * Setting flag for writing bounding box hint 00084 * void l_psWriteBoundingBox() 00085 * 00086 * See psio1.c for higher-level functions and their usage. 00087 */ 00088 00089 #include <string.h> 00090 #include "allheaders.h" 00091 00092 /* --------------------------------------------*/ 00093 #if USE_PSIO /* defined in environ.h */ 00094 /* --------------------------------------------*/ 00095 00096 /* Set default for writing bounding box hint */ 00097 static l_int32 var_PS_WRITE_BOUNDING_BOX = 1; 00098 00099 /* MS VC++ can't handle array initialization with static consts ! */ 00100 #define L_BUF_SIZE 512 00101 00102 static const l_int32 DEFAULT_INPUT_RES = 300; /* typical scan res, ppi */ 00103 static const l_int32 MIN_RES = 5; 00104 static const l_int32 MAX_RES = 3000; 00105 static const l_int32 MAX_85_LINE_COUNT = 64; /* max line length ascii85 */ 00106 00107 /* For computing resolution that fills page to desired amount */ 00108 static const l_int32 LETTER_WIDTH = 612; /* points */ 00109 static const l_int32 LETTER_HEIGHT = 792; /* points */ 00110 static const l_int32 A4_WIDTH = 595; /* points */ 00111 static const l_int32 A4_HEIGHT = 842; /* points */ 00112 static const l_float32 DEFAULT_FILL_FRACTION = 0.95; 00113 00114 static const l_uint32 power85[5] = {1, 00115 85, 00116 85 * 85, 00117 85 * 85 * 85, 00118 85 * 85 * 85 * 85}; 00119 00120 static l_int32 convertChunkToAscii85(l_uint8 *inarray, l_int32 insize, 00121 l_int32 *pindex, char *outbuf, 00122 l_int32 *pnbout); 00123 00124 #ifndef NO_CONSOLE_IO 00125 #define DEBUG_JPEG 0 00126 #define DEBUG_G4 0 00127 #define DEBUG_FLATE 0 00128 #endif /* ~NO_CONSOLE_IO */ 00129 00130 /* Note that the bounding box hint at the top of the generated PostScript 00131 * file is required for the "*Embed" functions. These generate a 00132 * PostScript file for an individual image that can be translated and 00133 * scaled by an application that embeds the image in its output 00134 * (e.g., in the PS output from a TeX file). 00135 * However, bounding box hints should not be embedded in any 00136 * PostScript image that will be composited with other images, 00137 * where more than one image may be placed in an arbitrary location 00138 * on a page. */ 00139 00140 00141 /*-------------------------------------------------------------* 00142 * For uncompressed images * 00143 *-------------------------------------------------------------*/ 00144 /*! 00145 * pixWritePSEmbed() 00146 * 00147 * Input: filein (input file, all depths, colormap OK) 00148 * fileout (output ps file) 00149 * Return: 0 if OK, 1 on error 00150 * 00151 * Notes: 00152 * (1) This is a simple wrapper function that generates an 00153 * uncompressed PS file, with a bounding box. 00154 * (2) The bounding box is required when a program such as TeX 00155 * (through epsf) places and rescales the image. 00156 * (3) The bounding box is sized for fitting the image to an 00157 * 8.5 x 11.0 inch page. 00158 */ 00159 l_int32 00160 pixWritePSEmbed(const char *filein, 00161 const char *fileout) 00162 { 00163 l_int32 w, h; 00164 l_float32 scale; 00165 FILE *fp; 00166 PIX *pix; 00167 00168 PROCNAME("pixWritePSEmbed"); 00169 00170 if (!filein) 00171 return ERROR_INT("filein not defined", procName, 1); 00172 if (!fileout) 00173 return ERROR_INT("fileout not defined", procName, 1); 00174 00175 if ((pix = pixRead(filein)) == NULL) 00176 return ERROR_INT("image not read from file", procName, 1); 00177 w = pixGetWidth(pix); 00178 h = pixGetHeight(pix); 00179 if (w * 11.0 > h * 8.5) 00180 scale = 8.5 * 300. / (l_float32)w; 00181 else 00182 scale = 11.0 * 300. / (l_float32)h; 00183 00184 if ((fp = fopenWriteStream(fileout, "wb")) == NULL) 00185 return ERROR_INT("file not opened for write", procName, 1); 00186 pixWriteStreamPS(fp, pix, NULL, 0, scale); 00187 fclose(fp); 00188 00189 pixDestroy(&pix); 00190 return 0; 00191 } 00192 00193 00194 /*! 00195 * pixWriteStreamPS() 00196 * 00197 * Input: stream 00198 * pix 00199 * box (<optional>) 00200 * res (can use 0 for default of 300 ppi) 00201 * scale (to prevent scaling, use either 1.0 or 0.0) 00202 * Return: 0 if OK; 1 on error 00203 * 00204 * Notes: 00205 * (1) This writes image in PS format, optionally scaled, 00206 * adjusted for the printer resolution, and with 00207 * a bounding box. 00208 * (2) For details on use of parameters, see pixWriteStringPS(). 00209 */ 00210 l_int32 00211 pixWriteStreamPS(FILE *fp, 00212 PIX *pix, 00213 BOX *box, 00214 l_int32 res, 00215 l_float32 scale) 00216 { 00217 char *outstr; 00218 l_int32 length; 00219 PIX *pixc; 00220 00221 PROCNAME("pixWriteStreamPS"); 00222 00223 if (!fp) 00224 return (l_int32)ERROR_INT("stream not open", procName, 1); 00225 if (!pix) 00226 return (l_int32)ERROR_INT("pix not defined", procName, 1); 00227 00228 if ((pixc = pixConvertForPSWrap(pix)) == NULL) 00229 return (l_int32)ERROR_INT("pixc not made", procName, 1); 00230 00231 outstr = pixWriteStringPS(pixc, box, res, scale); 00232 length = strlen(outstr); 00233 fwrite(outstr, 1, length, fp); 00234 FREE(outstr); 00235 pixDestroy(&pixc); 00236 00237 return 0; 00238 } 00239 00240 00241 /*! 00242 * pixWriteStringPS() 00243 * 00244 * Input: pixs: all depths, colormap OK 00245 * box: (a) If box == null, image is placed, optionally scaled, 00246 * in a standard b.b. at the center of the page. 00247 * This is to be used when another program like 00248 * TeX (through epsf) places the image. 00249 * (b) If box != null, image is placed without a 00250 * b.b. at the specified page location and with 00251 * (optional) scaling. This is to be used when 00252 * you want to specify exactly where (and optionally 00253 * how big) you want the image to be. 00254 * Note that all coordinates are in PS convention, 00255 * with (0,0) at LL corner of the page: 00256 * (x,y) location of LL corner of image, in mils. 00257 * (w,h) scaled size, in mils. Use 0 to 00258 * scale with "scale" and "res" input. 00259 * res: resolution, in printer ppi. Use 0 for default (300 ppi). 00260 * scale: scale factor. If no scaling is desired, use 00261 * either 1.0 or 0.0. Scaling just resets the resolution 00262 * parameter; the actual scaling is done in the 00263 * interpreter at rendering time. This is important: 00264 * it allows you to scale the image up without 00265 * increasing the file size. 00266 * Return: ps string if OK, or null on error 00267 * 00268 * Notes: 00269 * (1) OK, this seems a bit complicated, because there are various 00270 * ways to scale and not to scale. Here's a summary: 00271 * (2) If you don't want any scaling at all: 00272 * * if you are using a box: 00273 * set w = 0, h = 0, and use scale = 1.0; it will print 00274 * each pixel unscaled at printer resolution 00275 * * if you are not using a box: 00276 * set scale = 1.0; it will print at printer resolution 00277 * (3) If you want the image to be a certain size in inches: 00278 * * you must use a box and set the box (w,h) in mils 00279 * (4) If you want the image to be scaled by a scale factor != 1.0: 00280 * * if you are using a box: 00281 * set w = 0, h = 0, and use the desired scale factor; 00282 * the higher the printer resolution, the smaller the 00283 * image will actually appear. 00284 * * if you are not using a box: 00285 * set the desired scale factor; the higher the printer 00286 * resolution, the smaller the image will actually appear. 00287 * (5) Another complication is the proliferation of distance units: 00288 * * The interface distances are in milli-inches. 00289 * * Three different units are used internally: 00290 * - pixels (units of 1/res inch) 00291 * - printer pts (units of 1/72 inch) 00292 * - inches 00293 * * Here is a quiz on volume units from a reviewer: 00294 * How many UK milli-cups in a US kilo-teaspoon? 00295 * (Hint: 1.0 US cup = 0.75 UK cup + 0.2 US gill; 00296 * 1.0 US gill = 24.0 US teaspoons) 00297 */ 00298 char * 00299 pixWriteStringPS(PIX *pixs, 00300 BOX *box, 00301 l_int32 res, 00302 l_float32 scale) 00303 { 00304 char nib1, nib2; 00305 char *hexdata, *outstr; 00306 l_uint8 byteval; 00307 l_int32 i, j, k, w, h, d; 00308 l_float32 wpt, hpt, xpt, ypt; 00309 l_int32 wpl, psbpl, hexbytes, boxflag, bps; 00310 l_uint32 *line, *data; 00311 PIX *pix; 00312 00313 PROCNAME("pixWriteStringPS"); 00314 00315 if (!pixs) 00316 return (char *)ERROR_PTR("pixs not defined", procName, NULL); 00317 00318 if ((pix = pixConvertForPSWrap(pixs)) == NULL) 00319 return (char *)ERROR_PTR("pix not made", procName, NULL); 00320 pixGetDimensions(pix, &w, &h, &d); 00321 00322 /* Get the factors by which PS scales and translates, in pts */ 00323 if (!box) 00324 boxflag = 0; /* no scaling; b.b. at center */ 00325 else 00326 boxflag = 1; /* no b.b., specify placement and optional scaling */ 00327 getScaledParametersPS(box, w, h, res, scale, &xpt, &ypt, &wpt, &hpt); 00328 00329 if (d == 1) 00330 bps = 1; /* bits/sample */ 00331 else /* d == 8 || d == 32 */ 00332 bps = 8; 00333 00334 /* Convert image data to hex string. psbpl is the number of 00335 * bytes in each raster line when it is packed to the byte 00336 * boundary (not the 32 bit word boundary, as with the pix). 00337 * When converted to hex, the hex string has 2 bytes for 00338 * every byte of raster data. */ 00339 wpl = pixGetWpl(pix); 00340 if (d == 1 || d == 8) 00341 psbpl = (w * d + 7) / 8; 00342 else /* d == 32 */ 00343 psbpl = 3 * w; 00344 data = pixGetData(pix); 00345 hexbytes = 2 * psbpl * h; /* size of ps hex array */ 00346 if ((hexdata = (char *)CALLOC(hexbytes + 1, sizeof(char))) == NULL) 00347 return (char *)ERROR_PTR("hexdata not made", procName, NULL); 00348 if (d == 1 || d == 8) { 00349 for (i = 0, k = 0; i < h; i++) { 00350 line = data + i * wpl; 00351 for (j = 0; j < psbpl; j++) { 00352 byteval = GET_DATA_BYTE(line, j); 00353 convertByteToHexAscii(byteval, &nib1, &nib2); 00354 hexdata[k++] = nib1; 00355 hexdata[k++] = nib2; 00356 } 00357 } 00358 } 00359 else { /* d == 32; hexdata bytes packed RGBRGB..., 2 per sample */ 00360 for (i = 0, k = 0; i < h; i++) { 00361 line = data + i * wpl; 00362 for (j = 0; j < w; j++) { 00363 byteval = GET_DATA_BYTE(line + j, 0); /* red */ 00364 convertByteToHexAscii(byteval, &nib1, &nib2); 00365 hexdata[k++] = nib1; 00366 hexdata[k++] = nib2; 00367 byteval = GET_DATA_BYTE(line + j, 1); /* green */ 00368 convertByteToHexAscii(byteval, &nib1, &nib2); 00369 hexdata[k++] = nib1; 00370 hexdata[k++] = nib2; 00371 byteval = GET_DATA_BYTE(line + j, 2); /* blue */ 00372 convertByteToHexAscii(byteval, &nib1, &nib2); 00373 hexdata[k++] = nib1; 00374 hexdata[k++] = nib2; 00375 } 00376 } 00377 } 00378 hexdata[k] = '\0'; 00379 00380 outstr = generateUncompressedPS(hexdata, w, h, d, psbpl, bps, 00381 xpt, ypt, wpt, hpt, boxflag); 00382 if (!outstr) 00383 return (char *)ERROR_PTR("outstr not made", procName, NULL); 00384 pixDestroy(&pix); 00385 return outstr; 00386 } 00387 00388 00389 /*! 00390 * generateUncompressedPS() 00391 * 00392 * Input: hexdata 00393 * w, h (raster image size in pixels) 00394 * d (image depth in bpp; rgb is 32) 00395 * psbpl (raster bytes/line, when packed to the byte boundary) 00396 * bps (bits/sample: either 1 or 8) 00397 * xpt, ypt (location of LL corner of image, in pts, relative 00398 * to the PostScript origin (0,0) at the LL corner 00399 * of the page) 00400 * wpt, hpt (rendered image size in pts) 00401 * boxflag (1 to print out bounding box hint; 0 to skip) 00402 * Return: PS string, or null on error 00403 * 00404 * Notes: 00405 * (1) Low-level function. 00406 */ 00407 char * 00408 generateUncompressedPS(char *hexdata, 00409 l_int32 w, 00410 l_int32 h, 00411 l_int32 d, 00412 l_int32 psbpl, 00413 l_int32 bps, 00414 l_float32 xpt, 00415 l_float32 ypt, 00416 l_float32 wpt, 00417 l_float32 hpt, 00418 l_int32 boxflag) 00419 { 00420 char *outstr; 00421 char bigbuf[L_BUF_SIZE]; 00422 SARRAY *sa; 00423 00424 PROCNAME("generateUncompressedPS"); 00425 00426 if (!hexdata) 00427 return (char *)ERROR_PTR("hexdata not defined", procName, NULL); 00428 00429 if ((sa = sarrayCreate(0)) == NULL) 00430 return (char *)ERROR_PTR("sa not made", procName, NULL); 00431 sarrayAddString(sa, (char *)"%!Adobe-PS", L_COPY); 00432 if (boxflag == 0) { 00433 sprintf(bigbuf, 00434 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f", 00435 xpt, ypt, xpt + wpt, ypt + hpt); 00436 sarrayAddString(sa, bigbuf, L_COPY); 00437 } 00438 else /* boxflag == 1 */ 00439 sarrayAddString(sa, (char *)"gsave", L_COPY); 00440 00441 if (d == 1) 00442 sarrayAddString(sa, 00443 (char *)"{1 exch sub} settransfer %invert binary", L_COPY); 00444 00445 sprintf(bigbuf, "/bpl %d string def %%bpl as a string", psbpl); 00446 sarrayAddString(sa, bigbuf, L_COPY); 00447 sprintf(bigbuf, 00448 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt); 00449 sarrayAddString(sa, bigbuf, L_COPY); 00450 sprintf(bigbuf, 00451 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt); 00452 sarrayAddString(sa, bigbuf, L_COPY); 00453 sprintf(bigbuf, 00454 "%d %d %d %%image dimensions in pixels", w, h, bps); 00455 sarrayAddString(sa, bigbuf, L_COPY); 00456 sprintf(bigbuf, 00457 "[%d %d %d %d %d %d] %%mapping matrix: [w 0 0 -h 0 h]", 00458 w, 0, 0, -h, 0, h); 00459 sarrayAddString(sa, bigbuf, L_COPY); 00460 00461 if (boxflag == 0) { 00462 if (d == 1 || d == 8) 00463 sarrayAddString(sa, 00464 (char *)"{currentfile bpl readhexstring pop} image", L_COPY); 00465 else /* d == 32 */ 00466 sarrayAddString(sa, 00467 (char *)"{currentfile bpl readhexstring pop} false 3 colorimage", 00468 L_COPY); 00469 } 00470 else { /* boxflag == 1 */ 00471 if (d == 1 || d == 8) 00472 sarrayAddString(sa, 00473 (char *)"{currentfile bpl readhexstring pop} bind image", L_COPY); 00474 else /* d == 32 */ 00475 sarrayAddString(sa, 00476 (char *)"{currentfile bpl readhexstring pop} bind false 3 colorimage", 00477 L_COPY); 00478 } 00479 00480 sarrayAddString(sa, hexdata, L_INSERT); 00481 00482 if (boxflag == 0) 00483 sarrayAddString(sa, (char *)"\nshowpage", L_COPY); 00484 else /* boxflag == 1 */ 00485 sarrayAddString(sa, (char *)"\ngrestore", L_COPY); 00486 00487 if ((outstr = sarrayToString(sa, 1)) == NULL) 00488 return (char *)ERROR_PTR("outstr not made", procName, NULL); 00489 00490 sarrayDestroy(&sa); 00491 return outstr; 00492 } 00493 00494 00495 /*! 00496 * getScaledParametersPS() 00497 * 00498 * Input: box (<optional> location of image in mils; with 00499 * (x,y) being the LL corner) 00500 * wpix (pix width in pixels) 00501 * hpix (pix height in pixels) 00502 * res (of printer; use 0 for default) 00503 * scale (use 1.0 or 0.0 for no scaling) 00504 * &xpt (location of llx in pts) 00505 * &ypt (location of lly in pts) 00506 * &wpt (image width in pts) 00507 * &hpt (image height in pts) 00508 * Return: void (no arg checking) 00509 * 00510 * Notes: 00511 * (1) The image is always scaled, depending on res and scale. 00512 * (2) If no box, the image is centered on the page. 00513 * (3) If there is a box, the image is placed within it. 00514 */ 00515 void 00516 getScaledParametersPS(BOX *box, 00517 l_int32 wpix, 00518 l_int32 hpix, 00519 l_int32 res, 00520 l_float32 scale, 00521 l_float32 *pxpt, 00522 l_float32 *pypt, 00523 l_float32 *pwpt, 00524 l_float32 *phpt) 00525 { 00526 l_int32 bx, by, bw, bh; 00527 l_float32 winch, hinch, xinch, yinch, fres; 00528 00529 PROCNAME("getScaledParametersPS"); 00530 00531 if (res == 0) 00532 res = DEFAULT_INPUT_RES; 00533 fres = (l_float32)res; 00534 00535 /* Allow the PS interpreter to scale the resolution */ 00536 if (scale == 0.0) 00537 scale = 1.0; 00538 if (scale != 1.0) { 00539 fres = (l_float32)res / scale; 00540 res = (l_int32)fres; 00541 } 00542 00543 /* Limit valid resolution interval */ 00544 if (res < MIN_RES || res > MAX_RES) { 00545 L_WARNING_INT("res %d out of bounds; using default res; no scaling", 00546 procName, res); 00547 res = DEFAULT_INPUT_RES; 00548 fres = (l_float32)res; 00549 } 00550 00551 if (!box) { /* center on page */ 00552 winch = (l_float32)wpix / fres; 00553 hinch = (l_float32)hpix / fres; 00554 xinch = (8.5 - winch) / 2.; 00555 yinch = (11.0 - hinch) / 2.; 00556 } 00557 else { 00558 boxGetGeometry(box, &bx, &by, &bw, &bh); 00559 if (bw == 0) 00560 winch = (l_float32)wpix / fres; 00561 else 00562 winch = (l_float32)bw / 1000.; 00563 if (bh == 0) 00564 hinch = (l_float32)hpix / fres; 00565 else 00566 hinch = (l_float32)bh / 1000.; 00567 xinch = (l_float32)bx / 1000.; 00568 yinch = (l_float32)by / 1000.; 00569 } 00570 00571 if (xinch < 0) 00572 L_WARNING("left edge < 0.0 inch", procName); 00573 if (xinch + winch > 8.5) 00574 L_WARNING("right edge > 8.5 inch", procName); 00575 if (yinch < 0.0) 00576 L_WARNING("bottom edge < 0.0 inch", procName); 00577 if (yinch + hinch > 11.0) 00578 L_WARNING("top edge > 11.0 inch", procName); 00579 00580 *pwpt = 72. * winch; 00581 *phpt = 72. * hinch; 00582 *pxpt = 72. * xinch; 00583 *pypt = 72. * yinch; 00584 return; 00585 } 00586 00587 00588 /*! 00589 * convertByteToHexAscii() 00590 * 00591 * Input: byteval (input byte) 00592 * &nib1, &nib2 (<return> two hex ascii characters) 00593 * Return: void 00594 */ 00595 void 00596 convertByteToHexAscii(l_uint8 byteval, 00597 char *pnib1, 00598 char *pnib2) 00599 { 00600 l_uint8 nib; 00601 00602 nib = byteval >> 4; 00603 if (nib < 10) 00604 *pnib1 = '0' + nib; 00605 else 00606 *pnib1 = 'a' + (nib - 10); 00607 nib = byteval & 0xf; 00608 if (nib < 10) 00609 *pnib2 = '0' + nib; 00610 else 00611 *pnib2 = 'a' + (nib - 10); 00612 00613 return; 00614 } 00615 00616 00617 /*-------------------------------------------------------------* 00618 * For jpeg compressed images * 00619 *-------------------------------------------------------------*/ 00620 /*! 00621 * convertJpegToPSEmbed() 00622 * 00623 * Input: filein (input jpeg file) 00624 * fileout (output ps file) 00625 * Return: 0 if OK, 1 on error 00626 * 00627 * Notes: 00628 * (1) This function takes a jpeg file as input and generates a DCT 00629 * compressed, ascii85 encoded PS file, with a bounding box. 00630 * (2) The bounding box is required when a program such as TeX 00631 * (through epsf) places and rescales the image. 00632 * (3) The bounding box is sized for fitting the image to an 00633 * 8.5 x 11.0 inch page. 00634 */ 00635 l_int32 00636 convertJpegToPSEmbed(const char *filein, 00637 const char *fileout) 00638 { 00639 char *outstr; 00640 l_int32 w, h, nbytes; 00641 l_float32 xpt, ypt, wpt, hpt; 00642 L_COMPRESSED_DATA *cid; 00643 00644 PROCNAME("convertJpegToPSEmbed"); 00645 00646 if (!filein) 00647 return ERROR_INT("filein not defined", procName, 1); 00648 if (!fileout) 00649 return ERROR_INT("fileout not defined", procName, 1); 00650 00651 /* Generate the ascii encoded jpeg data */ 00652 if ((cid = l_generateJpegData(filein, 1)) == NULL) 00653 return ERROR_INT("jpeg data not made", procName, 1); 00654 w = cid->w; 00655 h = cid->h; 00656 00657 /* Scale for 20 pt boundary and otherwise full filling 00658 * in one direction on 8.5 x 11 inch device */ 00659 xpt = 20.0; 00660 ypt = 20.0; 00661 if (w * 11.0 > h * 8.5) { 00662 wpt = 572.0; /* 612 - 2 * 20 */ 00663 hpt = wpt * (l_float32)h / (l_float32)w; 00664 } 00665 else { 00666 hpt = 752.0; /* 792 - 2 * 20 */ 00667 wpt = hpt * (l_float32)w / (l_float32)h; 00668 } 00669 00670 /* Generate the PS. 00671 * The bounding box information should be inserted (default). */ 00672 outstr = generateJpegPS(filein, cid, xpt, ypt, wpt, hpt, 1, 1); 00673 if (!outstr) 00674 return ERROR_INT("outstr not made", procName, 1); 00675 nbytes = strlen(outstr); 00676 00677 if (l_binaryWrite(fileout, "w", outstr, nbytes)) 00678 return ERROR_INT("ps string not written to file", procName, 1); 00679 FREE(outstr); 00680 compressed_dataDestroy(&cid); 00681 return 0; 00682 } 00683 00684 00685 /*! 00686 * convertJpegToPS() 00687 * 00688 * Input: filein (input jpeg file) 00689 * fileout (output ps file) 00690 * operation ("w" for write; "a" for append) 00691 * x, y (location of LL corner of image, in pixels, relative 00692 * to the PostScript origin (0,0) at the LL corner 00693 * of the page) 00694 * res (resolution of the input image, in ppi; use 0 for default) 00695 * scale (scaling by printer; use 0.0 or 1.0 for no scaling) 00696 * pageno (page number; must start with 1; you can use 0 00697 * if there is only one page) 00698 * endpage (boolean: use TRUE if this is the last image to be 00699 * added to the page; FALSE otherwise) 00700 * Return: 0 if OK, 1 on error 00701 * 00702 * Notes: 00703 * (1) This is simpler to use than pixWriteStringPS(), and 00704 * it outputs in level 2 PS as compressed DCT (overlaid 00705 * with ascii85 encoding). 00706 * (2) An output file can contain multiple pages, each with 00707 * multiple images. The arguments to convertJpegToPS() 00708 * allow you to control placement of jpeg images on multiple 00709 * pages within a PostScript file. 00710 * (3) For the first image written to a file, use "w", which 00711 * opens for write and clears the file. For all subsequent 00712 * images written to that file, use "a". 00713 * (4) The (x, y) parameters give the LL corner of the image 00714 * relative to the LL corner of the page. They are in 00715 * units of pixels if scale = 1.0. If you use (e.g.) 00716 * scale = 2.0, the image is placed at (2x, 2y) on the page, 00717 * and the image dimensions are also doubled. 00718 * (5) Display vs printed resolution: 00719 * * If your display is 75 ppi and your image was created 00720 * at a resolution of 300 ppi, you can get the image 00721 * to print at the same size as it appears on your display 00722 * by either setting scale = 4.0 or by setting res = 75. 00723 * Both tell the printer to make a 4x enlarged image. 00724 * * If your image is generated at 150 ppi and you use scale = 1, 00725 * it will be rendered such that 150 pixels correspond 00726 * to 72 pts (1 inch on the printer). This function does 00727 * the conversion from pixels (with or without scaling) to 00728 * pts, which are the units that the printer uses. 00729 * * The printer will choose its own resolution to use 00730 * in rendering the image, which will not affect the size 00731 * of the rendered image. That is because the output 00732 * PostScript file describes the geometry in terms of pts, 00733 * which are defined to be 1/72 inch. The printer will 00734 * only see the size of the image in pts, through the 00735 * scale and translate parameters and the affine 00736 * transform (the ImageMatrix) of the image. 00737 * (6) To render multiple images on the same page, set 00738 * endpage = FALSE for each image until you get to the 00739 * last, for which you set endpage = TRUE. This causes the 00740 * "showpage" command to be invoked. Showpage outputs 00741 * the entire page and clears the raster buffer for the 00742 * next page to be added. Without a "showpage", 00743 * subsequent images from the next page will overlay those 00744 * previously put down. 00745 * (7) For multiple pages, increment the page number, starting 00746 * with page 1. This allows PostScript (and PDF) to build 00747 * a page directory, which viewers use for navigation. 00748 */ 00749 l_int32 00750 convertJpegToPS(const char *filein, 00751 const char *fileout, 00752 const char *operation, 00753 l_int32 x, 00754 l_int32 y, 00755 l_int32 res, 00756 l_float32 scale, 00757 l_int32 pageno, 00758 l_int32 endpage) 00759 { 00760 char *outstr; 00761 l_int32 nbytes; 00762 00763 PROCNAME("convertJpegToPS"); 00764 00765 if (!filein) 00766 return ERROR_INT("filein not defined", procName, 1); 00767 if (!fileout) 00768 return ERROR_INT("fileout not defined", procName, 1); 00769 if (strcmp(operation, "w") && strcmp(operation, "a")) 00770 return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1); 00771 00772 if (convertJpegToPSString(filein, &outstr, &nbytes, x, y, res, scale, 00773 pageno, endpage)) 00774 return ERROR_INT("ps string not made", procName, 1); 00775 00776 if (l_binaryWrite(fileout, operation, outstr, nbytes)) 00777 return ERROR_INT("ps string not written to file", procName, 1); 00778 00779 FREE(outstr); 00780 return 0; 00781 } 00782 00783 00784 /*! 00785 * convertJpegToPSString() 00786 * 00787 * Generates PS string in jpeg format from jpeg file 00788 * 00789 * Input: filein (input jpeg file) 00790 * &poutstr (<return> PS string) 00791 * &nbytes (<return> number of bytes in PS string) 00792 * x, y (location of LL corner of image, in pixels, relative 00793 * to the PostScript origin (0,0) at the LL corner 00794 * of the page) 00795 * res (resolution of the input image, in ppi; use 0 for default) 00796 * scale (scaling by printer; use 0.0 or 1.0 for no scaling) 00797 * pageno (page number; must start with 1; you can use 0 00798 * if there is only one page) 00799 * endpage (boolean: use TRUE if this is the last image to be 00800 * added to the page; FALSE otherwise) 00801 * Return: 0 if OK, 1 on error 00802 * 00803 * Notes: 00804 * (1) For usage, see convertJpegToPS() 00805 */ 00806 l_int32 00807 convertJpegToPSString(const char *filein, 00808 char **poutstr, 00809 l_int32 *pnbytes, 00810 l_int32 x, 00811 l_int32 y, 00812 l_int32 res, 00813 l_float32 scale, 00814 l_int32 pageno, 00815 l_int32 endpage) 00816 { 00817 char *outstr; 00818 l_float32 xpt, ypt, wpt, hpt; 00819 L_COMPRESSED_DATA *cid; 00820 00821 PROCNAME("convertJpegToPSString"); 00822 00823 if (!poutstr) 00824 return ERROR_INT("&outstr not defined", procName, 1); 00825 if (!pnbytes) 00826 return ERROR_INT("&nbytes not defined", procName, 1); 00827 *poutstr = NULL; 00828 *pnbytes = 0; 00829 if (!filein) 00830 return ERROR_INT("filein not defined", procName, 1); 00831 00832 /* Generate the ascii encoded jpeg data */ 00833 if ((cid = l_generateJpegData(filein, 1)) == NULL) 00834 return ERROR_INT("jpeg data not made", procName, 1); 00835 00836 /* Get scaled location in pts. Guess the input scan resolution 00837 * based on the input parameter @res, the resolution data in 00838 * the pix, and the size of the image. */ 00839 if (scale == 0.0) 00840 scale = 1.0; 00841 if (res <= 0) { 00842 if (cid->res > 0) 00843 res = cid->res; 00844 else 00845 res = DEFAULT_INPUT_RES; 00846 } 00847 00848 /* Get scaled location in pts */ 00849 if (scale == 0.0) 00850 scale = 1.0; 00851 if (res == 0) 00852 res = DEFAULT_INPUT_RES; 00853 xpt = scale * x * 72. / res; 00854 ypt = scale * y * 72. / res; 00855 wpt = scale * cid->w * 72. / res; 00856 hpt = scale * cid->h * 72. / res; 00857 00858 if (pageno == 0) 00859 pageno = 1; 00860 00861 #if DEBUG_JPEG 00862 fprintf(stderr, "w = %d, h = %d, bps = %d, spp = %d\n", 00863 cid->w, cid->h, cid->bps, cid->spp); 00864 fprintf(stderr, "comp bytes = %d, nbytes85 = %d, ratio = %5.3f\n", 00865 cid->nbytescomp, cid->nbytes85, 00866 (l_float32)cid->nbytes85 / (l_float32)cid->nbytescomp); 00867 fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n", 00868 xpt, ypt, wpt, hpt); 00869 #endif /* DEBUG_JPEG */ 00870 00871 /* Generate the PS */ 00872 outstr = generateJpegPS(filein, cid, xpt, ypt, wpt, hpt, pageno, endpage); 00873 if (!outstr) 00874 return ERROR_INT("outstr not made", procName, 1); 00875 *poutstr = outstr; 00876 *pnbytes = strlen(outstr); 00877 compressed_dataDestroy(&cid); 00878 return 0; 00879 } 00880 00881 00882 /*! 00883 * generateJpegPS() 00884 * 00885 * Input: filein (<optional> input jpeg filename; can be null) 00886 * cid (jpeg compressed image data) 00887 * xpt, ypt (location of LL corner of image, in pts, relative 00888 * to the PostScript origin (0,0) at the LL corner 00889 * of the page) 00890 * wpt, hpt (rendered image size in pts) 00891 * pageno (page number; must start with 1; you can use 0 00892 * if there is only one page.) 00893 * endpage (boolean: use TRUE if this is the last image to be 00894 * added to the page; FALSE otherwise) 00895 * Return: PS string, or null on error 00896 * 00897 * Notes: 00898 * (1) Low-level function. 00899 */ 00900 char * 00901 generateJpegPS(const char *filein, 00902 L_COMPRESSED_DATA *cid, 00903 l_float32 xpt, 00904 l_float32 ypt, 00905 l_float32 wpt, 00906 l_float32 hpt, 00907 l_int32 pageno, 00908 l_int32 endpage) 00909 { 00910 l_int32 w, h, bps, spp; 00911 char *outstr; 00912 char bigbuf[L_BUF_SIZE]; 00913 SARRAY *sa; 00914 00915 PROCNAME("generateJpegPS"); 00916 00917 if (!cid) 00918 return (char *)ERROR_PTR("jpeg data not defined", procName, NULL); 00919 w = cid->w; 00920 h = cid->h; 00921 bps = cid->bps; 00922 spp = cid->spp; 00923 00924 if ((sa = sarrayCreate(50)) == NULL) 00925 return (char *)ERROR_PTR("sa not made", procName, NULL); 00926 00927 sarrayAddString(sa, (char *)"%!PS-Adobe-3.0", L_COPY); 00928 sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY); 00929 if (filein) { 00930 sprintf(bigbuf, "%%%%Title: %s", filein); 00931 sarrayAddString(sa, bigbuf, L_COPY); 00932 } 00933 sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY); 00934 00935 if (var_PS_WRITE_BOUNDING_BOX == 1) { 00936 sprintf(bigbuf, 00937 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f", 00938 xpt, ypt, xpt + wpt, ypt + hpt); 00939 sarrayAddString(sa, bigbuf, L_COPY); 00940 } 00941 00942 sarrayAddString(sa, (char *)"%%LanguageLevel: 2", L_COPY); 00943 sarrayAddString(sa, (char *)"%%EndComments", L_COPY); 00944 sprintf(bigbuf, "%%%%Page: %d %d", pageno, pageno); 00945 sarrayAddString(sa, bigbuf, L_COPY); 00946 00947 sarrayAddString(sa, (char *)"save", L_COPY); 00948 sarrayAddString(sa, 00949 (char *)"/RawData currentfile /ASCII85Decode filter def", L_COPY); 00950 sarrayAddString(sa, 00951 (char *)"/Data RawData << >> /DCTDecode filter def", L_COPY); 00952 00953 sprintf(bigbuf, 00954 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt); 00955 sarrayAddString(sa, bigbuf, L_COPY); 00956 00957 sprintf(bigbuf, 00958 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt); 00959 sarrayAddString(sa, bigbuf, L_COPY); 00960 00961 if (spp == 1) 00962 sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY); 00963 else if (spp == 3) 00964 sarrayAddString(sa, (char *)"/DeviceRGB setcolorspace", L_COPY); 00965 else /*spp == 4 */ 00966 sarrayAddString(sa, (char *)"/DeviceCMYK setcolorspace", L_COPY); 00967 00968 sarrayAddString(sa, (char *)"{ << /ImageType 1", L_COPY); 00969 sprintf(bigbuf, " /Width %d", w); 00970 sarrayAddString(sa, bigbuf, L_COPY); 00971 sprintf(bigbuf, " /Height %d", h); 00972 sarrayAddString(sa, bigbuf, L_COPY); 00973 sprintf(bigbuf, " /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h); 00974 sarrayAddString(sa, bigbuf, L_COPY); 00975 sarrayAddString(sa, (char *)" /DataSource Data", L_COPY); 00976 sprintf(bigbuf, " /BitsPerComponent %d", bps); 00977 sarrayAddString(sa, bigbuf, L_COPY); 00978 00979 if (spp == 1) 00980 sarrayAddString(sa, (char *)" /Decode [0 1]", L_COPY); 00981 else if (spp == 3) 00982 sarrayAddString(sa, (char *)" /Decode [0 1 0 1 0 1]", L_COPY); 00983 else /* spp == 4 */ 00984 sarrayAddString(sa, (char *)" /Decode [0 1 0 1 0 1 0 1]", L_COPY); 00985 00986 sarrayAddString(sa, (char *)" >> image", L_COPY); 00987 sarrayAddString(sa, (char *)" Data closefile", L_COPY); 00988 sarrayAddString(sa, (char *)" RawData flushfile", L_COPY); 00989 if (endpage == TRUE) 00990 sarrayAddString(sa, (char *)" showpage", L_COPY); 00991 sarrayAddString(sa, (char *)" restore", L_COPY); 00992 sarrayAddString(sa, (char *)"} exec", L_COPY); 00993 00994 /* Insert the ascii85 jpeg data; this is now owned by sa */ 00995 sarrayAddString(sa, cid->data85, L_INSERT); 00996 cid->data85 = NULL; /* it has been transferred and destroyed */ 00997 00998 /* Generate and return the output string */ 00999 outstr = sarrayToString(sa, 1); 01000 sarrayDestroy(&sa); 01001 return outstr; 01002 } 01003 01004 01005 /*! 01006 * pixGenerateJpegData() 01007 * 01008 * Input: pixs (8 or 32 bpp, no colormap) 01009 * ascii85flag (0 for jpeg; 1 for ascii85-encoded jpeg) 01010 * quality (0 for default, which is 75) 01011 * Return: cid (jpeg compressed data), or null on error 01012 * 01013 * Notes: 01014 * (1) Set ascii85flag: 01015 * - 0 for binary data (not permitted in PostScript) 01016 * - 1 for ascii85 (5 for 4) encoded binary data 01017 */ 01018 L_COMPRESSED_DATA * 01019 pixGenerateJpegData(PIX *pixs, 01020 l_int32 ascii85flag, 01021 l_int32 quality) 01022 { 01023 l_int32 d; 01024 char *tname; 01025 L_COMPRESSED_DATA *cid; 01026 01027 PROCNAME("pixGenerateJpegData"); 01028 01029 if (!pixs) 01030 return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not defined", 01031 procName, NULL); 01032 if (pixGetColormap(pixs)) 01033 return (L_COMPRESSED_DATA *)ERROR_PTR("pixs has colormap", 01034 procName, NULL); 01035 d = pixGetDepth(pixs); 01036 if (d != 8 && d != 32) 01037 return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not 8 or 32 bpp", 01038 procName, NULL); 01039 01040 /* Compress to a temp jpeg file */ 01041 tname = genTempFilename("/tmp", "temp.jpg", 1, 1); 01042 pixWriteJpeg(tname, pixs, quality, 0); 01043 01044 cid = l_generateJpegData(tname, ascii85flag); 01045 FREE(tname); 01046 return cid; 01047 } 01048 01049 01050 /*! 01051 * l_generateJpegData() 01052 * 01053 * Input: fname (of jpeg file) 01054 * ascii85flag (0 for jpeg; 1 for ascii85-encoded jpeg) 01055 * Return: cid (containing jpeg data), or null on error 01056 * 01057 * Notes: 01058 * (1) Set ascii85flag: 01059 * - 0 for binary data (not permitted in PostScript) 01060 * - 1 for ascii85 (5 for 4) encoded binary data 01061 */ 01062 L_COMPRESSED_DATA * 01063 l_generateJpegData(const char *fname, 01064 l_int32 ascii85flag) 01065 { 01066 l_uint8 *datacomp = NULL; /* entire jpeg compressed file */ 01067 char *data85 = NULL; /* ascii85 encoded jpeg compressed file */ 01068 l_int32 w, h, xres, yres, bps, spp; 01069 l_int32 nbytes85; 01070 size_t nbytescomp; 01071 FILE *fp; 01072 L_COMPRESSED_DATA *cid; 01073 01074 PROCNAME("l_generateJpegData"); 01075 01076 if (!fname) 01077 return (L_COMPRESSED_DATA *)ERROR_PTR("fname not defined", 01078 procName, NULL); 01079 01080 /* The returned jpeg data in memory is the entire jpeg file, 01081 * which starts with ffd8 and ends with ffd9 */ 01082 if ((datacomp = l_binaryRead(fname, &nbytescomp)) == NULL) 01083 return (L_COMPRESSED_DATA *)ERROR_PTR("datacomp not extracted", 01084 procName, NULL); 01085 01086 /* Read the metadata */ 01087 if ((fp = fopenReadStream(fname)) == NULL) 01088 return (L_COMPRESSED_DATA *)ERROR_PTR("stream not opened", 01089 procName, NULL); 01090 freadHeaderJpeg(fp, &w, &h, &spp, NULL, NULL); 01091 bps = 8; 01092 fgetJpegResolution(fp, &xres, &yres); 01093 fclose(fp); 01094 01095 /* Optionally, encode the compressed data */ 01096 if (ascii85flag == 1) { 01097 data85 = encodeAscii85(datacomp, nbytescomp, &nbytes85); 01098 FREE(datacomp); 01099 if (!data85) 01100 return (L_COMPRESSED_DATA *)ERROR_PTR("data85 not made", 01101 procName, NULL); 01102 else 01103 data85[nbytes85 - 1] = '\0'; /* remove the newline */ 01104 } 01105 01106 cid = (L_COMPRESSED_DATA *)CALLOC(1, sizeof(L_COMPRESSED_DATA)); 01107 if (!cid) 01108 return (L_COMPRESSED_DATA *)ERROR_PTR("cid not made", procName, NULL); 01109 if (ascii85flag == 0) 01110 cid->datacomp = datacomp; 01111 else { /* ascii85 */ 01112 cid->data85 = data85; 01113 cid->nbytes85 = nbytes85; 01114 } 01115 cid->type = L_JPEG_ENCODE; 01116 cid->nbytescomp = nbytescomp; 01117 cid->w = w; 01118 cid->h = h; 01119 cid->bps = bps; 01120 cid->spp = spp; 01121 cid->res = xres; 01122 return cid; 01123 } 01124 01125 01126 /*! 01127 * compressed_dataDestroy() 01128 * 01129 * Input: &cid (<will be set to null before returning>) 01130 * Return: void 01131 */ 01132 void 01133 compressed_dataDestroy(L_COMPRESSED_DATA **pcid) 01134 { 01135 L_COMPRESSED_DATA *cid; 01136 01137 PROCNAME("compressed_dataDestroy"); 01138 01139 if (pcid == NULL) { 01140 L_WARNING("ptr address is null!", procName); 01141 return; 01142 } 01143 if ((cid = *pcid) == NULL) 01144 return; 01145 01146 if (cid->datacomp) FREE(cid->datacomp); 01147 if (cid->data85) FREE(cid->data85); 01148 if (cid->cmapdata85) FREE(cid->cmapdata85); 01149 if (cid->cmapdatahex) FREE(cid->cmapdatahex); 01150 FREE(cid); 01151 *pcid = NULL; 01152 return; 01153 } 01154 01155 01156 /*-------------------------------------------------------------* 01157 * For ccitt g4 compressed images * 01158 *-------------------------------------------------------------*/ 01159 /*! 01160 * convertG4ToPSEmbed() 01161 * 01162 * Input: filein (input tiff file) 01163 * fileout (output ps file) 01164 * Return: 0 if OK, 1 on error 01165 * 01166 * Notes: 01167 * (1) This function takes a g4 compressed tif file as input and 01168 * generates a g4 compressed, ascii85 encoded PS file, with 01169 * a bounding box. 01170 * (2) The bounding box is required when a program such as TeX 01171 * (through epsf) places and rescales the image. 01172 * (3) The bounding box is sized for fitting the image to an 01173 * 8.5 x 11.0 inch page. 01174 * (4) We paint this through a mask, over whatever is below. 01175 */ 01176 l_int32 01177 convertG4ToPSEmbed(const char *filein, 01178 const char *fileout) 01179 { 01180 char *outstr; 01181 l_int32 w, h, nbytes; 01182 l_float32 xpt, ypt, wpt, hpt; 01183 L_COMPRESSED_DATA *cid; 01184 01185 PROCNAME("convertG4ToPSEmbed"); 01186 01187 if (!filein) 01188 return ERROR_INT("filein not defined", procName, 1); 01189 if (!fileout) 01190 return ERROR_INT("fileout not defined", procName, 1); 01191 01192 if ((cid = l_generateG4Data(filein, 1)) == NULL) 01193 return ERROR_INT("g4 data not made", procName, 1); 01194 w = cid->w; 01195 h = cid->h; 01196 01197 /* Scale for 20 pt boundary and otherwise full filling 01198 * in one direction on 8.5 x 11 inch device */ 01199 xpt = 20.0; 01200 ypt = 20.0; 01201 if (w * 11.0 > h * 8.5) { 01202 wpt = 572.0; /* 612 - 2 * 20 */ 01203 hpt = wpt * (l_float32)h / (l_float32)w; 01204 } 01205 else { 01206 hpt = 752.0; /* 792 - 2 * 20 */ 01207 wpt = hpt * (l_float32)w / (l_float32)h; 01208 } 01209 01210 /* Generate the PS, painting through the image mask. 01211 * The bounding box information should be inserted (default). */ 01212 outstr = generateG4PS(filein, cid, xpt, ypt, wpt, hpt, 1, 1, 1); 01213 if (!outstr) 01214 return ERROR_INT("outstr not made", procName, 1); 01215 nbytes = strlen(outstr); 01216 01217 if (l_binaryWrite(fileout, "w", outstr, nbytes)) 01218 return ERROR_INT("ps string not written to file", procName, 1); 01219 FREE(outstr); 01220 compressed_dataDestroy(&cid); 01221 return 0; 01222 } 01223 01224 01225 /*! 01226 * convertG4ToPS() 01227 * 01228 * Input: filein (input tiff g4 file) 01229 * fileout (output ps file) 01230 * operation ("w" for write; "a" for append) 01231 * x, y (location of LL corner of image, in pixels, relative 01232 * to the PostScript origin (0,0) at the LL corner 01233 * of the page) 01234 * res (resolution of the input image, in ppi; typ. values 01235 * are 300 and 600; use 0 for automatic determination 01236 * based on image size) 01237 * scale (scaling by printer; use 0.0 or 1.0 for no scaling) 01238 * pageno (page number; must start with 1; you can use 0 01239 * if there is only one page.) 01240 * maskflag (boolean: use TRUE if just painting through fg; 01241 * FALSE if painting both fg and bg. 01242 * endpage (boolean: use TRUE if this is the last image to be 01243 * added to the page; FALSE otherwise) 01244 * Return: 0 if OK, 1 on error 01245 * 01246 * Notes: 01247 * (1) See the usage comments in convertJpegToPS(), some of 01248 * which are repeated here. 01249 * (2) This is a wrapper for tiff g4. The PostScript that 01250 * is generated is expanded by about 5/4 (due to the 01251 * ascii85 encoding. If you convert to pdf (ps2pdf), the 01252 * ascii85 decoder is automatically invoked, so that the 01253 * pdf wrapped g4 file is essentially the same size as 01254 * the original g4 file. It's useful to have the PS 01255 * file ascii85 encoded, because many printers will not 01256 * print binary PS files. 01257 * (3) For the first image written to a file, use "w", which 01258 * opens for write and clears the file. For all subsequent 01259 * images written to that file, use "a". 01260 * (4) To render multiple images on the same page, set 01261 * endpage = FALSE for each image until you get to the 01262 * last, for which you set endpage = TRUE. This causes the 01263 * "showpage" command to be invoked. Showpage outputs 01264 * the entire page and clears the raster buffer for the 01265 * next page to be added. Without a "showpage", 01266 * subsequent images from the next page will overlay those 01267 * previously put down. 01268 * (5) For multiple images to the same page, where you are writing 01269 * both jpeg and tiff-g4, you have two options: 01270 * (a) write the g4 first, as either image (maskflag == FALSE) 01271 * or imagemask (maskflag == TRUE), and then write the 01272 * jpeg over it. 01273 * (b) write the jpeg first and as the last item, write 01274 * the g4 as an imagemask (maskflag == TRUE), to paint 01275 * through the foreground only. 01276 * We have this flexibility with the tiff-g4 because it is 1 bpp. 01277 * (6) For multiple pages, increment the page number, starting 01278 * with page 1. This allows PostScript (and PDF) to build 01279 * a page directory, which viewers use for navigation. 01280 */ 01281 l_int32 01282 convertG4ToPS(const char *filein, 01283 const char *fileout, 01284 const char *operation, 01285 l_int32 x, 01286 l_int32 y, 01287 l_int32 res, 01288 l_float32 scale, 01289 l_int32 pageno, 01290 l_int32 maskflag, 01291 l_int32 endpage) 01292 { 01293 char *outstr; 01294 l_int32 nbytes; 01295 01296 PROCNAME("convertG4ToPS"); 01297 01298 if (!filein) 01299 return ERROR_INT("filein not defined", procName, 1); 01300 if (!fileout) 01301 return ERROR_INT("fileout not defined", procName, 1); 01302 if (strcmp(operation, "w") && strcmp(operation, "a")) 01303 return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1); 01304 01305 if (convertG4ToPSString(filein, &outstr, &nbytes, x, y, res, scale, 01306 pageno, maskflag, endpage)) 01307 return ERROR_INT("ps string not made", procName, 1); 01308 01309 if (l_binaryWrite(fileout, operation, outstr, nbytes)) 01310 return ERROR_INT("ps string not written to file", procName, 1); 01311 01312 FREE(outstr); 01313 return 0; 01314 } 01315 01316 01317 /*! 01318 * convertG4ToPSString() 01319 * 01320 * Input: filein (input tiff g4 file) 01321 * &poutstr (<return> PS string) 01322 * &nbytes (<return> number of bytes in PS string) 01323 * x, y (location of LL corner of image, in pixels, relative 01324 * to the PostScript origin (0,0) at the LL corner 01325 * of the page) 01326 * res (resolution of the input image, in ppi; typ. values 01327 * are 300 and 600; use 0 for automatic determination 01328 * based on image size) 01329 * scale (scaling by printer; use 0.0 or 1.0 for no scaling) 01330 * pageno (page number; must start with 1; you can use 0 01331 * if there is only one page.) 01332 * maskflag (boolean: use TRUE if just painting through fg; 01333 * FALSE if painting both fg and bg. 01334 * endpage (boolean: use TRUE if this is the last image to be 01335 * added to the page; FALSE otherwise) 01336 * Return: 0 if OK, 1 on error 01337 * 01338 * Notes: 01339 * (1) Generates PS string in G4 compressed tiff format from G4 tiff file. 01340 * (2) For usage, see convertG4ToPS(). 01341 */ 01342 l_int32 01343 convertG4ToPSString(const char *filein, 01344 char **poutstr, 01345 l_int32 *pnbytes, 01346 l_int32 x, 01347 l_int32 y, 01348 l_int32 res, 01349 l_float32 scale, 01350 l_int32 pageno, 01351 l_int32 maskflag, 01352 l_int32 endpage) 01353 { 01354 char *outstr; 01355 l_float32 xpt, ypt, wpt, hpt; 01356 L_COMPRESSED_DATA *cid; 01357 01358 PROCNAME("convertG4ToPSString"); 01359 01360 if (!poutstr) 01361 return ERROR_INT("&outstr not defined", procName, 1); 01362 if (!pnbytes) 01363 return ERROR_INT("&nbytes not defined", procName, 1); 01364 *poutstr = NULL; 01365 *pnbytes = 0; 01366 if (!filein) 01367 return ERROR_INT("filein not defined", procName, 1); 01368 01369 if ((cid = l_generateG4Data(filein, 1)) == NULL) 01370 return ERROR_INT("g4 data not made", procName, 1); 01371 01372 /* Get scaled location in pts. Guess the input scan resolution 01373 * based on the input parameter @res, the resolution data in 01374 * the pix, and the size of the image. */ 01375 if (scale == 0.0) 01376 scale = 1.0; 01377 if (res <= 0) { 01378 if (cid->res > 0) 01379 res = cid->res; 01380 else { 01381 if (cid->h <= 3509) /* A4 height at 300 ppi */ 01382 res = 300; 01383 else 01384 res = 600; 01385 } 01386 } 01387 xpt = scale * x * 72. / res; 01388 ypt = scale * y * 72. / res; 01389 wpt = scale * cid->w * 72. / res; 01390 hpt = scale * cid->h * 72. / res; 01391 01392 if (pageno == 0) 01393 pageno = 1; 01394 01395 #if DEBUG_G4 01396 fprintf(stderr, "w = %d, h = %d, minisblack = %d\n", 01397 cid->w, cid->h, cid->minisblack); 01398 fprintf(stderr, "comp bytes = %d, nbytes85 = %d\n", 01399 cid->nbytescomp, cid->nbytes85); 01400 fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n", 01401 xpt, ypt, wpt, hpt); 01402 #endif /* DEBUG_G4 */ 01403 01404 /* Generate the PS */ 01405 outstr = generateG4PS(filein, cid, xpt, ypt, wpt, hpt, 01406 maskflag, pageno, endpage); 01407 if (!outstr) 01408 return ERROR_INT("outstr not made", procName, 1); 01409 *poutstr = outstr; 01410 *pnbytes = strlen(outstr); 01411 compressed_dataDestroy(&cid); 01412 return 0; 01413 } 01414 01415 01416 /*! 01417 * generateG4PS() 01418 * 01419 * Input: filein (<optional> input tiff g4 file; can be null) 01420 * cid (g4 compressed image data) 01421 * xpt, ypt (location of LL corner of image, in pts, relative 01422 * to the PostScript origin (0,0) at the LL corner 01423 * of the page) 01424 * wpt, hpt (rendered image size in pts) 01425 * maskflag (boolean: use TRUE if just painting through fg; 01426 * FALSE if painting both fg and bg. 01427 * pageno (page number; must start with 1; you can use 0 01428 * if there is only one page.) 01429 * endpage (boolean: use TRUE if this is the last image to be 01430 * added to the page; FALSE otherwise) 01431 * Return: PS string, or null on error 01432 * 01433 * Notes: 01434 * (1) Low-level function. 01435 */ 01436 char * 01437 generateG4PS(const char *filein, 01438 L_COMPRESSED_DATA *cid, 01439 l_float32 xpt, 01440 l_float32 ypt, 01441 l_float32 wpt, 01442 l_float32 hpt, 01443 l_int32 maskflag, 01444 l_int32 pageno, 01445 l_int32 endpage) 01446 { 01447 l_int32 w, h; 01448 char *outstr; 01449 char bigbuf[L_BUF_SIZE]; 01450 SARRAY *sa; 01451 01452 PROCNAME("generateG4PS"); 01453 01454 if (!cid) 01455 return (char *)ERROR_PTR("g4 data not defined", procName, NULL); 01456 w = cid->w; 01457 h = cid->h; 01458 01459 if ((sa = sarrayCreate(50)) == NULL) 01460 return (char *)ERROR_PTR("sa not made", procName, NULL); 01461 01462 sarrayAddString(sa, (char *)"%!PS-Adobe-3.0", L_COPY); 01463 sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY); 01464 if (filein) { 01465 sprintf(bigbuf, "%%%%Title: %s", filein); 01466 sarrayAddString(sa, bigbuf, L_COPY); 01467 } 01468 sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY); 01469 01470 if (var_PS_WRITE_BOUNDING_BOX == 1) { 01471 sprintf(bigbuf, 01472 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f", 01473 xpt, ypt, xpt + wpt, ypt + hpt); 01474 sarrayAddString(sa, bigbuf, L_COPY); 01475 } 01476 01477 sarrayAddString(sa, (char *)"%%LanguageLevel: 2", L_COPY); 01478 sarrayAddString(sa, (char *)"%%EndComments", L_COPY); 01479 sprintf(bigbuf, "%%%%Page: %d %d", pageno, pageno); 01480 sarrayAddString(sa, bigbuf, L_COPY); 01481 01482 sarrayAddString(sa, (char *)"save", L_COPY); 01483 sarrayAddString(sa, (char *)"100 dict begin", L_COPY); 01484 01485 sprintf(bigbuf, 01486 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt); 01487 sarrayAddString(sa, bigbuf, L_COPY); 01488 01489 sprintf(bigbuf, 01490 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt); 01491 sarrayAddString(sa, bigbuf, L_COPY); 01492 01493 sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY); 01494 01495 sarrayAddString(sa, (char *)"{", L_COPY); 01496 sarrayAddString(sa, 01497 (char *)" /RawData currentfile /ASCII85Decode filter def", L_COPY); 01498 sarrayAddString(sa, (char *)" << ", L_COPY); 01499 sarrayAddString(sa, (char *)" /ImageType 1", L_COPY); 01500 sprintf(bigbuf, " /Width %d", w); 01501 sarrayAddString(sa, bigbuf, L_COPY); 01502 sprintf(bigbuf, " /Height %d", h); 01503 sarrayAddString(sa, bigbuf, L_COPY); 01504 sprintf(bigbuf, " /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h); 01505 sarrayAddString(sa, bigbuf, L_COPY); 01506 sarrayAddString(sa, (char *)" /BitsPerComponent 1", L_COPY); 01507 sarrayAddString(sa, (char *)" /Interpolate true", L_COPY); 01508 if (cid->minisblack) 01509 sarrayAddString(sa, (char *)" /Decode [1 0]", L_COPY); 01510 else /* miniswhite; typical for 1 bpp */ 01511 sarrayAddString(sa, (char *)" /Decode [0 1]", L_COPY); 01512 sarrayAddString(sa, (char *)" /DataSource RawData", L_COPY); 01513 sarrayAddString(sa, (char *)" <<", L_COPY); 01514 sarrayAddString(sa, (char *)" /K -1", L_COPY); 01515 sprintf(bigbuf, " /Columns %d", w); 01516 sarrayAddString(sa, bigbuf, L_COPY); 01517 sprintf(bigbuf, " /Rows %d", h); 01518 sarrayAddString(sa, bigbuf, L_COPY); 01519 sarrayAddString(sa, (char *)" >> /CCITTFaxDecode filter", L_COPY); 01520 if (maskflag == TRUE) /* just paint through the fg */ 01521 sarrayAddString(sa, (char *)" >> imagemask", L_COPY); 01522 else /* Paint full image */ 01523 sarrayAddString(sa, (char *)" >> image", L_COPY); 01524 sarrayAddString(sa, (char *)" RawData flushfile", L_COPY); 01525 if (endpage == TRUE) 01526 sarrayAddString(sa, (char *)" showpage", L_COPY); 01527 sarrayAddString(sa, (char *)"}", L_COPY); 01528 01529 sarrayAddString(sa, (char *)"%%BeginData:", L_COPY); 01530 sarrayAddString(sa, (char *)"exec", L_COPY); 01531 01532 /* Insert the ascii85 ccittg4 data; this is now owned by sa */ 01533 sarrayAddString(sa, cid->data85, L_INSERT); 01534 01535 /* Concat the trailing data */ 01536 sarrayAddString(sa, (char *)"%%EndData", L_COPY); 01537 sarrayAddString(sa, (char *)"end", L_COPY); 01538 sarrayAddString(sa, (char *)"restore", L_COPY); 01539 01540 outstr = sarrayToString(sa, 1); 01541 sarrayDestroy(&sa); 01542 cid->data85 = NULL; /* it has been transferred and destroyed */ 01543 return outstr; 01544 } 01545 01546 01547 /*! 01548 * pixGenerateG4Data() 01549 * 01550 * Input: pixs (1 bpp) 01551 * ascii85flag (0 for gzipped; 1 for ascii85-encoded gzipped) 01552 * Return: cid (g4 compressed image data), or null on error 01553 * 01554 * Notes: 01555 * (1) Set ascii85flag: 01556 * - 0 for binary data (not permitted in PostScript) 01557 * - 1 for ascii85 (5 for 4) encoded binary data 01558 */ 01559 L_COMPRESSED_DATA * 01560 pixGenerateG4Data(PIX *pixs, 01561 l_int32 ascii85flag) 01562 { 01563 char *tname; 01564 L_COMPRESSED_DATA *cid; 01565 01566 PROCNAME("pixGenerateG4Data"); 01567 01568 if (!pixs) 01569 return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not defined", 01570 procName, NULL); 01571 if (pixGetDepth(pixs) != 1) 01572 return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not 1 bpp", 01573 procName, NULL); 01574 01575 /* Compress to a temp tiff g4 file */ 01576 tname = genTempFilename("/tmp", "temp.tif", 1, 1); 01577 pixWrite(tname, pixs, IFF_TIFF_G4); 01578 01579 cid = l_generateG4Data(tname, ascii85flag); 01580 FREE(tname); 01581 return cid; 01582 } 01583 01584 01585 /*! 01586 * l_generateG4Data() 01587 * 01588 * Input: fname (of g4 compressed file) 01589 * ascii85flag (0 for g4 compressed; 1 for ascii85-encoded g4) 01590 * Return: cid (g4 compressed image data), or null on error 01591 * 01592 * Notes: 01593 * (1) Set ascii85flag: 01594 * - 0 for binary data (not permitted in PostScript) 01595 * - 1 for ascii85 (5 for 4) encoded binary data 01596 */ 01597 L_COMPRESSED_DATA * 01598 l_generateG4Data(const char *fname, 01599 l_int32 ascii85flag) 01600 { 01601 l_uint8 *datacomp = NULL; /* g4 compressed raster data */ 01602 char *data85 = NULL; /* ascii85 encoded g4 compressed data */ 01603 l_int32 w, h, xres, yres; 01604 l_int32 minisblack; /* TRUE or FALSE */ 01605 l_int32 nbytes85; 01606 size_t nbytescomp; 01607 L_COMPRESSED_DATA *cid; 01608 FILE *fp; 01609 01610 PROCNAME("l_generateG4Data"); 01611 01612 if (!fname) 01613 return (L_COMPRESSED_DATA *)ERROR_PTR("fname not defined", 01614 procName, NULL); 01615 01616 /* The returned ccitt g4 data in memory is the block of 01617 * bytes in the tiff file, starting after 8 bytes and 01618 * ending before the directory. */ 01619 if (extractG4DataFromFile(fname, &datacomp, &nbytescomp, 01620 &w, &h, &minisblack)) { 01621 return (L_COMPRESSED_DATA *)ERROR_PTR("datacomp not extracted", 01622 procName, NULL); 01623 } 01624 01625 /* Read the resolution */ 01626 if ((fp = fopenReadStream(fname)) == NULL) 01627 return (L_COMPRESSED_DATA *)ERROR_PTR("stream not opened", 01628 procName, NULL); 01629 getTiffResolution(fp, &xres, &yres); 01630 fclose(fp); 01631 01632 /* Optionally, encode the compressed data */ 01633 if (ascii85flag == 1) { 01634 data85 = encodeAscii85(datacomp, nbytescomp, &nbytes85); 01635 FREE(datacomp); 01636 if (!data85) 01637 return (L_COMPRESSED_DATA *)ERROR_PTR("data85 not made", 01638 procName, NULL); 01639 else 01640 data85[nbytes85 - 1] = '\0'; /* remove the newline */ 01641 } 01642 01643 cid = (L_COMPRESSED_DATA *)CALLOC(1, sizeof(L_COMPRESSED_DATA)); 01644 if (!cid) 01645 return (L_COMPRESSED_DATA *)ERROR_PTR("cid not made", procName, NULL); 01646 if (ascii85flag == 0) 01647 cid->datacomp = datacomp; 01648 else { /* ascii85 */ 01649 cid->data85 = data85; 01650 cid->nbytes85 = nbytes85; 01651 } 01652 cid->type = L_G4_ENCODE; 01653 cid->nbytescomp = nbytescomp; 01654 cid->w = w; 01655 cid->h = h; 01656 cid->minisblack = minisblack; 01657 cid->res = xres; 01658 return cid; 01659 } 01660 01661 01662 /*-------------------------------------------------------------* 01663 * For tiff multipage files * 01664 *-------------------------------------------------------------*/ 01665 /*! 01666 * convertTiffMultipageToPS() 01667 * 01668 * Input: filein (input tiff multipage file) 01669 * fileout (output ps file) 01670 * tempfile (<optional> for temporary g4 tiffs; 01671 * use NULL for default) 01672 * factor (for filling 8.5 x 11 inch page; 01673 * use 0.0 for DEFAULT_FILL_FRACTION) 01674 * Return: 0 if OK, 1 on error 01675 * 01676 * Notes: 01677 * (1) This converts a multipage tiff file of binary page images 01678 * into a ccitt g4 compressed PS file. 01679 * (2) If the images are generated from a standard resolution fax, 01680 * the vertical resolution is doubled to give a normal-looking 01681 * aspect ratio. 01682 */ 01683 l_int32 01684 convertTiffMultipageToPS(const char *filein, 01685 const char *fileout, 01686 const char *tempfile, 01687 l_float32 fillfract) 01688 { 01689 const char tempdefault[] = "/tmp/junk_temp_g4.tif"; 01690 const char *tempname; 01691 l_int32 i, npages, w, h, istiff; 01692 l_float32 scale; 01693 PIX *pix, *pixs; 01694 FILE *fp; 01695 01696 PROCNAME("convertTiffMultipageToPS"); 01697 01698 if (!filein) 01699 return ERROR_INT("filein not defined", procName, 1); 01700 if (!fileout) 01701 return ERROR_INT("fileout not defined", procName, 1); 01702 01703 if ((fp = fopenReadStream(filein)) == NULL) 01704 return ERROR_INT("file not found", procName, 1); 01705 istiff = fileFormatIsTiff(fp); 01706 if (!istiff) { 01707 fclose(fp); 01708 return ERROR_INT("file not tiff format", procName, 1); 01709 } 01710 tiffGetCount(fp, &npages); 01711 fclose(fp); 01712 01713 if (tempfile) 01714 tempname = tempfile; 01715 else 01716 tempname = tempdefault; 01717 01718 if (fillfract == 0.0) 01719 fillfract = DEFAULT_FILL_FRACTION; 01720 01721 for (i = 0; i < npages; i++) { 01722 if ((pix = pixReadTiff(filein, i)) == NULL) 01723 return ERROR_INT("pix not made", procName, 1); 01724 01725 w = pixGetWidth(pix); 01726 h = pixGetHeight(pix); 01727 if (w == 1728 && h < w) /* it's a std res fax */ 01728 pixs = pixScale(pix, 1.0, 2.0); 01729 else 01730 pixs = pixClone(pix); 01731 01732 pixWrite(tempname, pixs, IFF_TIFF_G4); 01733 scale = L_MIN(fillfract * 2550 / w, fillfract * 3300 / h); 01734 if (i == 0) 01735 convertG4ToPS(tempname, fileout, "w", 0, 0, 300, scale, 01736 i + 1, FALSE, TRUE); 01737 else 01738 convertG4ToPS(tempname, fileout, "a", 0, 0, 300, scale, 01739 i + 1, FALSE, TRUE); 01740 pixDestroy(&pix); 01741 pixDestroy(&pixs); 01742 } 01743 01744 return 0; 01745 } 01746 01747 01748 /*---------------------------------------------------------------------* 01749 * For flate (gzip) compressed images (e.g., png) * 01750 *---------------------------------------------------------------------*/ 01751 /*! 01752 * convertFlateToPSEmbed() 01753 * 01754 * Input: filein (input file -- any format) 01755 * fileout (output ps file) 01756 * Return: 0 if OK, 1 on error 01757 * 01758 * Notes: 01759 * (1) This function takes any image file as input and generates a 01760 * flate-compressed, ascii85 encoded PS file, with a bounding box. 01761 * (2) The bounding box is required when a program such as TeX 01762 * (through epsf) places and rescales the image. 01763 * (3) The bounding box is sized for fitting the image to an 01764 * 8.5 x 11.0 inch page. 01765 */ 01766 l_int32 01767 convertFlateToPSEmbed(const char *filein, 01768 const char *fileout) 01769 { 01770 char *outstr; 01771 l_int32 w, h, nbytes; 01772 l_float32 xpt, ypt, wpt, hpt; 01773 L_COMPRESSED_DATA *cid; 01774 01775 PROCNAME("convertFlateToPSEmbed"); 01776 01777 if (!filein) 01778 return ERROR_INT("filein not defined", procName, 1); 01779 if (!fileout) 01780 return ERROR_INT("fileout not defined", procName, 1); 01781 01782 if ((cid = l_generateFlateData(filein, 1)) == NULL) 01783 return ERROR_INT("flate data not made", procName, 1); 01784 w = cid->w; 01785 h = cid->h; 01786 01787 /* Scale for 20 pt boundary and otherwise full filling 01788 * in one direction on 8.5 x 11 inch device */ 01789 xpt = 20.0; 01790 ypt = 20.0; 01791 if (w * 11.0 > h * 8.5) { 01792 wpt = 572.0; /* 612 - 2 * 20 */ 01793 hpt = wpt * (l_float32)h / (l_float32)w; 01794 } 01795 else { 01796 hpt = 752.0; /* 792 - 2 * 20 */ 01797 wpt = hpt * (l_float32)w / (l_float32)h; 01798 } 01799 01800 /* Generate the PS. 01801 * The bounding box information should be inserted (default). */ 01802 outstr = generateFlatePS(filein, cid, xpt, ypt, wpt, hpt, 1, 1); 01803 if (!outstr) 01804 return ERROR_INT("outstr not made", procName, 1); 01805 nbytes = strlen(outstr); 01806 01807 if (l_binaryWrite(fileout, "w", outstr, nbytes)) 01808 return ERROR_INT("ps string not written to file", procName, 1); 01809 FREE(outstr); 01810 compressed_dataDestroy(&cid); 01811 return 0; 01812 } 01813 01814 01815 /*! 01816 * convertFlateToPS() 01817 * 01818 * Input: filein (input file -- any format) 01819 * fileout (output ps file) 01820 * operation ("w" for write; "a" for append) 01821 * x, y (location of LL corner of image, in pixels, relative 01822 * to the PostScript origin (0,0) at the LL corner 01823 * of the page) 01824 * res (resolution of the input image, in ppi; use 0 for default) 01825 * scale (scaling by printer; use 0.0 or 1.0 for no scaling) 01826 * pageno (page number; must start with 1; you can use 0 01827 * if there is only one page.) 01828 * endpage (boolean: use TRUE if this is the last image to be 01829 * added to the page; FALSE otherwise) 01830 * Return: 0 if OK, 1 on error 01831 * 01832 * Notes: 01833 * (1) This outputs level 3 PS as flate compressed (overlaid 01834 * with ascii85 encoding). 01835 * (2) An output file can contain multiple pages, each with 01836 * multiple images. The arguments to convertFlateToPS() 01837 * allow you to control placement of png images on multiple 01838 * pages within a PostScript file. 01839 * (3) For the first image written to a file, use "w", which 01840 * opens for write and clears the file. For all subsequent 01841 * images written to that file, use "a". 01842 * (4) The (x, y) parameters give the LL corner of the image 01843 * relative to the LL corner of the page. They are in 01844 * units of pixels if scale = 1.0. If you use (e.g.) 01845 * scale = 2.0, the image is placed at (2x, 2y) on the page, 01846 * and the image dimensions are also doubled. 01847 * (5) Display vs printed resolution: 01848 * * If your display is 75 ppi and your image was created 01849 * at a resolution of 300 ppi, you can get the image 01850 * to print at the same size as it appears on your display 01851 * by either setting scale = 4.0 or by setting res = 75. 01852 * Both tell the printer to make a 4x enlarged image. 01853 * * If your image is generated at 150 ppi and you use scale = 1, 01854 * it will be rendered such that 150 pixels correspond 01855 * to 72 pts (1 inch on the printer). This function does 01856 * the conversion from pixels (with or without scaling) to 01857 * pts, which are the units that the printer uses. 01858 * * The printer will choose its own resolution to use 01859 * in rendering the image, which will not affect the size 01860 * of the rendered image. That is because the output 01861 * PostScript file describes the geometry in terms of pts, 01862 * which are defined to be 1/72 inch. The printer will 01863 * only see the size of the image in pts, through the 01864 * scale and translate parameters and the affine 01865 * transform (the ImageMatrix) of the image. 01866 * (6) To render multiple images on the same page, set 01867 * endpage = FALSE for each image until you get to the 01868 * last, for which you set endpage = TRUE. This causes the 01869 * "showpage" command to be invoked. Showpage outputs 01870 * the entire page and clears the raster buffer for the 01871 * next page to be added. Without a "showpage", 01872 * subsequent images from the next page will overlay those 01873 * previously put down. 01874 * (7) For multiple pages, increment the page number, starting 01875 * with page 1. This allows PostScript (and PDF) to build 01876 * a page directory, which viewers use for navigation. 01877 */ 01878 l_int32 01879 convertFlateToPS(const char *filein, 01880 const char *fileout, 01881 const char *operation, 01882 l_int32 x, 01883 l_int32 y, 01884 l_int32 res, 01885 l_float32 scale, 01886 l_int32 pageno, 01887 l_int32 endpage) 01888 { 01889 char *outstr; 01890 l_int32 nbytes; 01891 01892 PROCNAME("convertFlateToPS"); 01893 01894 if (!filein) 01895 return ERROR_INT("filein not defined", procName, 1); 01896 if (!fileout) 01897 return ERROR_INT("fileout not defined", procName, 1); 01898 if (strcmp(operation, "w") && strcmp(operation, "a")) 01899 return ERROR_INT("operation must be \"w\" or \"a\"", procName, 1); 01900 01901 if (convertFlateToPSString(filein, &outstr, &nbytes, x, y, res, scale, 01902 pageno, endpage)) 01903 return ERROR_INT("ps string not made", procName, 1); 01904 01905 if (l_binaryWrite(fileout, operation, outstr, nbytes)) 01906 return ERROR_INT("ps string not written to file", procName, 1); 01907 01908 FREE(outstr); 01909 return 0; 01910 } 01911 01912 01913 /*! 01914 * convertFlateToPSString() 01915 * 01916 * Generates level 3 PS string in flate compressed format. 01917 * 01918 * Input: filein (input image file) 01919 * &poutstr (<return> PS string) 01920 * &nbytes (<return> number of bytes in PS string) 01921 * x, y (location of LL corner of image, in pixels, relative 01922 * to the PostScript origin (0,0) at the LL corner 01923 * of the page) 01924 * res (resolution of the input image, in ppi; use 0 for default) 01925 * scale (scaling by printer; use 0.0 or 1.0 for no scaling) 01926 * pageno (page number; must start with 1; you can use 0 01927 * if there is only one page.) 01928 * endpage (boolean: use TRUE if this is the last image to be 01929 * added to the page; FALSE otherwise) 01930 * Return: 0 if OK, 1 on error 01931 * 01932 * Notes: 01933 * (1) The returned PS character array is a null-terminated 01934 * ascii string. All the raster data is ascii85 encoded, so 01935 * there are no null bytes embedded in it. 01936 * (2) The raster encoding is made with gzip, the same as that 01937 * in a png file that is compressed without prediction. 01938 * The raster data itself is 25% larger than that in the 01939 * binary form, due to the ascii85 encoding. 01940 * 01941 * Usage: See convertFlateToPS() 01942 */ 01943 l_int32 01944 convertFlateToPSString(const char *filein, 01945 char **poutstr, 01946 l_int32 *pnbytes, 01947 l_int32 x, 01948 l_int32 y, 01949 l_int32 res, 01950 l_float32 scale, 01951 l_int32 pageno, 01952 l_int32 endpage) 01953 { 01954 char *outstr; 01955 l_float32 xpt, ypt, wpt, hpt; 01956 L_COMPRESSED_DATA *cid; 01957 01958 PROCNAME("convertFlateToPSString"); 01959 01960 if (!poutstr) 01961 return ERROR_INT("&outstr not defined", procName, 1); 01962 if (!pnbytes) 01963 return ERROR_INT("&nbytes not defined", procName, 1); 01964 *pnbytes = 0; 01965 *poutstr = NULL; 01966 if (!filein) 01967 return ERROR_INT("filein not defined", procName, 1); 01968 01969 if ((cid = l_generateFlateData(filein, 1)) == NULL) 01970 return ERROR_INT("flate data not made", procName, 1); 01971 01972 /* Get scaled location in pts. Guess the input scan resolution 01973 * based on the input parameter @res, the resolution data in 01974 * the pix, and the size of the image. */ 01975 if (scale == 0.0) 01976 scale = 1.0; 01977 if (res <= 0) { 01978 if (cid->res > 0) 01979 res = cid->res; 01980 else 01981 res = DEFAULT_INPUT_RES; 01982 } 01983 xpt = scale * x * 72. / res; 01984 ypt = scale * y * 72. / res; 01985 wpt = scale * cid->w * 72. / res; 01986 hpt = scale * cid->h * 72. / res; 01987 01988 if (pageno == 0) 01989 pageno = 1; 01990 01991 #if DEBUG_FLATE 01992 fprintf(stderr, "w = %d, h = %d, bps = %d, spp = %d\n", 01993 cid->w, cid->h, cid->bps, cid->spp); 01994 fprintf(stderr, "uncomp bytes = %d, comp bytes = %d, nbytes85 = %d\n", 01995 cid->nbytes, cid->nbytescomp, cid->nbytes85); 01996 fprintf(stderr, "xpt = %7.2f, ypt = %7.2f, wpt = %7.2f, hpt = %7.2f\n", 01997 xpt, ypt, wpt, hpt); 01998 #endif /* DEBUG_FLATE */ 01999 02000 /* Generate the PS */ 02001 outstr = generateFlatePS(filein, cid, xpt, ypt, wpt, hpt, pageno, endpage); 02002 if (!outstr) 02003 return ERROR_INT("outstr not made", procName, 1); 02004 *poutstr = outstr; 02005 *pnbytes = strlen(outstr); 02006 compressed_dataDestroy(&cid); 02007 return 0; 02008 } 02009 02010 02011 /*! 02012 * generateFlatePS() 02013 * 02014 * Input: filein (<optional> input filename; can be null) 02015 * cid (flate compressed image data) 02016 * xpt, ypt (location of LL corner of image, in pts, relative 02017 * to the PostScript origin (0,0) at the LL corner 02018 * of the page) 02019 * wpt, hpt (rendered image size in pts) 02020 * pageno (page number; must start with 1; you can use 0 02021 * if there is only one page) 02022 * endpage (boolean: use TRUE if this is the last image to be 02023 * added to the page; FALSE otherwise) 02024 * Return: PS string, or null on error 02025 */ 02026 char * 02027 generateFlatePS(const char *filein, 02028 L_COMPRESSED_DATA *cid, 02029 l_float32 xpt, 02030 l_float32 ypt, 02031 l_float32 wpt, 02032 l_float32 hpt, 02033 l_int32 pageno, 02034 l_int32 endpage) 02035 { 02036 l_int32 w, h, bps, spp; 02037 char *outstr; 02038 char bigbuf[L_BUF_SIZE]; 02039 SARRAY *sa; 02040 02041 PROCNAME("generateFlatePS"); 02042 02043 if (!cid) 02044 return (char *)ERROR_PTR("flate data not defined", procName, NULL); 02045 w = cid->w; 02046 h = cid->h; 02047 bps = cid->bps; 02048 spp = cid->spp; 02049 02050 if ((sa = sarrayCreate(50)) == NULL) 02051 return (char *)ERROR_PTR("sa not made", procName, NULL); 02052 02053 sarrayAddString(sa, (char *)"%!PS-Adobe-3.0 EPSF-3.0", L_COPY); 02054 sarrayAddString(sa, (char *)"%%Creator: leptonica", L_COPY); 02055 if (filein) { 02056 sprintf(bigbuf, "%%%%Title: %s", filein); 02057 sarrayAddString(sa, bigbuf, L_COPY); 02058 } 02059 sarrayAddString(sa, (char *)"%%DocumentData: Clean7Bit", L_COPY); 02060 02061 if (var_PS_WRITE_BOUNDING_BOX == 1) { 02062 sprintf(bigbuf, 02063 "%%%%BoundingBox: %7.2f %7.2f %7.2f %7.2f", 02064 xpt, ypt, xpt + wpt, ypt + hpt); 02065 sarrayAddString(sa, bigbuf, L_COPY); 02066 } 02067 02068 sarrayAddString(sa, (char *)"%%LanguageLevel: 3", L_COPY); 02069 sarrayAddString(sa, (char *)"%%EndComments", L_COPY); 02070 sprintf(bigbuf, "%%%%Page: %d %d", pageno, pageno); 02071 sarrayAddString(sa, bigbuf, L_COPY); 02072 02073 sarrayAddString(sa, (char *)"save", L_COPY); 02074 sprintf(bigbuf, 02075 "%7.2f %7.2f translate %%set image origin in pts", xpt, ypt); 02076 sarrayAddString(sa, bigbuf, L_COPY); 02077 02078 sprintf(bigbuf, 02079 "%7.2f %7.2f scale %%set image size in pts", wpt, hpt); 02080 sarrayAddString(sa, bigbuf, L_COPY); 02081 02082 /* If there is a colormap, add the data; it is now owned by sa */ 02083 if (cid->cmapdata85) { 02084 sprintf(bigbuf, 02085 "[ /Indexed /DeviceRGB %d %%set colormap type/size", 02086 cid->ncolors - 1); 02087 sarrayAddString(sa, bigbuf, L_COPY); 02088 sarrayAddString(sa, (char *)" <~", L_COPY); 02089 sarrayAddString(sa, cid->cmapdata85, L_INSERT); 02090 sarrayAddString(sa, (char *)" ] setcolorspace", L_COPY); 02091 } 02092 else if (spp == 1) 02093 sarrayAddString(sa, (char *)"/DeviceGray setcolorspace", L_COPY); 02094 else /* spp == 3 */ 02095 sarrayAddString(sa, (char *)"/DeviceRGB setcolorspace", L_COPY); 02096 02097 sarrayAddString(sa, 02098 (char *)"/RawData currentfile /ASCII85Decode filter def", L_COPY); 02099 sarrayAddString(sa, 02100 (char *)"/Data RawData << >> /FlateDecode filter def", L_COPY); 02101 02102 sarrayAddString(sa, (char *)"{ << /ImageType 1", L_COPY); 02103 sprintf(bigbuf, " /Width %d", w); 02104 sarrayAddString(sa, bigbuf, L_COPY); 02105 sprintf(bigbuf, " /Height %d", h); 02106 sarrayAddString(sa, bigbuf, L_COPY); 02107 sprintf(bigbuf, " /BitsPerComponent %d", bps); 02108 sarrayAddString(sa, bigbuf, L_COPY); 02109 sprintf(bigbuf, " /ImageMatrix [ %d 0 0 %d 0 %d ]", w, -h, h); 02110 sarrayAddString(sa, bigbuf, L_COPY); 02111 02112 if (cid->cmapdata85) 02113 sarrayAddString(sa, (char *)" /Decode [0 255]", L_COPY); 02114 else if (spp == 1) { 02115 if (bps == 1) /* miniswhite photometry */ 02116 sarrayAddString(sa, (char *)" /Decode [1 0]", L_COPY); 02117 else /* bps > 1 */ 02118 sarrayAddString(sa, (char *)" /Decode [0 1]", L_COPY); 02119 } 02120 else /* spp == 3 */ 02121 sarrayAddString(sa, (char *)" /Decode [0 1 0 1 0 1]", L_COPY); 02122 02123 sarrayAddString(sa, (char *)" /DataSource Data", L_COPY); 02124 sarrayAddString(sa, (char *)" >> image", L_COPY); 02125 sarrayAddString(sa, (char *)" Data closefile", L_COPY); 02126 sarrayAddString(sa, (char *)" RawData flushfile", L_COPY); 02127 if (endpage == TRUE) 02128 sarrayAddString(sa, (char *)" showpage", L_COPY); 02129 sarrayAddString(sa, (char *)" restore", L_COPY); 02130 sarrayAddString(sa, (char *)"} exec", L_COPY); 02131 02132 /* Insert the ascii85 gzipped data; this is now owned by sa */ 02133 sarrayAddString(sa, cid->data85, L_INSERT); 02134 02135 /* Generate and return the output string */ 02136 outstr = sarrayToString(sa, 1); 02137 sarrayDestroy(&sa); 02138 cid->cmapdata85 = NULL; /* it has been transferred to sa and destroyed */ 02139 cid->data85 = NULL; /* it has been transferred to sa and destroyed */ 02140 return outstr; 02141 } 02142 02143 02144 /*! 02145 * l_generateFlateData() 02146 * 02147 * Input: fname 02148 * ascii85flag (0 for gzipped; 1 for ascii85-encoded gzipped) 02149 * Return: cid (flate compressed image data), or null on error 02150 * 02151 * Notes: 02152 * (1) The input image is converted to one of these 4 types: 02153 * - 1 bpp 02154 * - 8 bpp, no colormap 02155 * - 8 bpp, colormap 02156 * - 32 bpp rgb 02157 * (2) Set ascii85flag: 02158 * - 0 for binary data (not permitted in PostScript) 02159 * - 1 for ascii85 (5 for 4) encoded binary data 02160 */ 02161 L_COMPRESSED_DATA * 02162 l_generateFlateData(const char *fname, 02163 l_int32 ascii85flag) 02164 { 02165 L_COMPRESSED_DATA *cid; 02166 PIX *pixs; 02167 02168 PROCNAME("l_generateFlateData"); 02169 02170 if (!fname) 02171 return (L_COMPRESSED_DATA *)ERROR_PTR("fname not defined", 02172 procName, NULL); 02173 02174 if ((pixs = pixRead(fname)) == NULL) 02175 return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not made", 02176 procName, NULL); 02177 cid = pixGenerateFlateData(pixs, ascii85flag); 02178 pixDestroy(&pixs); 02179 return cid; 02180 } 02181 02182 02183 /*! 02184 * pixGenerateFlateData() 02185 * 02186 * Input: pixs 02187 * ascii85flag (0 for gzipped; 1 for ascii85-encoded gzipped) 02188 * Return: cid (flate compressed image data), or null on error 02189 */ 02190 L_COMPRESSED_DATA * 02191 pixGenerateFlateData(PIX *pixs, 02192 l_int32 ascii85flag) 02193 { 02194 l_uint8 *data = NULL; /* uncompressed raster data in required format */ 02195 l_uint8 *datacomp = NULL; /* gzipped raster data */ 02196 char *data85 = NULL; /* ascii85 encoded gzipped raster data */ 02197 l_uint8 *cmapdata = NULL; /* uncompressed colormap */ 02198 char *cmapdata85 = NULL; /* ascii85 encoded uncompressed colormap */ 02199 char *cmapdatahex = NULL; /* hex ascii uncompressed colormap */ 02200 l_int32 ncolors; /* in colormap; not used if cmapdata85 is null */ 02201 l_int32 bps; /* bits/sample: usually 8 */ 02202 l_int32 spp; /* samples/pixel: 1-grayscale); 3-rgb; 4-rgba */ 02203 l_int32 w, h, d, cmapflag; 02204 l_int32 ncmapbytes, ncmapbytes85, nbytes85; 02205 size_t nbytes, nbytescomp; 02206 L_COMPRESSED_DATA *cid; 02207 PIX *pixt; 02208 PIXCMAP *cmap; 02209 02210 PROCNAME("pixGenerateFlateData"); 02211 02212 if (!pixs) 02213 return (L_COMPRESSED_DATA *)ERROR_PTR("pixs not defined", 02214 procName, NULL); 02215 02216 /* Convert the image to one of these 4 types: 02217 * 1 bpp 02218 * 8 bpp, no colormap 02219 * 8 bpp, colormap 02220 * 32 bpp rgb */ 02221 pixGetDimensions(pixs, &w, &h, &d); 02222 cmap = pixGetColormap(pixs); 02223 cmapflag = (cmap) ? 1 : 0; 02224 if (d == 2 || d == 4 || d == 16) { 02225 pixt = pixConvertTo8(pixs, cmapflag); 02226 cmap = pixGetColormap(pixt); 02227 d = pixGetDepth(pixt); 02228 } 02229 else 02230 pixt = pixClone(pixs); 02231 spp = (d == 32) ? 3 : 1; 02232 bps = (d == 32) ? 8 : d; 02233 02234 /* Extract and encode the colormap data as both ascii85 and hexascii */ 02235 ncolors = 0; 02236 if (cmap) { 02237 pixcmapSerializeToMemory(cmap, 3, &ncolors, &cmapdata, &ncmapbytes); 02238 if (!cmapdata) 02239 return (L_COMPRESSED_DATA *)ERROR_PTR("cmapdata not made", 02240 procName, NULL); 02241 02242 cmapdata85 = encodeAscii85(cmapdata, ncmapbytes, &ncmapbytes85); 02243 cmapdatahex = pixcmapConvertToHex(cmapdata, ncmapbytes, ncolors); 02244 FREE(cmapdata); 02245 } 02246 02247 /* Extract and compress the raster data */ 02248 pixGetRasterData(pixt, &data, &nbytes); 02249 pixDestroy(&pixt); 02250 datacomp = zlibCompress(data, nbytes, &nbytescomp); 02251 if (!datacomp) { 02252 if (cmapdata85) FREE(cmapdata85); 02253 if (cmapdatahex) FREE(cmapdatahex); 02254 return (L_COMPRESSED_DATA *)ERROR_PTR("datacomp not made", 02255 procName, NULL); 02256 } 02257 FREE(data); 02258 02259 /* Optionally, encode the compressed data */ 02260 if (ascii85flag == 1) { 02261 data85 = encodeAscii85(datacomp, nbytescomp, &nbytes85); 02262 FREE(datacomp); 02263 if (!data85) { 02264 FREE(cmapdata85); 02265 return (L_COMPRESSED_DATA *)ERROR_PTR("data85 not made", 02266 procName, NULL); 02267 } 02268 else 02269 data85[nbytes85 - 1] = '\0'; /* remove the newline */ 02270 } 02271 02272 cid = (L_COMPRESSED_DATA *)CALLOC(1, sizeof(L_COMPRESSED_DATA)); 02273 if (!cid) 02274 return (L_COMPRESSED_DATA *)ERROR_PTR("cid not made", procName, NULL); 02275 if (ascii85flag == 0) 02276 cid->datacomp = datacomp; 02277 else { /* ascii85 */ 02278 cid->data85 = data85; 02279 cid->nbytes85 = nbytes85; 02280 } 02281 cid->type = L_FLATE_ENCODE; 02282 cid->cmapdatahex = cmapdatahex; 02283 cid->cmapdata85 = cmapdata85; 02284 cid->nbytescomp = nbytescomp; 02285 cid->ncolors = ncolors; 02286 cid->w = w; 02287 cid->h = h; 02288 cid->bps = bps; 02289 cid->spp = spp; 02290 cid->res = pixGetXRes(pixs); 02291 cid->nbytes = nbytes; /* only for debugging */ 02292 return cid; 02293 } 02294 02295 02296 /*---------------------------------------------------------------------* 02297 * Write to memory * 02298 *---------------------------------------------------------------------*/ 02299 /*! 02300 * pixWriteMemPS() 02301 * 02302 * Input: &data (<return> data of tiff compressed image) 02303 * &size (<return> size of returned data) 02304 * pix 02305 * box (<optional>) 02306 * res (can use 0 for default of 300 ppi) 02307 * scale (to prevent scaling, use either 1.0 or 0.0) 02308 * Return: 0 if OK, 1 on error 02309 * 02310 * Notes: 02311 * (1) See pixWriteStringPS() for usage. 02312 * (2) This is just a wrapper for pixWriteStringPS(), which 02313 * writes uncompressed image data to memory. 02314 */ 02315 l_int32 02316 pixWriteMemPS(l_uint8 **pdata, 02317 size_t *psize, 02318 PIX *pix, 02319 BOX *box, 02320 l_int32 res, 02321 l_float32 scale) 02322 { 02323 PROCNAME("pixWriteMemPS"); 02324 02325 if (!pdata) 02326 return ERROR_INT("&data not defined", procName, 1 ); 02327 if (!psize) 02328 return ERROR_INT("&size not defined", procName, 1 ); 02329 if (!pix) 02330 return ERROR_INT("&pix not defined", procName, 1 ); 02331 02332 *pdata = (l_uint8 *)pixWriteStringPS(pix, box, res, scale); 02333 *psize = strlen((char *)(*pdata)); 02334 return 0; 02335 } 02336 02337 02338 /*-------------------------------------------------------------* 02339 * Converting resolution * 02340 *-------------------------------------------------------------*/ 02341 /*! 02342 * getResLetterPage() 02343 * 02344 * Input: w (image width, pixels) 02345 * h (image height, pixels) 02346 * fillfract (fraction in linear dimension of full page, not 02347 * to be exceeded; use 0 for default) 02348 * Return: 0 if OK, 1 on error 02349 */ 02350 l_int32 02351 getResLetterPage(l_int32 w, 02352 l_int32 h, 02353 l_float32 fillfract) 02354 { 02355 l_int32 resw, resh, res; 02356 02357 if (fillfract == 0.0) 02358 fillfract = DEFAULT_FILL_FRACTION; 02359 resw = (l_int32)((w * 72.) / (LETTER_WIDTH * fillfract)); 02360 resh = (l_int32)((h * 72.) / (LETTER_HEIGHT * fillfract)); 02361 res = L_MAX(resw, resh); 02362 return res; 02363 } 02364 02365 02366 /*! 02367 * getResA4Page() 02368 * 02369 * Input: w (image width, pixels) 02370 * h (image height, pixels) 02371 * fillfract (fraction in linear dimension of full page, not 02372 * to be exceeded; use 0 for default) 02373 * Return: 0 if OK, 1 on error 02374 */ 02375 l_int32 02376 getResA4Page(l_int32 w, 02377 l_int32 h, 02378 l_float32 fillfract) 02379 { 02380 l_int32 resw, resh, res; 02381 02382 if (fillfract == 0.0) 02383 fillfract = DEFAULT_FILL_FRACTION; 02384 resw = (l_int32)((w * 72.) / (A4_WIDTH * fillfract)); 02385 resh = (l_int32)((h * 72.) / (A4_HEIGHT * fillfract)); 02386 res = L_MAX(resw, resh); 02387 return res; 02388 } 02389 02390 02391 02392 /*-------------------------------------------------------------* 02393 * Utility for encoding and decoding data with ascii85 * 02394 *-------------------------------------------------------------*/ 02395 /*! 02396 * encodeAscii85() 02397 * 02398 * Input: inarray (input data) 02399 * insize (number of bytes in input array) 02400 * &outsize (<return> number of bytes in output char array) 02401 * Return: chara (with 64 characters + \n in each line) 02402 * 02403 * Notes: 02404 * (1) Ghostscript has a stack break if the last line of 02405 * data only has a '>', so we avoid the problem by 02406 * always putting '~>' on the last line. 02407 */ 02408 char * 02409 encodeAscii85(l_uint8 *inarray, 02410 l_int32 insize, 02411 l_int32 *poutsize) 02412 { 02413 char *chara; 02414 char *outbuf; 02415 l_int32 maxsize, i, index, outindex, linecount, nbout, eof; 02416 02417 PROCNAME("encodeAscii85"); 02418 02419 if (!inarray) 02420 return (char *)ERROR_PTR("inarray not defined", procName, NULL); 02421 02422 /* Accumulate results in char array */ 02423 maxsize = (l_int32)(80. + (insize * 5. / 4.) * 02424 (1. + 2. / MAX_85_LINE_COUNT)); 02425 if ((chara = (char *)CALLOC(maxsize, sizeof(char))) == NULL) 02426 return (char *)ERROR_PTR("chara not made", procName, NULL); 02427 02428 if ((outbuf = (char *)CALLOC(8, sizeof(char))) == NULL) 02429 return (char *)ERROR_PTR("outbuf not made", procName, NULL); 02430 02431 linecount = 0; 02432 index = 0; 02433 outindex = 0; 02434 while (1) { 02435 eof = convertChunkToAscii85(inarray, insize, &index, outbuf, &nbout); 02436 for (i = 0; i < nbout; i++) { 02437 chara[outindex++] = outbuf[i]; 02438 linecount++; 02439 if (linecount >= MAX_85_LINE_COUNT) { 02440 chara[outindex++] = '\n'; 02441 linecount = 0; 02442 } 02443 } 02444 if (eof == TRUE) { 02445 if (linecount != 0) 02446 chara[outindex++] = '\n'; 02447 chara[outindex++] = '~'; 02448 chara[outindex++] = '>'; 02449 chara[outindex++] = '\n'; 02450 break; 02451 } 02452 } 02453 02454 FREE(outbuf); 02455 *poutsize = outindex; 02456 return chara; 02457 } 02458 02459 02460 /*! 02461 * convertChunkToAscii85() 02462 * 02463 * Input: inarray (input data) 02464 * insize (number of bytes in input array) 02465 * &index (use and <return> -- ptr) 02466 * outbuf (holds 8 ascii chars; we use no more than 7) 02467 * &nbsout (<return> number of bytes written to outbuf) 02468 * Return: boolean for eof (0 if more data, 1 if end of file) 02469 * 02470 * Notes: 02471 * (1) Attempts to read 4 bytes and write 5. 02472 * (2) Writes 1 byte if the value is 0. 02473 */ 02474 static l_int32 02475 convertChunkToAscii85(l_uint8 *inarray, 02476 l_int32 insize, 02477 l_int32 *pindex, 02478 char *outbuf, 02479 l_int32 *pnbout) 02480 { 02481 l_uint8 inbyte; 02482 l_uint32 inword, val; 02483 l_int32 eof, index, nread, nbout, i; 02484 02485 eof = FALSE; 02486 index = *pindex; 02487 nread = L_MIN(4, (insize - index)); 02488 if (insize == index + nread) 02489 eof = TRUE; 02490 *pindex += nread; /* save new index */ 02491 02492 /* Read input data and save in l_uint32 */ 02493 inword = 0; 02494 for (i = 0; i < nread; i++) { 02495 inbyte = inarray[index + i]; 02496 inword += inbyte << (8 * (3 - i)); 02497 } 02498 02499 #if 0 02500 fprintf(stderr, "index = %d, nread = %d\n", index, nread); 02501 fprintf(stderr, "inword = %x\n", inword); 02502 fprintf(stderr, "eof = %d\n", eof); 02503 #endif 02504 02505 /* Special case: output 1 byte only */ 02506 if (inword == 0) { 02507 outbuf[0] = 'z'; 02508 nbout = 1; 02509 } 02510 else { /* output nread + 1 bytes */ 02511 for (i = 4; i >= 4 - nread; i--) { 02512 val = inword / power85[i]; 02513 outbuf[4 - i] = (l_uint8)(val + '!'); 02514 inword -= val * power85[i]; 02515 } 02516 nbout = nread + 1; 02517 } 02518 *pnbout = nbout; 02519 02520 return eof; 02521 } 02522 02523 02524 /*! 02525 * decodeAscii85() 02526 * 02527 * Input: inarray (ascii85 input data) 02528 * insize (number of bytes in input array) 02529 * &outsize (<return> number of bytes in output l_uint8 array) 02530 * Return: outarray (binary) 02531 * 02532 * Notes: 02533 * (1) We assume the data is properly encoded, so we do not check 02534 * for invalid characters or the final '>' character. 02535 * (2) We permit whitespace to be added to the encoding in an 02536 * arbitrary way. 02537 */ 02538 l_uint8 * 02539 decodeAscii85(char *ina, 02540 l_int32 insize, 02541 l_int32 *poutsize) 02542 { 02543 char inc; 02544 char *pin; 02545 l_uint8 val; 02546 l_uint8 *outa; 02547 l_int32 maxsize, ocount, bytecount, index; 02548 l_uint32 oword; 02549 02550 PROCNAME("decodeAscii85"); 02551 02552 if (!ina) 02553 return (l_uint8 *)ERROR_PTR("ina not defined", procName, NULL); 02554 02555 /* Accumulate results in outa */ 02556 maxsize = (l_int32)(80. + (insize * 4. / 5.)); /* plenty big */ 02557 if ((outa = (l_uint8 *)CALLOC(maxsize, sizeof(l_uint8))) == NULL) 02558 return (l_uint8 *)ERROR_PTR("outa not made", procName, NULL); 02559 02560 pin = ina; 02561 ocount = 0; /* byte index into outa */ 02562 oword = 0; 02563 for (index = 0, bytecount = 0; index < insize; index++, pin++) { 02564 inc = *pin; 02565 02566 if (inc == ' ' || inc == '\t' || inc == '\n' || 02567 inc == '\f' || inc == '\r' || inc == '\v') /* ignore white space */ 02568 continue; 02569 02570 val = inc - '!'; 02571 if (val < 85) { 02572 oword = oword * 85 + val; 02573 if (bytecount < 4) 02574 bytecount++; 02575 else { /* we have all 5 input chars for the oword */ 02576 outa[ocount] = (oword >> 24) & 0xff; 02577 outa[ocount + 1] = (oword >> 16) & 0xff; 02578 outa[ocount + 2] = (oword >> 8) & 0xff; 02579 outa[ocount + 3] = oword & 0xff; 02580 ocount += 4; 02581 bytecount = 0; 02582 oword = 0; 02583 } 02584 } 02585 else if (inc == 'z' && bytecount == 0) { 02586 outa[ocount] = 0; 02587 outa[ocount + 1] = 0; 02588 outa[ocount + 2] = 0; 02589 outa[ocount + 3] = 0; 02590 ocount += 4; 02591 } 02592 else if (inc == '~') { /* end of data */ 02593 fprintf(stderr, " %d extra bytes output\n", bytecount - 1); 02594 switch (bytecount) { 02595 case 0: /* normal eof */ 02596 case 1: /* error */ 02597 break; 02598 case 2: /* 1 extra byte */ 02599 oword = oword * (85 * 85 * 85) + 0xffffff; 02600 outa[ocount] = (oword >> 24) & 0xff; 02601 break; 02602 case 3: /* 2 extra bytes */ 02603 oword = oword * (85 * 85) + 0xffff; 02604 outa[ocount] = (oword >> 24) & 0xff; 02605 outa[ocount + 1] = (oword >> 16) & 0xff; 02606 break; 02607 case 4: /* 3 extra bytes */ 02608 oword = oword * 85 + 0xff; 02609 outa[ocount] = (oword >> 24) & 0xff; 02610 outa[ocount + 1] = (oword >> 16) & 0xff; 02611 outa[ocount + 2] = (oword >> 8) & 0xff; 02612 break; 02613 } 02614 if (bytecount > 1) 02615 ocount += (bytecount - 1); 02616 break; 02617 } 02618 } 02619 *poutsize = ocount; 02620 02621 return outa; 02622 } 02623 02624 02625 /*-------------------------------------------------------------* 02626 * Setting flag for writing bounding box hint * 02627 *-------------------------------------------------------------*/ 02628 void 02629 l_psWriteBoundingBox(l_int32 flag) 02630 { 02631 var_PS_WRITE_BOUNDING_BOX = flag; 02632 } 02633 02634 02635 /* --------------------------------------------*/ 02636 #endif /* USE_PSIO */ 02637 /* --------------------------------------------*/ 02638