/* * pixWriteMixedToPS() * * Input: pixb (<optionall> 1 bpp "mask"; typically for text) * pixc (<optional> 8 or 32 bpp image regions) * scale (relative scale factor for rendering pixb * relative to pixc; typ. 4.0) * pageno (page number in set; use 1 for new output file) * fileout (output ps file) * Return: 0 if OK, 1 on error * * Notes: * (1) This low level function generates the PS string for a mixed * text/image page, and adds it to an existing file if * %pageno > 1. * (2) The two images (pixb and pixc) are typically generated at the * resolution that they will be rendered in the PS file. * (3) pixb is the text component. In the PostScript world, we think of * it as a mask through which we paint black. * (4) pixc is the (typically halftone) image component. It is * white in the rest of the page. To minimize the size of the * PS file, it should be rendered at a resolution that is at * least equal to its actual resolution. * (5) %scale gives the ratio of resolution of pixb to pixc. * Typical resolutions are: 600 ppi for pixb, 150 ppi for pixc; * so %scale = 4.0. If one of the images is not defined, * the value of %scale is ignored. * (6) We write pixc with DCT compression (jpeg). This is followed * by painting the text as black through the mask pixb. If * pixc doesn't exist (alltext), we write the text with the * PS "image" operator instead of the "imagemask" operator, * because ghostscript's ps2pdf is flaky when the latter is used. * (7) The actual output resolution is determined by fitting the * result to a letter-size (8.5 x 11 inch) page. */ l_int32 pixWriteMixedToPS(PIX *pixb, PIX *pixc, l_float32 scale, l_int32 pageno, const char *fileout) { char *tname; const char *op; l_int32 resb, resc, endpage, maskop, ret; PROCNAME("pixWriteMixedToPS"); if (!pixb && !pixc) return ERROR_INT("pixb and pixc both undefined", procName, 1); if (!fileout) return ERROR_INT("fileout not defined", procName, 1); /* Compute the resolution that fills a letter-size page. */ if (!pixc) { resb = getResLetterPage(pixGetWidth(pixb), pixGetHeight(pixb), 0); } else { resc = getResLetterPage(pixGetWidth(pixc), pixGetHeight(pixc), 0); if (pixb) resb = (l_int32)(scale * resc); } /* Write the jpeg image first */ if (pixc) { tname = l_makeTempFilename(NULL); pixWrite(tname, pixc, IFF_JFIF_JPEG); endpage = (pixb) ? FALSE : TRUE; op = (pageno <= 1) ? "w" : "a"; ret = convertJpegToPS(tname, fileout, op, 0, 0, resc, 1.0, pageno, endpage); lept_rmfile(tname); LEPT_FREE(tname); if (ret) return ERROR_INT("jpeg data not written", procName, 1); } /* Write the binary data, either directly or, if there is * a jpeg image on the page, through the mask. */ if (pixb) { tname = l_makeTempFilename(NULL); pixWrite(tname, pixb, IFF_TIFF_G4); op = (pageno <= 1 && !pixc) ? "w" : "a"; maskop = (pixc) ? 1 : 0; ret = convertG4ToPS(tname, fileout, op, 0, 0, resb, 1.0, pageno, maskop, 1); lept_rmfile(tname); LEPT_FREE(tname); if (ret) return ERROR_INT("tiff data not written", procName, 1); } return 0; }
/*! * \brief pixWriteMemGif() * * \param[out] pdata data of gif compressed image * \param[out] psize size of returned data * \param[in] pix * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) See comments in pixReadMemGif() * (2) For Giflib version >= 5.1, this uses the EGifOpen() buffer * interface. No temp files are required. * </pre> */ l_int32 pixWriteMemGif(l_uint8 **pdata, size_t *psize, PIX *pix) { #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 int giferr; l_int32 result; GifFileType *gif; L_BBUFFER *buffer; #else char *fname; #endif /* 5.1 and beyond */ PROCNAME("pixWriteMemGif"); if (!pdata) return ERROR_INT("&data not defined", procName, 1 ); *pdata = NULL; if (!psize) return ERROR_INT("&size not defined", procName, 1 ); *psize = 0; if (!pix) return ERROR_INT("&pix not defined", procName, 1 ); #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 if((buffer = bbufferCreate(NULL, 0)) == NULL) { return ERROR_INT("failed to create buffer", procName, 1); } if ((gif = EGifOpen((void*)buffer, gifWriteFunc, NULL)) == NULL) { bbufferDestroy(&buffer); return ERROR_INT("failed to create GIF image handle", procName, 1); } result = pixToGif(pix, gif); EGifCloseFile(gif, &giferr); if(result == 0) { *pdata = bbufferDestroyAndSaveData(&buffer, psize); } else { bbufferDestroy(&buffer); } return result; #else L_INFO("writing to a temp file, not directly to memory\n", procName); /* Write to a temp file */ fname = l_makeTempFilename(NULL); pixWrite(fname, pix, IFF_GIF); /* Read back into memory */ *pdata = l_binaryRead(fname, psize); lept_rmfile(fname); LEPT_FREE(fname); return 0; #endif }
/*! * \brief pixReadMemGif() * * \param[in] data const; gif-encoded * \param[in] size of data * \return pix, or NULL on error * * <pre> * Notes: * * For Giflib version >= 5.1, this uses the DGifOpen() buffer * interface. No temp files are required. * * For Giflib version < 5.1: * (1) Write the gif compressed data to file and read it back. * Note: we can't use the GNU runtime extension fmemopen() * because libgif doesn't have a file stream interface. * (2) This should be relatively safe from a sophisticated attack, * because we use mkstemp (or its Windows equivalent) to generate * a filename and link the file. It would be nice to go further * and do this: * l_int32 fd = mkstemp(template); * FILE *fp = fdopen(fd, "w+b"); * fwrite(data, 1, size, fp); * rewind(fp); * Pix *pix = pixReadStreamGif(fp); * but this can't be done with gif files becuase of the way * that libgif handles the file descriptors: fp is in a * bad state after writing. * </pre> */ PIX * pixReadMemGif(const l_uint8 *cdata, size_t size) { #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 GifFileType *gif; GifReadBuffer buffer; #else char *fname; PIX *pix; #endif /* 5.1 and beyond */ PROCNAME("pixReadMemGif"); if (!cdata) return (PIX *)ERROR_PTR("cdata not defined", procName, NULL); #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 buffer.cdata = cdata; buffer.size = size; buffer.pos = 0; if ((gif = DGifOpen((void*)&buffer, gifReadFunc, NULL)) == NULL) return (PIX *)ERROR_PTR("could not open gif stream from memory", procName, NULL); return gifToPix(gif); #else L_INFO("using a temp file; not reading from memory\n", procName); /* Write to a temp file */ fname = l_makeTempFilename(NULL); l_binaryWrite(fname, "w", (l_uint8 *)cdata, size); /* Read back from the file */ pix = pixRead(fname); lept_rmfile(fname); LEPT_FREE(fname); if (!pix) L_ERROR("pix not read\n", procName); return pix; #endif /* 5.1 and beyond */ }
int main(int argc, char **argv) { l_int32 i, n, w, h; BOXA *boxa; NUMA *naindex, *naw, *nah, *naw_med, *nah_med; PIX *pixs, *pixt; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Generate arrays of word widths and heights */ pixs = pixRead("feyn.tif"); pixGetWordBoxesInTextlines(pixs, 1, 6, 6, 500, 50, &boxa, &naindex); n = boxaGetCount(boxa); naw = numaCreate(0); nah = numaCreate(0); for (i = 0; i < n; i++) { boxaGetBoxGeometry(boxa, i, NULL, NULL, &w, &h); numaAddNumber(naw, w); numaAddNumber(nah, h); } boxaDestroy(&boxa); numaDestroy(&naindex); /* Make the rank bin arrays of median values, with 10 bins */ lept_rmfile("/tmp/lept/regout/w_10bin.png"); /* remove existing ones */ lept_rmfile("/tmp/lept/regout/h_10bin.png"); lept_rmfile("/tmp/lept/regout/w_30bin.png"); lept_rmfile("/tmp/lept/regout/h_30bin.png"); numaGetRankBinValues(naw, 10, NULL, &naw_med); numaGetRankBinValues(nah, 10, NULL, &nah_med); gplotSimple1(naw_med, GPLOT_PNG, "/tmp/lept/regout/w_10bin", "width vs rank bins (10)"); gplotSimple1(nah_med, GPLOT_PNG, "/tmp/lept/regout/h_10bin", "height vs rank bins (10)"); numaDestroy(&naw_med); numaDestroy(&nah_med); /* Make the rank bin arrays of median values, with 30 bins */ numaGetRankBinValues(naw, 30, NULL, &naw_med); numaGetRankBinValues(nah, 30, NULL, &nah_med); gplotSimple1(naw_med, GPLOT_PNG, "/tmp/lept/regout/w_30bin", "width vs rank bins (30)"); gplotSimple1(nah_med, GPLOT_PNG, "/tmp/lept/regout/h_30bin", "height vs rank bins (30)"); numaDestroy(&naw_med); numaDestroy(&nah_med); /* Save as golden files, or check against them */ regTestCheckFile(rp, "/tmp/lept/regout/w_10bin.png"); /* 0 */ regTestCheckFile(rp, "/tmp/lept/regout/h_10bin.png"); /* 1 */ regTestCheckFile(rp, "/tmp/lept/regout/w_30bin.png"); /* 2 */ regTestCheckFile(rp, "/tmp/lept/regout/h_30bin.png"); /* 3 */ /* Display results for debugging */ pixt = pixRead("/tmp/lept/regout/w_10bin.png"); pixDisplayWithTitle(pixt, 0, 0, NULL, rp->display); pixDestroy(&pixt); pixt = pixRead("/tmp/lept/regout/h_10bin.png"); pixDisplayWithTitle(pixt, 650, 0, NULL, rp->display); pixDestroy(&pixt); pixt = pixRead("/tmp/lept/regout/w_30bin.png"); pixDisplayWithTitle(pixt, 0, 550, NULL, rp->display); pixDestroy(&pixt); pixt = pixRead("/tmp/lept/regout/h_30bin.png"); pixDisplayWithTitle(pixt, 650, 550, NULL, rp->display); pixDestroy(&pixt); pixDestroy(&pixs); numaDestroy(&naw); numaDestroy(&nah); return regTestCleanup(rp); }
int main(int argc, char **argv) { l_int32 i, n; l_float32 pi, angle, val; BOX *box; BOXA *boxa, *boxa1, *boxa2; NUMA *na1, *na2; PIX *pix, *pix1, *pix2; PIXA *pixa1, *pixa2, *pixa3, *pixa4; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; lept_rmfile("/tmp/regout/insert3.ba"); lept_rmfile("/tmp/regout/insert4.ba"); lept_rmfile("/tmp/regout/insert6.pa"); lept_rmfile("/tmp/regout/insert7.pa"); lept_rmfile("/tmp/regout/insert9.pa"); lept_rmfile("/tmp/regout/insert10.pa"); /* ----------------- Test numa operations -------------------- */ pi = 3.1415926535; na1 = numaCreate(500); for (i = 0; i < 500; i++) { angle = 0.02293 * i * pi; val = (l_float32)sin(angle); numaAddNumber(na1, val); } numaWrite("/tmp/regout/insert0.na", na1); na2 = numaCopy(na1); n = numaGetCount(na2); for (i = 0; i < n; i++) { numaGetFValue(na2, i, &val); numaRemoveNumber(na2, i); numaInsertNumber(na2, i, val); } numaWrite("/tmp/regout/insert1.na", na2); regTestCheckFile(rp, "/tmp/regout/insert0.na"); /* 0 */ regTestCheckFile(rp, "/tmp/regout/insert1.na"); /* 1 */ regTestCompareFiles(rp, 0, 1); /* 2 */ numaDestroy(&na1); numaDestroy(&na2); /* ----------------- Test boxa operations -------------------- */ pix1 = pixRead("feyn.tif"); box = boxCreate(1138, 1666, 1070, 380); pix2 = pixClipRectangle(pix1, box, NULL); boxDestroy(&box); boxa1 = pixConnComp(pix2, NULL, 8); boxaWrite("/tmp/regout/insert3.ba", boxa1); boxa2 = boxaCopy(boxa1, L_COPY); n = boxaGetCount(boxa2); for (i = 0; i < n; i++) { boxaRemoveBoxAndSave(boxa2, i, &box); boxaInsertBox(boxa2, i, box); } boxaWrite("/tmp/regout/insert4.ba", boxa2); regTestCheckFile(rp, "/tmp/regout/insert3.ba"); /* 3 */ regTestCheckFile(rp, "/tmp/regout/insert4.ba"); /* 4 */ regTestCompareFiles(rp, 3, 4); /* 5 */ pixDestroy(&pix1); pixDestroy(&pix2); boxaDestroy(&boxa1); boxaDestroy(&boxa2); /* ----------------- Test pixa operations -------------------- */ pix1 = pixRead("feyn.tif"); box = boxCreate(1138, 1666, 1070, 380); pix2 = pixClipRectangle(pix1, box, NULL); boxDestroy(&box); boxa = pixConnComp(pix2, &pixa1, 8); boxaDestroy(&boxa); pixaWrite("/tmp/regout/insert6.pa", pixa1); regTestCheckFile(rp, "/tmp/regout/insert6.pa"); /* 6 */ pixDestroy(&pix1); pixDestroy(&pix2); /* Remove and insert each one */ pixa2 = pixaCopy(pixa1, L_COPY); n = pixaGetCount(pixa2); for (i = 0; i < n; i++) { pixaRemovePixAndSave(pixa2, i, &pix, &box); pixaInsertPix(pixa2, i, pix, box); } pixaWrite("/tmp/regout/insert7.pa", pixa2); regTestCheckFile(rp, "/tmp/regout/insert7.pa"); /* 7 */ regTestCompareFiles(rp, 6, 7); /* 8 */ /* Move the last to the beginning; do it n times */ pixa3 = pixaCopy(pixa2, L_COPY); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa3, n - 1, L_CLONE); box = pixaGetBox(pixa3, n - 1, L_CLONE); pixaInsertPix(pixa3, 0, pix, box); pixaRemovePix(pixa3, n); } pixaWrite("/tmp/regout/insert9.pa", pixa3); regTestCheckFile(rp, "/tmp/regout/insert9.pa"); /* 9 */ /* Move the first one to the end; do it n times */ pixa4 = pixaCopy(pixa3, L_COPY); for (i = 0; i < n; i++) { pix = pixaGetPix(pixa4, 0, L_CLONE); box = pixaGetBox(pixa4, 0, L_CLONE); pixaInsertPix(pixa4, n, pix, box); /* make sure insert works at end */ pixaRemovePix(pixa4, 0); } pixaWrite("/tmp/regout/insert10.pa", pixa4); regTestCheckFile(rp, "/tmp/regout/insert10.pa"); /* 10 */ regTestCompareFiles(rp, 9, 10); /* 11 */ pixaDestroy(&pixa1); pixaDestroy(&pixa2); pixaDestroy(&pixa3); pixaDestroy(&pixa4); return regTestCleanup(rp); }
/* * pixaWriteCompressedToPS() * * Input: pixa (any set of images) * fileout (output ps file) * res (of input image) * level (compression: 2 or 3) * Return: 0 if OK, 1 on error * * Notes: * (1) This generates a PS file of multiple page images, all * with bounding boxes. * (2) It compresses to: * cmap + level2: jpeg * cmap + level3: flate * 1 bpp: tiffg4 * 2 or 4 bpp + level2: jpeg * 2 or 4 bpp + level3: flate * 8 bpp: jpeg * 16 bpp: flate * 32 bpp: jpeg * (3) To generate a pdf, use: ps2pdf <infile.ps> <outfile.pdf> */ l_int32 pixaWriteCompressedToPS(PIXA *pixa, const char *fileout, l_int32 res, l_int32 level) { char *tname; l_int32 i, n, firstfile, index, writeout, d; PIX *pix, *pixt; PIXCMAP *cmap; PROCNAME("pixaWriteCompressedToPS"); if (!pixa) return ERROR_INT("pixa not defined", procName, 1); if (!fileout) return ERROR_INT("fileout not defined", procName, 1); if (level != 2 && level != 3) { L_ERROR("only levels 2 and 3 permitted; using level 2\n", procName); level = 2; } n = pixaGetCount(pixa); firstfile = TRUE; index = 0; tname = l_makeTempFilename(NULL); for (i = 0; i < n; i++) { writeout = TRUE; pix = pixaGetPix(pixa, i, L_CLONE); d = pixGetDepth(pix); cmap = pixGetColormap(pix); if (d == 1) { pixWrite(tname, pix, IFF_TIFF_G4); } else if (cmap) { if (level == 2) { pixt = pixConvertForPSWrap(pix); pixWrite(tname, pixt, IFF_JFIF_JPEG); pixDestroy(&pixt); } else { /* level == 3 */ pixWrite(tname, pix, IFF_PNG); } } else if (d == 16) { if (level == 2) L_WARNING("d = 16; must write out flate\n", procName); pixWrite(tname, pix, IFF_PNG); } else if (d == 2 || d == 4) { if (level == 2) { pixt = pixConvertTo8(pix, 0); pixWrite(tname, pixt, IFF_JFIF_JPEG); pixDestroy(&pixt); } else { /* level == 3 */ pixWrite(tname, pix, IFF_PNG); } } else if (d == 8 || d == 32) { pixWrite(tname, pix, IFF_JFIF_JPEG); } else { /* shouldn't happen */ L_ERROR("invalid depth: %d\n", procName, d); writeout = FALSE; } pixDestroy(&pix); if (writeout) writeImageCompressedToPSFile(tname, fileout, res, &firstfile, &index); } lept_rmfile(tname); LEPT_FREE(tname); return 0; }
/* * convertToPSEmbed() * * Input: filein (input image file -- any format) * fileout (output ps file) * level (compression: 1 (uncompressed), 2 or 3) * Return: 0 if OK, 1 on error * * Notes: * (1) This is a wrapper function that generates a PS file with * a bounding box, from any input image file. * (2) Do the best job of compression given the specified level. * %level=3 does flate compression on anything that is not * tiffg4 (1 bpp) or jpeg (8 bpp or rgb). * (3) If %level=2 and the file is not tiffg4 or jpeg, it will * first be written to file as jpeg with quality = 75. * This will remove the colormap and cause some degradation * in the image. * (4) The bounding box is required when a program such as TeX * (through epsf) places and rescales the image. It is * sized for fitting the image to an 8.5 x 11.0 inch page. */ l_int32 convertToPSEmbed(const char *filein, const char *fileout, l_int32 level) { char *tname; l_int32 d, format; PIX *pix, *pixs; PROCNAME("convertToPSEmbed"); if (!filein) return ERROR_INT("filein not defined", procName, 1); if (!fileout) return ERROR_INT("fileout not defined", procName, 1); if (level != 1 && level != 2 && level != 3) { L_ERROR("invalid level specified; using level 2\n", procName); level = 2; } if (level == 1) { /* no compression */ pixWritePSEmbed(filein, fileout); return 0; } /* Find the format and write out directly if in jpeg or tiff g4 */ findFileFormat(filein, &format); if (format == IFF_JFIF_JPEG) { convertJpegToPSEmbed(filein, fileout); return 0; } else if (format == IFF_TIFF_G4) { convertG4ToPSEmbed(filein, fileout); return 0; } else if (format == IFF_UNKNOWN) { L_ERROR("format of %s not known\n", procName, filein); return 1; } /* If level 3, flate encode. */ if (level == 3) { convertFlateToPSEmbed(filein, fileout); return 0; } /* OK, it's level 2, so we must convert to jpeg or tiff g4 */ if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("image not read from file", procName, 1); d = pixGetDepth(pixs); if ((d == 2 || d == 4) && !pixGetColormap(pixs)) pix = pixConvertTo8(pixs, 0); else if (d == 16) pix = pixConvert16To8(pixs, 1); else pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pix); tname = l_makeTempFilename(NULL); if (d == 1) { pixWrite(tname, pix, IFF_TIFF_G4); convertG4ToPSEmbed(tname, fileout); } else { pixWrite(tname, pix, IFF_JFIF_JPEG); convertJpegToPSEmbed(tname, fileout); } lept_rmfile(tname); LEPT_FREE(tname); pixDestroy(&pix); pixDestroy(&pixs); return 0; }