/*! * pixAddRGB() * * Input: pixs1, pixs2 (32 bpp RGB, or colormapped) * Return: pixd, or null on error * * Notes: * (1) Clips computation to the minimum size, aligning the UL corners. * (2) Removes any colormap to RGB, and ignores the LSB of each * pixel word (the alpha channel). * (3) Adds each component value, pixelwise, clipping to 255. * (4) This is useful to combine two images where most of the * pixels are essentially black, such as in pixPerceptualDiff(). */ PIX * pixAddRGB(PIX *pixs1, PIX *pixs2) { l_int32 i, j, w, h, d, w2, h2, d2, wplc1, wplc2, wpld; l_int32 rval1, gval1, bval1, rval2, gval2, bval2, rval, gval, bval; l_uint32 *datac1, *datac2, *datad, *linec1, *linec2, *lined; PIX *pixc1, *pixc2, *pixd; PROCNAME("pixAddRGB"); if (!pixs1) return (PIX *)ERROR_PTR("pixs1 not defined", procName, NULL); if (!pixs2) return (PIX *)ERROR_PTR("pixs2 not defined", procName, NULL); pixGetDimensions(pixs1, &w, &h, &d); pixGetDimensions(pixs2, &w2, &h2, &d2); if (!pixGetColormap(pixs1) && d != 32) return (PIX *)ERROR_PTR("pixs1 not cmapped or rgb", procName, NULL); if (!pixGetColormap(pixs2) && d2 != 32) return (PIX *)ERROR_PTR("pixs2 not cmapped or rgb", procName, NULL); if (pixGetColormap(pixs1)) pixc1 = pixRemoveColormap(pixs1, REMOVE_CMAP_TO_FULL_COLOR); else pixc1 = pixClone(pixs1); if (pixGetColormap(pixs2)) pixc2 = pixRemoveColormap(pixs2, REMOVE_CMAP_TO_FULL_COLOR); else pixc2 = pixClone(pixs2); w = L_MIN(w, w2); h = L_MIN(h, h2); pixd = pixCreate(w, h, 32); pixCopyResolution(pixd, pixs1); datac1 = pixGetData(pixc1); datac2 = pixGetData(pixc2); datad = pixGetData(pixd); wplc1 = pixGetWpl(pixc1); wplc2 = pixGetWpl(pixc2); wpld = pixGetWpl(pixd); for (i = 0; i < h; i++) { linec1 = datac1 + i * wplc1; linec2 = datac2 + i * wplc2; lined = datad + i * wpld; for (j = 0; j < w; j++) { extractRGBValues(linec1[j], &rval1, &gval1, &bval1); extractRGBValues(linec2[j], &rval2, &gval2, &bval2); rval = L_MIN(255, rval1 + rval2); gval = L_MIN(255, gval1 + gval2); bval = L_MIN(255, bval1 + bval2); composeRGBPixel(rval, gval, bval, lined + j); } } pixDestroy(&pixc1); pixDestroy(&pixc2); return pixd; }
/*! * pixProjectivePta() * * Input: pixs (all depths; colormap ok) * ptad (4 pts of final coordinate space) * ptas (4 pts of initial coordinate space) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Brings in either black or white pixels from the boundary * (2) Removes any existing colormap, if necessary, before transforming */ PIX * pixProjectivePta(PIX *pixs, PTA *ptad, PTA *ptas, l_int32 incolor) { l_int32 d; l_uint32 colorval; PIX *pixt1, *pixt2, *pixd; PROCNAME("pixProjectivePta"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!ptas) return (PIX *)ERROR_PTR("ptas not defined", procName, NULL); if (!ptad) return (PIX *)ERROR_PTR("ptad not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); if (ptaGetCount(ptas) != 4) return (PIX *)ERROR_PTR("ptas count not 4", procName, NULL); if (ptaGetCount(ptad) != 4) return (PIX *)ERROR_PTR("ptad count not 4", procName, NULL); if (pixGetDepth(pixs) == 1) return pixProjectiveSampledPta(pixs, ptad, ptas, incolor); /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pixt1); if (d < 8) pixt2 = pixConvertTo8(pixt1, FALSE); else pixt2 = pixClone(pixt1); d = pixGetDepth(pixt2); /* Compute actual color to bring in from edges */ colorval = 0; if (incolor == L_BRING_IN_WHITE) { if (d == 8) colorval = 255; else /* d == 32 */ colorval = 0xffffff00; } if (d == 8) pixd = pixProjectivePtaGray(pixt2, ptad, ptas, colorval); else /* d == 32 */ pixd = pixProjectivePtaColor(pixt2, ptad, ptas, colorval); pixDestroy(&pixt1); pixDestroy(&pixt2); return pixd; }
l_int32 main(int argc, char **argv) { l_uint32 *colors; l_int32 ncolors; PIX *pix1, *pix2, *pix3; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Find the most populated colors */ pix1 = pixRead("fish24.jpg"); pixGetMostPopulatedColors(pix1, 2, 3, 10, &colors, NULL); pix2 = pixDisplayColorArray(colors, 10, 190, 5, 1); pixDisplayWithTitle(pix2, 0, 0, NULL, rp->display); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 0 */ lept_free(colors); pixDestroy(&pix2); /* Do a simple color quantization with sigbits = 2 */ pix2 = pixSimpleColorQuantize(pix1, 2, 3, 10); pixDisplayWithTitle(pix2, 0, 400, NULL, rp->display); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 1 */ pix3 = pixRemoveColormap(pix2, REMOVE_CMAP_TO_FULL_COLOR); regTestComparePix(rp, pix2, pix3); /* 2 */ pixNumColors(pix3, 1, &ncolors); regTestCompareValues(rp, ncolors, 10, 0.0); /* 3 */ pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Do a simple color quantization with sigbits = 3 */ pix1 = pixRead("wyom.jpg"); pixNumColors(pix1, 1, &ncolors); /* >255, so should give 0 */ regTestCompareValues(rp, ncolors, 0, 0.0); /* 4 */ pix2 = pixSimpleColorQuantize(pix1, 3, 3, 20); pixDisplayWithTitle(pix2, 1000, 0, NULL, rp->display); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 5 */ ncolors = pixcmapGetCount(pixGetColormap(pix2)); regTestCompareValues(rp, ncolors, 20, 0.0); /* 6 */ pixDestroy(&pix1); pixDestroy(&pix2); /* Find the number of perceptually significant gray intensities */ pix1 = pixRead("marge.jpg"); pix2 = pixConvertTo8(pix1, 0); pixNumSignificantGrayColors(pix2, 20, 236, 0.0001, 1, &ncolors); regTestCompareValues(rp, ncolors, 219, 0.0); /* 7 */ pixDestroy(&pix1); pixDestroy(&pix2); return regTestCleanup(rp); }
/*! * pixApplyFilter() * * Input: pix (8 or 32 bpp; or 2, 4 or 8 bpp with colormap) * dpix (filter) * outflag (L_CLIP_TO_ZERO, L_TAKE_ABSVAL, * L_THRESH_NEG_TO_BLACK or L_THRESH_NEG_TO_WHITE) * Return: pixd, or null on error * * Notes: * (1) Apply the input filter to pix by multiplying it for the * Fourier transform of pix. The inverse Fourier transform * is then used on the result to return the filtered image. * (2) If pix is 32 bpp RGB, the filter is applied to each color * channel separately. * (3) If colormapped, remove to grayscale. */ PIX * pixApplyFilter(PIX *pixs, DPIX *dpix, l_int32 outflag) { l_int32 w, h, d; PIX *pixt, *pixd, *pixr, *pixrc, *pixg, *pixgc, *pixb, *pixbc; PROCNAME("pixApplyFilter"); if (!pixs && !dpix) return (PIX *)ERROR_PTR("pixs or dpix not defined", procName, NULL); /* Remove colormap if necessary */ pixGetDimensions(pixs, &w, &h, &d); if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pixs)) { L_WARNING("pix has colormap; removing", procName); pixt = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pixt); } else pixt = pixClone(pixs); if (d != 8 && d != 32) { pixDestroy(&pixt); return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL); } if (d == 8) { pixd = pixApplyFilterGray(pixt, dpix, outflag); } else { /* d == 32 */ pixr = pixGetRGBComponent(pixt, COLOR_RED); pixrc = pixApplyFilterGray(pixr, dpix, outflag); pixDestroy(&pixr); pixg = pixGetRGBComponent(pixt, COLOR_GREEN); pixgc = pixApplyFilterGray(pixg, dpix, outflag); pixDestroy(&pixg); pixb = pixGetRGBComponent(pixt, COLOR_BLUE); pixbc = pixApplyFilterGray(pixb, dpix, outflag); pixDestroy(&pixb); pixd = pixCreateRGBImage(pixrc, pixgc, pixbc); pixDestroy(&pixrc); pixDestroy(&pixgc); pixDestroy(&pixbc); } pixDestroy(&pixt); return pixd; }
/*! * pixRotateAM() * * Input: pixs (2, 4, 8 bpp gray or colormapped, or 32 bpp RGB) * angle (radians; clockwise is positive) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Rotates about image center. * (2) A positive angle gives a clockwise rotation. * (3) Brings in either black or white pixels from the boundary. */ PIX * pixRotateAM(PIX *pixs, l_float32 angle, l_int32 incolor) { l_int32 d; l_uint32 fillval; PIX *pixt1, *pixt2, *pixd; PROCNAME("pixRotateAM"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetDepth(pixs) == 1) return (PIX *)ERROR_PTR("pixs is 1 bpp", procName, NULL); if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE) return pixClone(pixs); /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pixt1); if (d < 8) pixt2 = pixConvertTo8(pixt1, FALSE); else pixt2 = pixClone(pixt1); d = pixGetDepth(pixt2); /* Compute actual incoming color */ fillval = 0; if (incolor == L_BRING_IN_WHITE) { if (d == 8) fillval = 255; else /* d == 32 */ fillval = 0xffffff00; } if (d == 8) pixd = pixRotateAMGray(pixt2, angle, fillval); else /* d == 32 */ pixd = pixRotateAMColor(pixt2, angle, fillval); pixDestroy(&pixt1); pixDestroy(&pixt2); return pixd; }
main(int argc, char **argv) { l_int32 max_dist, max_colors, sel_size, final_colors; PIX *pixs, *pixd, *pixt; char *filein, *fileout; static char mainName[] = "colorsegtest"; if (argc != 3 && argc != 7) exit(ERROR_INT( "Syntax: colorsegtest filein fileout" " [max_dist max_colors sel_size final_colors]\n" " Default values are: max_dist = 120\n" " max_colors = 15\n" " sel_size = 4\n" " final_colors = 15\n", mainName, 1)); filein = argv[1]; fileout = argv[2]; if (argc == 3) { /* use default values */ max_dist = MAX_DIST; max_colors = MAX_COLORS; sel_size = SEL_SIZE; final_colors = FINAL_COLORS; } else { /* 6 input args */ max_dist = atoi(argv[3]); max_colors = atoi(argv[4]); sel_size = atoi(argv[5]); final_colors = atoi(argv[6]); } if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); startTimer(); pixt = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); pixd = pixColorSegment(pixt, max_dist, max_colors, sel_size, final_colors); fprintf(stderr, "Time to segment: %7.3f sec\n", stopTimer()); pixWrite(fileout, pixd, IFF_PNG); pixDestroy(&pixs); pixDestroy(&pixd); return 0; }
/*! * pixProjective() * * Input: pixs (all depths; colormap ok) * vc (vector of 8 coefficients for projective transformation) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Brings in either black or white pixels from the boundary * (2) Removes any existing colormap, if necessary, before transforming */ PIX * pixProjective(PIX *pixs, l_float32 *vc, l_int32 incolor) { l_int32 d; l_uint32 colorval; PIX *pixt1, *pixt2, *pixd; PROCNAME("pixProjective"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!vc) return (PIX *)ERROR_PTR("vc not defined", procName, NULL); if (pixGetDepth(pixs) == 1) return pixProjectiveSampled(pixs, vc, incolor); /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pixt1); if (d < 8) pixt2 = pixConvertTo8(pixt1, FALSE); else pixt2 = pixClone(pixt1); d = pixGetDepth(pixt2); /* Compute actual color to bring in from edges */ colorval = 0; if (incolor == L_BRING_IN_WHITE) { if (d == 8) colorval = 255; else /* d == 32 */ colorval = 0xffffff00; } if (d == 8) pixd = pixProjectiveGray(pixt2, vc, colorval); else /* d == 32 */ pixd = pixProjectiveColor(pixt2, vc, colorval); pixDestroy(&pixt1); pixDestroy(&pixt2); return pixd; }
/* Use which == 1 to test alpha blending; which == 2 to test "blending" * by pixel multiplication. This generates a composite of 5 images: * the original, blending over a box at the bottom (2 ways), and * multiplying over a box at the bottom (2 ways). */ static PIX * DoBlendTest(PIX *pix, BOX *box, l_uint32 color, l_float32 gamma, l_int32 minval, l_int32 maxval, l_int32 which) { PIX *pix1, *pix2, *pix3, *pixd; PIXA *pixa; pixa = pixaCreate(5); pix1 = pixRemoveColormap(pix, REMOVE_CMAP_TO_FULL_COLOR); pix2 = pixCopy(NULL, pix1); pixaAddPix(pixa, pix2, L_COPY); if (which == 1) pix3 = pixBlendBackgroundToColor(NULL, pix2, box, color, gamma, minval, maxval); else pix3 = pixMultiplyByColor(NULL, pix2, box, color); pixaAddPix(pixa, pix3, L_INSERT); if (which == 1) pixBlendBackgroundToColor(pix2, pix2, box, color, gamma, minval, maxval); else pixMultiplyByColor(pix2, pix2, box, color); pixaAddPix(pixa, pix2, L_INSERT); pix2 = pixCopy(NULL, pix1); if (which == 1) pix3 = pixBlendBackgroundToColor(NULL, pix2, NULL, color, gamma, minval, maxval); else pix3 = pixMultiplyByColor(NULL, pix2, NULL, color); pixaAddPix(pixa, pix3, L_INSERT); if (which == 1) pixBlendBackgroundToColor(pix2, pix2, NULL, color, gamma, minval, maxval); else pixMultiplyByColor(pix2, pix2, NULL, color); pixaAddPix(pixa, pix2, L_INSERT); pixd = pixaDisplayTiledInRows(pixa, 32, 800, 1.0, 0, 30, 2); pixDestroy(&pix1); pixaDestroy(&pixa); return pixd; }
// NOTE: Opposite to SetImage for raw images, SetImage for Pix clones its // input, so the source pix may be pixDestroyed immediately after. void ImageThresholder::SetImage(const Pix* pix) { image_data_ = NULL; if (pix_ != NULL) pixDestroy(&pix_); Pix* src = const_cast<Pix*>(pix); int depth; pixGetDimensions(src, &image_width_, &image_height_, &depth); // Convert the image as necessary so it is one of binary, plain RGB, or // 8 bit with no colormap. if (depth > 1 && depth < 8) { pix_ = pixConvertTo8(src, false); } else if (pixGetColormap(src)) { pix_ = pixRemoveColormap(src, REMOVE_CMAP_BASED_ON_SRC); } else { pix_ = pixClone(src); } depth = pixGetDepth(pix_); image_bytespp_ = depth / 8; image_bytespl_ = pixGetWpl(pix_) * sizeof(l_uint32); scale_ = 1; estimated_res_ = yres_ = pixGetYRes(src); Init(); }
/*! * \brief pixReadMemBmp() * * \param[in] cdata bmp data * \param[in] size number of bytes of bmp-formatted data * \return pix, or NULL on error */ PIX * pixReadMemBmp(const l_uint8 *cdata, size_t size) { l_uint8 pel[4]; l_uint8 *cmapBuf, *fdata, *data; l_int16 bftype, offset, depth, d; l_int32 width, height, xres, yres, compression, imagebytes; l_int32 cmapbytes, cmapEntries; l_int32 fdatabpl, extrabytes, pixWpl, pixBpl, i, j, k; l_uint32 *line, *pixdata, *pword; l_int64 npixels; BMP_FH *bmpfh; BMP_IH *bmpih; PIX *pix, *pix1; PIXCMAP *cmap; PROCNAME("pixReadMemBmp"); if (!cdata) return (PIX *)ERROR_PTR("cdata not defined", procName, NULL); if (size < sizeof(BMP_FH) + sizeof(BMP_IH)) return (PIX *)ERROR_PTR("bmf size error", procName, NULL); /* Verify this is an uncompressed bmp */ bmpfh = (BMP_FH *)cdata; bftype = convertOnBigEnd16(bmpfh->bfType); if (bftype != BMP_ID) return (PIX *)ERROR_PTR("not bmf format", procName, NULL); bmpih = (BMP_IH *)(cdata + BMP_FHBYTES); if (!bmpih) return (PIX *)ERROR_PTR("bmpih not defined", procName, NULL); compression = convertOnBigEnd32(bmpih->biCompression); if (compression != 0) return (PIX *)ERROR_PTR("cannot read compressed BMP files", procName, NULL); /* Read the rest of the useful header information */ offset = convertOnBigEnd16(bmpfh->bfOffBits); width = convertOnBigEnd32(bmpih->biWidth); height = convertOnBigEnd32(bmpih->biHeight); depth = convertOnBigEnd16(bmpih->biBitCount); imagebytes = convertOnBigEnd32(bmpih->biSizeImage); xres = convertOnBigEnd32(bmpih->biXPelsPerMeter); yres = convertOnBigEnd32(bmpih->biYPelsPerMeter); /* Some sanity checking. We impose limits on the image * dimensions and number of pixels. We make sure the file * is the correct size to hold the amount of uncompressed data * that is specified in the header. The number of colormap * entries is checked: it can be either 0 (no cmap) or some * number between 2 and 256. * Note that the imagebytes for uncompressed images is either * 0 or the size of the file data. (The fact that it can * be 0 is perhaps some legacy glitch). */ if (width < 1) return (PIX *)ERROR_PTR("width < 1", procName, NULL); if (width > L_MAX_ALLOWED_WIDTH) return (PIX *)ERROR_PTR("width too large", procName, NULL); if (height < 1) return (PIX *)ERROR_PTR("height < 1", procName, NULL); if (height > L_MAX_ALLOWED_HEIGHT) return (PIX *)ERROR_PTR("height too large", procName, NULL); npixels = 1LL * width * height; if (npixels > L_MAX_ALLOWED_PIXELS) return (PIX *)ERROR_PTR("npixels too large", procName, NULL); if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && depth != 16 && depth != 24 && depth != 32) return (PIX *)ERROR_PTR("depth not in {1, 2, 4, 8, 16, 24, 32}", procName,NULL); fdatabpl = 4 * ((1LL * width * depth + 31)/32); if (imagebytes != 0 && imagebytes != fdatabpl * height) return (PIX *)ERROR_PTR("invalid imagebytes", procName, NULL); cmapbytes = offset - BMP_FHBYTES - BMP_IHBYTES; cmapEntries = cmapbytes / sizeof(RGBA_QUAD); if (cmapEntries < 0 || cmapEntries == 1) return (PIX *)ERROR_PTR("invalid: cmap size < 0 or 1", procName, NULL); if (cmapEntries > L_MAX_ALLOWED_NUM_COLORS) return (PIX *)ERROR_PTR("invalid cmap: too large", procName,NULL); if (size != 1LL * offset + 1LL * fdatabpl * height) return (PIX *)ERROR_PTR("size incommensurate with image data", procName,NULL); /* Handle the colormap */ cmapBuf = NULL; if (cmapEntries > 0) { if ((cmapBuf = (l_uint8 *)LEPT_CALLOC(cmapEntries, sizeof(RGBA_QUAD))) == NULL) return (PIX *)ERROR_PTR("cmapBuf alloc fail", procName, NULL ); /* Read the colormap entry data from bmp. The RGBA_QUAD colormap * entries are used for both bmp and leptonica colormaps. */ memcpy(cmapBuf, cdata + BMP_FHBYTES + BMP_IHBYTES, sizeof(RGBA_QUAD) * cmapEntries); } /* Make a 32 bpp pix if depth is 24 bpp */ d = (depth == 24) ? 32 : depth; if ((pix = pixCreate(width, height, d)) == NULL) { LEPT_FREE(cmapBuf); return (PIX *)ERROR_PTR( "pix not made", procName, NULL); } pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */ pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */ pixSetInputFormat(pix, IFF_BMP); pixWpl = pixGetWpl(pix); pixBpl = 4 * pixWpl; /* Convert the bmp colormap to a pixcmap */ cmap = NULL; if (cmapEntries > 0) { /* import the colormap to the pix cmap */ cmap = pixcmapCreate(L_MIN(d, 8)); LEPT_FREE(cmap->array); /* remove generated cmap array */ cmap->array = (void *)cmapBuf; /* and replace */ cmap->n = L_MIN(cmapEntries, 256); for (i = 0; i < cmap->n; i++) /* set all colors opaque */ pixcmapSetAlpha (cmap, i, 255); } pixSetColormap(pix, cmap); /* Acquire the image data. Image origin for bmp is at lower right. */ fdata = (l_uint8 *)cdata + offset; /* start of the bmp image data */ pixdata = pixGetData(pix); if (depth != 24) { /* typ. 1 or 8 bpp */ data = (l_uint8 *)pixdata + pixBpl * (height - 1); for (i = 0; i < height; i++) { memcpy(data, fdata, fdatabpl); fdata += fdatabpl; data -= pixBpl; } } else { /* 24 bpp file; 32 bpp pix * Note: for bmp files, pel[0] is blue, pel[1] is green, * and pel[2] is red. This is opposite to the storage * in the pix, which puts the red pixel in the 0 byte, * the green in the 1 byte and the blue in the 2 byte. * Note also that all words are endian flipped after * assignment on L_LITTLE_ENDIAN platforms. * * We can then make these assignments for little endians: * SET_DATA_BYTE(pword, 1, pel[0]); blue * SET_DATA_BYTE(pword, 2, pel[1]); green * SET_DATA_BYTE(pword, 3, pel[2]); red * This looks like: * 3 (R) 2 (G) 1 (B) 0 * |-----------|------------|-----------|-----------| * and after byte flipping: * 3 2 (B) 1 (G) 0 (R) * |-----------|------------|-----------|-----------| * * For big endians we set: * SET_DATA_BYTE(pword, 2, pel[0]); blue * SET_DATA_BYTE(pword, 1, pel[1]); green * SET_DATA_BYTE(pword, 0, pel[2]); red * This looks like: * 0 (R) 1 (G) 2 (B) 3 * |-----------|------------|-----------|-----------| * so in both cases we get the correct assignment in the PIX. * * Can we do a platform-independent assignment? * Yes, set the bytes without using macros: * *((l_uint8 *)pword) = pel[2]; red * *((l_uint8 *)pword + 1) = pel[1]; green * *((l_uint8 *)pword + 2) = pel[0]; blue * For little endians, before flipping, this looks again like: * 3 (R) 2 (G) 1 (B) 0 * |-----------|------------|-----------|-----------| */ extrabytes = fdatabpl - 3 * width; line = pixdata + pixWpl * (height - 1); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pword = line + j; memcpy(&pel, fdata, 3); fdata += 3; *((l_uint8 *)pword + COLOR_RED) = pel[2]; *((l_uint8 *)pword + COLOR_GREEN) = pel[1]; *((l_uint8 *)pword + COLOR_BLUE) = pel[0]; } if (extrabytes) { for (k = 0; k < extrabytes; k++) { memcpy(&pel, fdata, 1); fdata++; } } line -= pixWpl; } } pixEndianByteSwap(pix); /* ---------------------------------------------- * The bmp colormap determines the values of black * and white pixels for binary in the following way: * (a) white = 0 [255], black = 1 [0] * 255, 255, 255, 255, 0, 0, 0, 255 * (b) black = 0 [0], white = 1 [255] * 0, 0, 0, 255, 255, 255, 255, 255 * We have no need for a 1 bpp pix with a colormap! * Note: the alpha component here is 255 (opaque) * ---------------------------------------------- */ if (depth == 1 && cmap) { pix1 = pixRemoveColormap(pix, REMOVE_CMAP_TO_BINARY); pixDestroy(&pix); pix = pix1; /* rename */ } return pix; }
/*! * pixDisplayWithTitle() * * Input: pix (1, 2, 4, 8, 16, 32 bpp) * x, y (location of display frame) * title (<optional> on frame; can be NULL); * dispflag (1 to write, else disabled) * Return: 0 if OK; 1 on error * * Notes: * (1) See notes for pixDisplay(). * (2) This displays the image if dispflag == 1. */ l_int32 pixDisplayWithTitle(PIX *pixs, l_int32 x, l_int32 y, const char *title, l_int32 dispflag) { char *tempname; char buffer[L_BUF_SIZE]; static l_int32 index = 0; /* caution: not .so or thread safe */ l_int32 w, h, d, spp, maxheight, opaque, threeviews, ignore; l_float32 ratw, rath, ratmin; PIX *pix0, *pix1, *pix2; PIXCMAP *cmap; #ifndef _WIN32 l_int32 wt, ht; #else char *pathname; char fullpath[_MAX_PATH]; #endif /* _WIN32 */ PROCNAME("pixDisplayWithTitle"); if (dispflag != 1) return 0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV && var_DISPLAY_PROG != L_DISPLAY_WITH_XLI && var_DISPLAY_PROG != L_DISPLAY_WITH_XV && var_DISPLAY_PROG != L_DISPLAY_WITH_IV && var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) { return ERROR_INT("no program chosen for display", procName, 1); } /* Display with three views if either spp = 4 or if colormapped * and the alpha component is not fully opaque */ opaque = TRUE; if ((cmap = pixGetColormap(pixs)) != NULL) pixcmapIsOpaque(cmap, &opaque); spp = pixGetSpp(pixs); threeviews = (spp == 4 || !opaque) ? TRUE : FALSE; /* If colormapped and not opaque, remove the colormap to RGBA */ if (!opaque) pix0 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA); else pix0 = pixClone(pixs); /* Scale if necessary; this will also remove a colormap */ pixGetDimensions(pix0, &w, &h, &d); maxheight = (threeviews) ? MAX_DISPLAY_HEIGHT / 3 : MAX_DISPLAY_HEIGHT; if (w <= MAX_DISPLAY_WIDTH && h <= maxheight) { if (d == 16) /* take MSB */ pix1 = pixConvert16To8(pix0, 1); else pix1 = pixClone(pix0); } else { ratw = (l_float32)MAX_DISPLAY_WIDTH / (l_float32)w; rath = (l_float32)maxheight / (l_float32)h; ratmin = L_MIN(ratw, rath); if (ratmin < 0.125 && d == 1) pix1 = pixScaleToGray8(pix0); else if (ratmin < 0.25 && d == 1) pix1 = pixScaleToGray4(pix0); else if (ratmin < 0.33 && d == 1) pix1 = pixScaleToGray3(pix0); else if (ratmin < 0.5 && d == 1) pix1 = pixScaleToGray2(pix0); else pix1 = pixScale(pix0, ratmin, ratmin); } pixDestroy(&pix0); if (!pix1) return ERROR_INT("pix1 not made", procName, 1); /* Generate the three views if required */ if (threeviews) pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0); else pix2 = pixClone(pix1); if (index == 0) { lept_rmdir("disp"); lept_mkdir("disp"); } index++; if (pixGetDepth(pix2) < 8 || (w < MAX_SIZE_FOR_PNG && h < MAX_SIZE_FOR_PNG)) { snprintf(buffer, L_BUF_SIZE, "/tmp/disp/write.%03d.png", index); pixWrite(buffer, pix2, IFF_PNG); } else { snprintf(buffer, L_BUF_SIZE, "/tmp/disp/write.%03d.jpg", index); pixWrite(buffer, pix2, IFF_JFIF_JPEG); } tempname = stringNew(buffer); #ifndef _WIN32 /* Unix */ if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) { /* no way to display title */ pixGetDimensions(pix2, &wt, &ht, NULL); snprintf(buffer, L_BUF_SIZE, "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10, x, y, tempname); } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) { if (title) { snprintf(buffer, L_BUF_SIZE, "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &", x, y, title, tempname); } else { snprintf(buffer, L_BUF_SIZE, "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &", x, y, tempname); } } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) { if (title) { snprintf(buffer, L_BUF_SIZE, "xv -quit -geometry +%d+%d -name \"%s\" %s &", x, y, title, tempname); } else { snprintf(buffer, L_BUF_SIZE, "xv -quit -geometry +%d+%d %s &", x, y, tempname); } } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_OPEN) { snprintf(buffer, L_BUF_SIZE, "open %s &", tempname); } ignore = system(buffer); #else /* _WIN32 */ /* Windows: L_DISPLAY_WITH_IV */ pathname = genPathname(tempname, NULL); _fullpath(fullpath, pathname, sizeof(fullpath)); if (title) { snprintf(buffer, L_BUF_SIZE, "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"", fullpath, x, y, title); } else { snprintf(buffer, L_BUF_SIZE, "i_view32.exe \"%s\" /pos=(%d,%d)", fullpath, x, y); } ignore = system(buffer); FREE(pathname); #endif /* _WIN32 */ pixDestroy(&pix1); pixDestroy(&pix2); FREE(tempname); return 0; }
/*! * ioFormatTest() * * Input: filename (input file) * Return: 0 if OK; 1 on error or if the test fails * * Notes: * (1) This writes and reads a set of output files losslessly * in different formats to /tmp/format/, and tests that the * result before and after is unchanged. * (2) This should work properly on input images of any depth, * with and without colormaps. * (3) All supported formats are tested for bmp, png, tiff and * non-ascii pnm. Ascii pnm also works (but who'd ever want * to use it?) We allow 2 bpp bmp, although it's not * supported elsewhere. And we don't support reading * 16 bpp png, although this can be turned on in pngio.c. * (4) This silently skips png or tiff testing if HAVE_LIBPNG * or HAVE_LIBTIFF are 0, respectively. */ l_int32 ioFormatTest(const char *filename) { l_int32 d, equal, problems; PIX *pixs, *pixc, *pix1, *pix2; PIXCMAP *cmap; PROCNAME("ioFormatTest"); if (!filename) return ERROR_INT("filename not defined", procName, 1); if ((pixs = pixRead(filename)) == NULL) return ERROR_INT("pixs not made", procName, 1); lept_mkdir("lept"); /* Note that the reader automatically removes colormaps * from 1 bpp BMP images, but not from 8 bpp BMP images. * Therefore, if our 8 bpp image initially doesn't have a * colormap, we are going to need to remove it from any * pix read from a BMP file. */ pixc = pixClone(pixs); /* laziness */ /* This does not test the alpha layer pixels, because most * formats don't support it. Remove any alpha. */ if (pixGetSpp(pixc) == 4) pixSetSpp(pixc, 3); cmap = pixGetColormap(pixc); /* colormap; can be NULL */ d = pixGetDepth(pixc); problems = FALSE; /* ----------------------- BMP -------------------------- */ /* BMP works for 1, 2, 4, 8 and 32 bpp images. * It always writes colormaps for 1 and 8 bpp, so we must * remove it after readback if the input image doesn't have * a colormap. Although we can write/read 2 bpp BMP, nobody * else can read them! */ if (d == 1 || d == 8) { L_INFO("write/read bmp\n", procName); pixWrite(FILE_BMP, pixc, IFF_BMP); pix1 = pixRead(FILE_BMP); if (!cmap) pix2 = pixRemoveColormap(pix1, REMOVE_CMAP_BASED_ON_SRC); else pix2 = pixClone(pix1); pixEqual(pixc, pix2, &equal); if (!equal) { L_INFO(" **** bad bmp image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); } if (d == 2 || d == 4 || d == 32) { L_INFO("write/read bmp\n", procName); pixWrite(FILE_BMP, pixc, IFF_BMP); pix1 = pixRead(FILE_BMP); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad bmp image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); } /* ----------------------- PNG -------------------------- */ #if HAVE_LIBPNG /* PNG works for all depths, but here, because we strip * 16 --> 8 bpp on reading, we don't test png for 16 bpp. */ if (d != 16) { L_INFO("write/read png\n", procName); pixWrite(FILE_PNG, pixc, IFF_PNG); pix1 = pixRead(FILE_PNG); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad png image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); } #endif /* HAVE_LIBPNG */ /* ----------------------- TIFF -------------------------- */ #if HAVE_LIBTIFF /* TIFF works for 1, 2, 4, 8, 16 and 32 bpp images. * Because 8 bpp tiff always writes 256 entry colormaps, the * colormap sizes may be different for 8 bpp images with * colormap; we are testing if the image content is the same. * Likewise, the 2 and 4 bpp tiff images with colormaps * have colormap sizes 4 and 16, rsp. This test should * work properly on the content, regardless of the number * of color entries in pixc. */ /* tiff uncompressed works for all pixel depths */ L_INFO("write/read uncompressed tiff\n", procName); pixWrite(FILE_TIFF, pixc, IFF_TIFF); pix1 = pixRead(FILE_TIFF); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff uncompressed image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); /* tiff lzw works for all pixel depths */ L_INFO("write/read lzw compressed tiff\n", procName); pixWrite(FILE_LZW, pixc, IFF_TIFF_LZW); pix1 = pixRead(FILE_LZW); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff lzw compressed image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); /* tiff adobe deflate (zip) works for all pixel depths */ L_INFO("write/read zip compressed tiff\n", procName); pixWrite(FILE_ZIP, pixc, IFF_TIFF_ZIP); pix1 = pixRead(FILE_ZIP); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff zip compressed image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); /* tiff g4, g3, rle and packbits work for 1 bpp */ if (d == 1) { L_INFO("write/read g4 compressed tiff\n", procName); pixWrite(FILE_G4, pixc, IFF_TIFF_G4); pix1 = pixRead(FILE_G4); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff g4 image ****\n", procName); problems = TRUE; } pixDestroy(&pix1); L_INFO("write/read g3 compressed tiff\n", procName); pixWrite(FILE_G3, pixc, IFF_TIFF_G3); pix1 = pixRead(FILE_G3); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff g3 image ****\n", procName); problems = TRUE; } pixDestroy(&pix1); L_INFO("write/read rle compressed tiff\n", procName); pixWrite(FILE_RLE, pixc, IFF_TIFF_RLE); pix1 = pixRead(FILE_RLE); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff rle image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); L_INFO("write/read packbits compressed tiff\n", procName); pixWrite(FILE_PB, pixc, IFF_TIFF_PACKBITS); pix1 = pixRead(FILE_PB); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff packbits image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); } #endif /* HAVE_LIBTIFF */ /* ----------------------- PNM -------------------------- */ /* pnm works for 1, 2, 4, 8, 16 and 32 bpp. * pnm doesn't have colormaps, so when we write colormapped * pix out as pnm, the colormap is removed. Thus for the test, * we must remove the colormap from pixc before testing. */ L_INFO("write/read pnm\n", procName); pixWrite(FILE_PNM, pixc, IFF_PNM); pix1 = pixRead(FILE_PNM); if (cmap) pix2 = pixRemoveColormap(pixc, REMOVE_CMAP_BASED_ON_SRC); else pix2 = pixClone(pixc); pixEqual(pix1, pix2, &equal); if (!equal) { L_INFO(" **** bad pnm image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); if (problems == FALSE) L_INFO("All formats read and written OK!\n", procName); pixDestroy(&pixc); pixDestroy(&pixs); return problems; }
main(int argc, char **argv) { l_int32 errorfound, same; PIX *pixs, *pixt1, *pixt2, *pixt3, *pixt4; static char mainName[] = "equal_reg"; if (argc != 1) exit(ERROR_INT(" Syntax: equal_reg", mainName, 1)); errorfound = FALSE; pixs = pixRead(FEYN1); pixWrite("/tmp/junkfeyn.png", pixs, IFF_PNG); pixt1 = pixRead("/tmp/junkfeyn.png"); pixEqual(pixs, pixt1, &same); if (same) L_INFO("equal for feyn1", mainName); else { L_INFO("FAILURE for equal for feyn1", mainName); errorfound = TRUE; } pixDestroy(&pixs); pixDestroy(&pixt1); pixs = pixRead(DREYFUS2); pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); pixWrite("/tmp/junkdrey2-1.png", pixt1, IFF_PNG); pixt2 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); pixWrite("/tmp/junkdrey2-2.png", pixt2, IFF_PNG); pixt3 = pixOctreeQuantNumColors(pixt2, 64, 1); pixWrite("/tmp/junkdrey2-3.png", pixt3, IFF_PNG); pixt4 = pixConvertRGBToColormap(pixt2, 1); pixWrite("/tmp/junkdrey2-4.png", pixt4, IFF_PNG); pixEqual(pixs, pixt1, &same); if (same) L_INFO("equal for pixt1 of dreyfus2", mainName); else { L_INFO("FAILURE for pixt1 of dreyfus2", mainName); errorfound = TRUE; } pixEqual(pixs, pixt2, &same); if (same) L_INFO("equal for pixt2 of dreyfus2", mainName); else { L_INFO("FAILURE for pixt2 of dreyfus2", mainName); errorfound = TRUE; } pixEqual(pixs, pixt3, &same); if (same) L_INFO("equal for pixt3 of dreyfus2", mainName); else { L_INFO("FAILURE for pixt3 of dreyfus2", mainName); errorfound = TRUE; } pixEqual(pixs, pixt4, &same); if (same) L_INFO("equal for pixt4 of dreyfus2", mainName); else { L_INFO("FAILURE for pixt4 of dreyfus2", mainName); errorfound = TRUE; } pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixs = pixRead(DREYFUS4); pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); pixWrite("/tmp/junkdrey4-1.png", pixt1, IFF_PNG); pixt2 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); pixWrite("/tmp/junkdrey4-2.png", pixt2, IFF_PNG); pixt3 = pixOctreeQuantNumColors(pixt2, 256, 1); pixWrite("/tmp/junkdrey4-3.png", pixt3, IFF_PNG); pixt4 = pixConvertRGBToColormap(pixt2, 1); pixWrite("/tmp/junkdrey4-4.png", pixt4, IFF_PNG); pixEqual(pixs, pixt1, &same); if (same) L_INFO("equal for pixt1 of dreyfus4", mainName); else { L_INFO("FAILURE for pixt1 of dreyfus4", mainName); errorfound = TRUE; } pixEqual(pixs, pixt2, &same); if (same) L_INFO("equal for pixt2 of dreyfus4", mainName); else { L_INFO("FAILURE for pixt2 of dreyfus4", mainName); errorfound = TRUE; } pixEqual(pixs, pixt3, &same); if (same) L_INFO("equal for pixt3 of dreyfus4", mainName); else { L_INFO("FAILURE for pixt3 of dreyfus4", mainName); errorfound = TRUE; } pixEqual(pixs, pixt4, &same); if (same) L_INFO("equal for pixt4 of dreyfus4", mainName); else { L_INFO("FAILURE for pixt4 of dreyfus4", mainName); errorfound = TRUE; } pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixs = pixRead(DREYFUS8); pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); pixWrite("/tmp/junkdrey8-1.png", pixt1, IFF_PNG); pixt2 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); pixWrite("/tmp/junkdrey8-2.png", pixt2, IFF_PNG); pixt3 = pixConvertRGBToColormap(pixt2, 1); pixWrite("/tmp/junkdrey8-3.png", pixt3, IFF_PNG); pixEqual(pixs, pixt1, &same); if (same) L_INFO("equal for pixt1 of dreyfus8", mainName); else { L_INFO("FAILURE for pixt1 of dreyfus8", mainName); errorfound = TRUE; } pixEqual(pixs, pixt2, &same); if (same) L_INFO("equal for pixt2 of dreyfus8", mainName); else { L_INFO("FAILURE for pixt2 of dreyfus8", mainName); errorfound = TRUE; } pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixs = pixRead(KAREN8); pixt1 = pixThresholdTo4bpp(pixs, 16, 1); pixWrite("/tmp/junkkar8-1.png", pixt1, IFF_PNG); pixt2 = pixRemoveColormap(pixt1, REMOVE_CMAP_BASED_ON_SRC); pixWrite("/tmp/junkkar8-2.png", pixt2, IFF_PNG); pixt3 = pixRemoveColormap(pixt1, REMOVE_CMAP_TO_FULL_COLOR); pixWrite("/tmp/junkkar8-3.png", pixt3, IFF_PNG); pixt4 = pixConvertRGBToColormap(pixt3, 1); pixEqual(pixt1, pixt2, &same); if (same) L_INFO("equal for pixt2 of karen8", mainName); else { L_INFO("FAILURE for pixt2 of karen8", mainName); errorfound = TRUE; } pixEqual(pixt1, pixt3, &same); if (same) L_INFO("equal for pixt3 of karen8", mainName); else { L_INFO("FAILURE for pixt3 of karen8", mainName); errorfound = TRUE; } pixEqual(pixt1, pixt4, &same); if (same) L_INFO("equal for pixt4 of karen8", mainName); else { L_INFO("FAILURE for pixt4 of karen8", mainName); errorfound = TRUE; } pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixs = pixRead(MARGE32); pixt1 = pixOctreeQuantNumColors(pixs, 32, 0); pixWrite("/tmp/junkmarge8-1.png", pixt1, IFF_PNG); pixt2 = pixRemoveColormap(pixt1, REMOVE_CMAP_TO_FULL_COLOR); pixWrite("/tmp/junkmarge8-2.png", pixt2, IFF_PNG); pixt3 = pixConvertRGBToColormap(pixt2, 1); pixWrite("/tmp/junkmarge8-3.png", pixt3, IFF_PNG); pixt4 = pixOctreeQuantNumColors(pixt2, 64, 0); pixWrite("/tmp/junkmarge8-4.png", pixt4, IFF_PNG); pixEqual(pixt1, pixt2, &same); if (same) L_INFO("equal for pixt2 of marge32", mainName); else { L_INFO("FAILURE for pixt2 of marge32", mainName); errorfound = TRUE; } pixEqual(pixt1, pixt3, &same); if (same) L_INFO("equal for pixt3 of marge32", mainName); else { L_INFO("FAILURE for pixt3 of marge32", mainName); errorfound = TRUE; } pixEqual(pixt1, pixt4, &same); if (same) L_INFO("equal for pixt4 of marge32", mainName); else { L_INFO("FAILURE for pixt4 of marge32", mainName); errorfound = TRUE; } pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); if (errorfound) L_INFO("FAILURE in processing this test", mainName); else L_INFO("SUCCESS in processing this test", mainName); exit(0); }
/*! * pixConvertToFPix() * * Input: pix (1, 2, 4, 8, 16 or 32 bpp) * ncomps (number of components: 3 for RGB, 1 otherwise) * Return: fpix, or null on error * * Notes: * (1) If colormapped, remove to grayscale. * (2) If 32 bpp and @ncomps == 3, this is RGB; convert to luminance. * In all other cases the src image is treated as having a single * component of pixel values. */ FPIX * pixConvertToFPix(PIX *pixs, l_int32 ncomps) { l_int32 w, h, d, i, j, val, wplt, wpld; l_uint32 uval; l_uint32 *datat, *linet; l_float32 *datad, *lined; PIX *pixt; FPIX *fpixd; PROCNAME("pixConvertToFPix"); if (!pixs) return (FPIX *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetColormap(pixs)) pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); else if (pixGetDepth(pixs) == 32 && ncomps == 3) pixt = pixConvertRGBToLuminance(pixs); else pixt = pixClone(pixs); pixGetDimensions(pixt, &w, &h, &d); if ((fpixd = fpixCreate(w, h)) == NULL) return (FPIX *)ERROR_PTR("fpixd not made", procName, NULL); datat = pixGetData(pixt); wplt = pixGetWpl(pixt); datad = fpixGetData(fpixd); wpld = fpixGetWpl(fpixd); for (i = 0; i < h; i++) { linet = datat + i * wplt; lined = datad + i * wpld; if (d == 1) { for (j = 0; j < w; j++) { val = GET_DATA_BIT(linet, j); lined[j] = (l_float32)val; } } else if (d == 2) { for (j = 0; j < w; j++) { val = GET_DATA_DIBIT(linet, j); lined[j] = (l_float32)val; } } else if (d == 4) { for (j = 0; j < w; j++) { val = GET_DATA_QBIT(linet, j); lined[j] = (l_float32)val; } } else if (d == 8) { for (j = 0; j < w; j++) { val = GET_DATA_BYTE(linet, j); lined[j] = (l_float32)val; } } else if (d == 16) { for (j = 0; j < w; j++) { val = GET_DATA_TWO_BYTES(linet, j); lined[j] = (l_float32)val; } } else if (d == 32) { for (j = 0; j < w; j++) { uval = GET_DATA_FOUR_BYTES(linet, j); lined[j] = (l_float32)uval; } } } pixDestroy(&pixt); return fpixd; }
/*! * \brief pixWriteMemWebP() * * \param[out] pencdata webp encoded data of pixs * \param[out] pencsize size of webp encoded data * \param[in] pixs any depth, cmapped OK * \param[in] quality 0 - 100; default ~80 * \param[in] lossless use 1 for lossless; 0 for lossy * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) Lossless and lossy encoding are entirely different in webp. * %quality applies to lossy, and is ignored for lossless. * (2) The input image is converted to RGB if necessary. If spp == 3, * we set the alpha channel to fully opaque (255), and * WebPEncodeRGBA() then removes the alpha chunk when encoding, * setting the internal header field has_alpha to 0. * </pre> */ l_ok pixWriteMemWebP(l_uint8 **pencdata, size_t *pencsize, PIX *pixs, l_int32 quality, l_int32 lossless) { l_int32 w, h, d, wpl, stride; l_uint32 *data; PIX *pix1, *pix2; PROCNAME("pixWriteMemWebP"); if (!pencdata) return ERROR_INT("&encdata not defined", procName, 1); *pencdata = NULL; if (!pencsize) return ERROR_INT("&encsize not defined", procName, 1); *pencsize = 0; if (!pixs) return ERROR_INT("&pixs not defined", procName, 1); if (lossless == 0 && (quality < 0 || quality > 100)) return ERROR_INT("quality not in [0 ... 100]", procName, 1); if ((pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL) return ERROR_INT("failure to remove color map", procName, 1); /* Convert to rgb if not 32 bpp; pix2 must not be a clone of pixs. */ if (pixGetDepth(pix1) != 32) pix2 = pixConvertTo32(pix1); else pix2 = pixCopy(NULL, pix1); pixDestroy(&pix1); pixGetDimensions(pix2, &w, &h, &d); if (w <= 0 || h <= 0 || d != 32) { pixDestroy(&pix2); return ERROR_INT("pix2 not 32 bpp or of 0 size", procName, 1); } /* If spp == 3, need to set alpha layer to opaque (all 1s). */ if (pixGetSpp(pix2) == 3) pixSetComponentArbitrary(pix2, L_ALPHA_CHANNEL, 255); /* The WebP API expects data in RGBA order. The pix stores * in host-dependent order with R as the MSB and A as the LSB. * On little-endian machines, the bytes in the word must * be swapped; e.g., R goes from byte 0 (LSB) to byte 3 (MSB). * No swapping is necessary for big-endians. */ pixEndianByteSwap(pix2); wpl = pixGetWpl(pix2); data = pixGetData(pix2); stride = wpl * 4; if (lossless) { *pencsize = WebPEncodeLosslessRGBA((uint8_t *)data, w, h, stride, pencdata); } else { *pencsize = WebPEncodeRGBA((uint8_t *)data, w, h, stride, quality, pencdata); } pixDestroy(&pix2); if (*pencsize == 0) { free(*pencdata); *pencdata = NULL; return ERROR_INT("webp encoding failed", procName, 1); } return 0; }
/*! * \brief pixWriteStreamAsciiPnm() * * \param[in] fp file stream opened for write * \param[in] pix * \return 0 if OK; 1 on error * * Writes "ascii" format only: * 1 bpp --> pbm P1 * 2, 4, 8, 16 bpp, no colormap or grayscale colormap --> pgm P2 * 2, 4, 8 bpp with color-valued colormap, or rgb --> rgb ppm P3 */ l_int32 pixWriteStreamAsciiPnm(FILE *fp, PIX *pix) { char buffer[256]; l_uint8 cval[3]; l_int32 h, w, d, ds, i, j, k, maxval, count; l_uint32 val; PIX *pixs; PROCNAME("pixWriteStreamAsciiPnm"); if (!fp) return ERROR_INT("fp not defined", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); pixGetDimensions(pix, &w, &h, &d); if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) return ERROR_INT("d not in {1,2,4,8,16,32}", procName, 1); /* If a colormap exists, remove and convert to grayscale or rgb */ if (pixGetColormap(pix) != NULL) pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); else pixs = pixClone(pix); ds = pixGetDepth(pixs); if (ds == 1) { /* binary */ fprintf(fp, "P1\n# Ascii PBM file written by leptonica " "(www.leptonica.com)\n%d %d\n", w, h); count = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixs, j, i, &val); if (val == 0) fputc('0', fp); else /* val == 1 */ fputc('1', fp); fputc(' ', fp); count += 2; if (count >= 70) { fputc('\n', fp); count = 0; } } } } else if (ds == 2 || ds == 4 || ds == 8 || ds == 16) { /* grayscale */ maxval = (1 << ds) - 1; fprintf(fp, "P2\n# Ascii PGM file written by leptonica " "(www.leptonica.com)\n%d %d\n%d\n", w, h, maxval); count = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixs, j, i, &val); if (ds == 2) { sprintf(buffer, "%1d ", val); fwrite(buffer, 1, 2, fp); count += 2; } else if (ds == 4) { sprintf(buffer, "%2d ", val); fwrite(buffer, 1, 3, fp); count += 3; } else if (ds == 8) { sprintf(buffer, "%3d ", val); fwrite(buffer, 1, 4, fp); count += 4; } else { /* ds == 16 */ sprintf(buffer, "%5d ", val); fwrite(buffer, 1, 6, fp); count += 6; } if (count >= 60) { fputc('\n', fp); count = 0; } } } } else { /* rgb color */ fprintf(fp, "P3\n# Ascii PPM file written by leptonica " "(www.leptonica.com)\n%d %d\n255\n", w, h); count = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixs, j, i, &val); cval[0] = GET_DATA_BYTE(&val, COLOR_RED); cval[1] = GET_DATA_BYTE(&val, COLOR_GREEN); cval[2] = GET_DATA_BYTE(&val, COLOR_BLUE); for (k = 0; k < 3; k++) { sprintf(buffer, "%3d ", cval[k]); fwrite(buffer, 1, 4, fp); count += 4; if (count >= 60) { fputc('\n', fp); count = 0; } } } } } pixDestroy(&pixs); return 0; }
/*! * convertFilesTo1bpp() * * Input: dirin * substr (<optional> substring filter on filenames; can be NULL) * upscaling (1, 2 or 4; only for input color or grayscale) * thresh (global threshold for binarization; use 0 for default) * firstpage * npages (use 0 to do all from @firstpage to the end) * dirout * outformat (IFF_PNG, IFF_TIFF_G4) * Return: 0 if OK, 1 on error * * Notes: * (1) Images are sorted lexicographically, and the names in the * output directory are retained except for the extension. */ l_int32 convertFilesTo1bpp(const char *dirin, const char *substr, l_int32 upscaling, l_int32 thresh, l_int32 firstpage, l_int32 npages, const char *dirout, l_int32 outformat) { l_int32 i, nfiles; char buf[512]; char *fname, *tail, *basename; PIX *pixs, *pixg1, *pixg2, *pixb; SARRAY *safiles; PROCNAME("convertFilesTo1bpp"); if (!dirin) return ERROR_INT("dirin", procName, 1); if (!dirout) return ERROR_INT("dirout", procName, 1); if (upscaling != 1 && upscaling != 2 && upscaling != 4) return ERROR_INT("invalid upscaling factor", procName, 1); if (thresh <= 0) thresh = 180; if (firstpage < 0) firstpage = 0; if (npages < 0) npages = 0; if (outformat != IFF_TIFF_G4) outformat = IFF_PNG; safiles = getSortedPathnamesInDirectory(dirin, substr, firstpage, npages); if (!safiles) return ERROR_INT("safiles not made", procName, 1); if ((nfiles = sarrayGetCount(safiles)) == 0) { sarrayDestroy(&safiles); return ERROR_INT("no matching files in the directory", procName, 1); } for (i = 0; i < nfiles; i++) { fname = sarrayGetString(safiles, i, L_NOCOPY); if ((pixs = pixRead(fname)) == NULL) { L_WARNING("Couldn't read file %s\n", procName, fname); continue; } if (pixGetDepth(pixs) == 32) pixg1 = pixConvertRGBToLuminance(pixs); else pixg1 = pixClone(pixs); pixg2 = pixRemoveColormap(pixg1, REMOVE_CMAP_TO_GRAYSCALE); if (pixGetDepth(pixg2) == 1) { pixb = pixClone(pixg2); } else { if (upscaling == 1) pixb = pixThresholdToBinary(pixg2, thresh); else if (upscaling == 2) pixb = pixScaleGray2xLIThresh(pixg2, thresh); else /* upscaling == 4 */ pixb = pixScaleGray4xLIThresh(pixg2, thresh); } pixDestroy(&pixs); pixDestroy(&pixg1); pixDestroy(&pixg2); splitPathAtDirectory(fname, NULL, &tail); splitPathAtExtension(tail, &basename, NULL); if (outformat == IFF_TIFF_G4) { snprintf(buf, sizeof(buf), "%s/%s.tif", dirout, basename); pixWrite(buf, pixb, IFF_TIFF_G4); } else { snprintf(buf, sizeof(buf), "%s/%s.png", dirout, basename); pixWrite(buf, pixb, IFF_PNG); } pixDestroy(&pixb); FREE(tail); FREE(basename); } sarrayDestroy(&safiles); return 0; }
bool CJBig2File::MemoryToJBig2(unsigned char* pBufferBGRA ,int BufferSize, int nWidth, int nHeight, std::wstring sDstFileName) { // check for valid input parameters /////////////////////////////////////////////////////////// if ( NULL == pBufferBGRA ) return false; int lBufferSize = BufferSize; unsigned char *pSourceBuffer = pBufferBGRA; PIX *pSource = pixCreate( nWidth, nHeight, 32 ); if ( !pSource ) return false; for ( int nY = 0; nY < nHeight; nY++ ) { for ( int nX = 0; nX < nWidth; nX++, pSourceBuffer += 3 )//todooo сделать 3 ? 4 { pixSetRGBPixel( pSource, nX, nY, pSourceBuffer[ 2 ], pSourceBuffer[ 1 ], pSourceBuffer[ 0 ] ); } } jbig2ctx *pContext = jbig2_init( m_dTreshold, 0.5, 0, 0, ! m_bPDFMode, m_bRefine ? 10 : -1 ); // Пока сделаем запись одной картинки в JBig2 // TO DO: надо будет сделать запись нескольких картинок в 1 JBig2 файл // Убираем ColorMap PIX *pPixL = NULL; if ( NULL == ( pPixL = pixRemoveColormap( pSource, REMOVE_CMAP_BASED_ON_SRC ) ) ) { pixDestroy( &pSource ); jbig2_destroy( pContext ); return false; } pixDestroy( &pSource ); PIX *pPixT = NULL; if ( pPixL->d > 1 ) { PIX *pGray = NULL; if ( pPixL->d > 8 ) { pGray = pixConvertRGBToGrayFast( pPixL ); if ( !pGray ) { pixDestroy( &pSource ); jbig2_destroy( pContext ); return false; } } else { pGray = pixClone( pPixL ); } if ( m_bUpscale2x ) { pPixT = pixScaleGray2xLIThresh( pGray, m_nBwTreshold ); } else if ( m_bUpscale4x ) { pPixT = pixScaleGray4xLIThresh( pGray, m_nBwTreshold ); } else { pPixT = pixThresholdToBinary( pGray, m_nBwTreshold ); } pixDestroy( &pGray ); } else { pPixT = pixClone( pPixL ); } if ( m_sOutputTreshold.length() > 0 ) { pixWrite( m_sOutputTreshold.c_str(), pPixT, IFF_BMP ); } if ( m_bSegment && pPixL->d > 1 ) { PIX *pGraphics = segment_image( pPixT, pPixL ); if ( pGraphics ) { char *sFilename; asprintf( &sFilename, "%s.%04d.%s", m_sBaseName.c_str(), 0, ".bmp" ); pixWrite( sFilename, pGraphics, IFF_BMP ); free( sFilename ); } if ( !pPixT ) { // Ничего не делаем return true; } } pixDestroy( &pPixL ); if ( !m_bSymbolMode ) { int nLength = 0; uint8_t *pBuffer = jbig2_encode_generic( pPixT, !m_bPDFMode, 0, 0, m_bDuplicateLineRemoval, &nLength ); bool bRes = true; NSFile::CFileBinary file; if (file.CreateFileW(sDstFileName ) == true ) { file.WriteFile(pBuffer, nLength); file.CloseFile(); bRes = true; } else bRes = false; pixDestroy( &pPixT ); if ( pBuffer ) free( pBuffer ); jbig2_destroy( pContext ); return bRes; } int nNumPages = 1; jbig2_add_page( pContext, pPixT ); pixDestroy( &pPixT ); int nLength = 0; uint8_t *pBuffer = jbig2_pages_complete( pContext, &nLength ); if ( !pBuffer ) { jbig2_destroy( pContext ); return false; } if ( m_bPDFMode ) { std::wstring sFileName = sDstFileName;//m_sBaseName + _T(".sym"); NSFile::CFileBinary file; if ( file.CreateFileW(sFileName) == false) { free( pBuffer ); jbig2_destroy( pContext ); return false; } file.WriteFile( pBuffer, nLength ); file.CloseFile(); } free( pBuffer ); for ( int nIndex = 0; nIndex < nNumPages; ++nIndex ) { pBuffer = jbig2_produce_page( pContext, nIndex, -1, -1, &nLength ); if ( m_bPDFMode ) { std::wstring sFileName = m_sBaseName + L".0000"; NSFile::CFileBinary file; if ( file.CreateFileW(sFileName) ==false) { free( pBuffer ); jbig2_destroy( pContext ); return false; } file.WriteFile( pBuffer, nLength ); file.CloseFile(); } free( pBuffer ); } jbig2_destroy( pContext ); return true; }
/*! * pixConvertToDPix() * * Input: pix (1, 2, 4, 8, 16 or 32 bpp) * ncomps (number of components: 3 for RGB, 1 otherwise) * shiftflag (L_NO_SHIFTING or L_WITH_SHIFTING) * Return: dpix, or null on error * * Notes: * (1) If colormapped, remove to grayscale. * (2) If 32 bpp and @ncomps == 3, this is RGB; convert to luminance. * In all other cases the src image is treated as having a single * component of pixel values. * (3) Set @shiftflag to L_WITH_SHIFTING to move the DC of the * the DFT to the center of pix. */ DPIX * pixConvertToDPix(PIX *pixs, l_int32 ncomps, l_int32 shiftflag) { l_int32 w, h, d; l_int32 i, j, val, wplt, wpld; l_uint32 uval; l_uint32 *datat, *linet; l_float64 *datad, *lined; PIX *pixt; DPIX *dpixd; PROCNAME("pixConvertToDPix"); if (!pixs) return (DPIX *)ERROR_PTR("pixs not defined", procName, NULL); if (shiftflag != L_NO_SHIFTING && shiftflag != L_WITH_SHIFTING) return (DPIX *)ERROR_PTR("invalid shiftflag", procName, NULL); if (pixGetColormap(pixs)) pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); else if (pixGetDepth(pixs) == 32 && ncomps == 3) pixt = pixConvertRGBToLuminance(pixs); else pixt = pixClone(pixs); pixGetDimensions(pixt, &w, &h, &d); if ((dpixd = dpixCreate(w, h)) == NULL) return (DPIX *)ERROR_PTR("dpixd not made", procName, NULL); datat = pixGetData(pixt); wplt = pixGetWpl(pixt); datad = dpixGetData(dpixd); wpld = dpixGetWpl(dpixd); for (i = 0; i < h; i++) { linet = datat + i * wplt; lined = datad + i * wpld; if (d == 1) { for (j = 0; j < w; j++) { val = GET_DATA_BIT(linet, j); lined[j] = shiftflag ? (l_float64)(val * pow(-1, i + j)) : (l_float64)val; } } else if (d == 2) { for (j = 0; j < w; j++) { val = GET_DATA_DIBIT(linet, j); lined[j] = shiftflag ? (l_float64)(val * pow(-1, i + j)) : (l_float64)val; } } else if (d == 4) { for (j = 0; j < w; j++) { val = GET_DATA_QBIT(linet, j); lined[j] = shiftflag ? (l_float64)(val * pow(-1, i + j)) : (l_float64)val; } } else if (d == 8) { for (j = 0; j < w; j++) { val = GET_DATA_BYTE(linet, j); lined[j] = shiftflag ? (l_float64)(val * pow(-1, i + j)) : (l_float64)val; } } else if (d == 16) { for (j = 0; j < w; j++) { val = GET_DATA_TWO_BYTES(linet, j); lined[j] = shiftflag ? (l_float64)(val * pow(-1, i + j)) : (l_float64)val; } } else if (d == 32) { for (j = 0; j < w; j++) { uval = GET_DATA_FOUR_BYTES(linet, j); lined[j] = shiftflag ? (l_float64)(uval * pow(-1, i + j)) : (l_float64)uval; } } } pixDestroy(&pixt); return dpixd; }
main(int argc, char **argv) { const char *str; l_int32 equal, index, w, h; BOX *box; PIX *pixs, *pixd, *pixt, *pixd1, *pixd2, *pixd3; PIX *pixt0, *pixt1, *pixt2, *pixt3, *pixt4; PIXA *pixa; PIXCMAP *cmap; static char mainName[] = "grayquant_reg"; if ((pixs = pixRead("test8.jpg")) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); pixa = pixaCreate(0); pixSaveTiled(pixs, pixa, 1, 1, 20, 8); /* threshold to 1 bpp */ pixd = pixThresholdToBinary(pixs, THRESHOLD); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixWrite("/tmp/junkthr0.png", pixd, IFF_PNG); pixDestroy(&pixd); /* dither to 2 bpp, with and without colormap */ pixd = pixDitherTo2bpp(pixs, 1); pixt = pixDitherTo2bpp(pixs, 0); pixt2 = pixConvertGrayToColormap(pixt); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr1.png", pixd, IFF_PNG); pixWrite("/tmp/junkthr2.png", pixt, IFF_PNG); pixWrite("/tmp/junkthr3.png", pixt2, IFF_PNG); /* pixcmapWriteStream(stderr, pixGetColormap(pixd)); */ pixEqual(pixd, pixt2, &equal); if (!equal) fprintf(stderr, "Error: thr2 != thr3\n"); pixDestroy(&pixt); pixDestroy(&pixt2); pixDestroy(&pixd); /* threshold to 2 bpp, with and without colormap */ pixd = pixThresholdTo2bpp(pixs, 4, 1); pixt = pixThresholdTo2bpp(pixs, 4, 0); pixt2 = pixConvertGrayToColormap(pixt); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr4.png", pixd, IFF_PNG); pixWrite("/tmp/junkthr5.png", pixt2, IFF_PNG); pixEqual(pixd, pixt2, &equal); if (!equal) fprintf(stderr, "Error: thr4 != thr5\n"); pixDestroy(&pixt); pixDestroy(&pixt2); pixDestroy(&pixd); pixd = pixThresholdTo2bpp(pixs, 3, 1); pixt = pixThresholdTo2bpp(pixs, 3, 0); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr6.png", pixd, IFF_PNG); pixWrite("/tmp/junkthr7.png", pixt, IFF_PNG); pixDestroy(&pixt); pixDestroy(&pixd); /* threshold to 4 bpp, with and without colormap */ pixd = pixThresholdTo4bpp(pixs, 9, 1); pixt = pixThresholdTo4bpp(pixs, 9, 0); pixt2 = pixConvertGrayToColormap(pixt); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr8.png", pixd, IFF_PNG); pixWrite("/tmp/junkthr9.png", pixt, IFF_PNG); pixWrite("/tmp/junkthr10.png", pixt2, IFF_PNG); /* pixcmapWriteStream(stderr, pixGetColormap(pixd)); */ pixDestroy(&pixt); pixDestroy(&pixt2); pixDestroy(&pixd); /* threshold on 8 bpp, with and without colormap */ pixd = pixThresholdOn8bpp(pixs, 9, 1); pixt = pixThresholdOn8bpp(pixs, 9, 0); pixt2 = pixConvertGrayToColormap(pixt); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr11.png", pixd, IFF_PNG); pixWrite("/tmp/junkthr12.png", pixt2, IFF_PNG); /* pixcmapWriteStream(stderr, pixGetColormap(pixd)); */ pixEqual(pixd, pixt2, &equal); if (!equal) fprintf(stderr, "Error: thr11 != thr12\n"); pixDestroy(&pixt); pixDestroy(&pixt2); pixDestroy(&pixd); pixd1 = pixaDisplay(pixa, 0, 0); pixDisplay(pixd1, 100, 100); pixWrite("/tmp/junkpixd1.jpg", pixd1, IFF_JFIF_JPEG); pixDestroy(&pixd1); pixaDestroy(&pixa); pixa = pixaCreate(0); pixSaveTiled(pixs, pixa, 1, 1, 20, 32); /* highlight 2 bpp with colormap */ pixd = pixThresholdTo2bpp(pixs, 3, 1); cmap = pixGetColormap(pixd); pixcmapWriteStream(stderr, cmap); box = boxCreate(278, 35, 122, 50); pixSetSelectCmap(pixd, box, 2, 255, 255, 100); pixcmapWriteStream(stderr, cmap); pixDisplay(pixd, 0, 0); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixWrite("/tmp/junkthr13.png", pixd, IFF_PNG); pixDestroy(&pixd); boxDestroy(&box); /* test pixThreshold8() */ pixd = pixThreshold8(pixs, 1, 2, 1); /* cmap */ pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixWrite("/tmp/junkthr14.png", pixd, IFF_PNG); pixDisplay(pixd, 100, 0); pixDestroy(&pixd); pixd = pixThreshold8(pixs, 1, 2, 0); /* no cmap */ pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr15.png", pixd, IFF_PNG); pixDisplay(pixd, 200, 0); pixDestroy(&pixd); pixd = pixThreshold8(pixs, 2, 3, 1); /* highlight one box */ pixSaveTiled(pixd, pixa, 1, 0, 20, 0); box = boxCreate(278, 35, 122, 50); pixSetSelectCmap(pixd, box, 2, 255, 255, 100); pixWrite("/tmp/junkthr16.png", pixd, IFF_PNG); pixDisplay(pixd, 300, 0); cmap = pixGetColormap(pixd); pixcmapWriteStream(stderr, cmap); boxDestroy(&box); pixDestroy(&pixd); pixd = pixThreshold8(pixs, 2, 4, 0); /* no cmap */ pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr17.png", pixd, IFF_PNG); pixDisplay(pixd, 400, 0); pixDestroy(&pixd); pixd = pixThreshold8(pixs, 4, 6, 1); /* highlight one box */ box = boxCreate(278, 35, 122, 50); pixSetSelectCmap(pixd, box, 5, 255, 255, 100); pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr18.png", pixd, IFF_PNG); cmap = pixGetColormap(pixd); pixcmapWriteStream(stderr, cmap); boxDestroy(&box); pixDisplay(pixd, 500, 0); pixDestroy(&pixd); pixd = pixThreshold8(pixs, 4, 6, 0); /* no cmap */ pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr19.png", pixd, IFF_PNG); pixDisplay(pixd, 600, 0); pixDestroy(&pixd); /* highlight 4 bpp with 2 colormap entries */ /* Note: We use 5 levels (0-4) for gray. */ /* 5 & 6 are used for highlight color. */ pixd = pixThresholdTo4bpp(pixs, 5, 1); cmap = pixGetColormap(pixd); pixcmapGetIndex(cmap, 255, 255, 255, &index); box = boxCreate(278, 35, 122, 50); pixSetSelectCmap(pixd, box, index, 255, 255, 100); /* use 5 */ boxDestroy(&box); box = boxCreate(4, 6, 157, 33); pixSetSelectCmap(pixd, box, index, 100, 255, 255); /* use 6 */ boxDestroy(&box); pixcmapWriteStream(stderr, cmap); pixSaveTiled(pixd, pixa, 1, 1, 20, 0); pixDisplay(pixd, 700, 0); pixWrite("/tmp/junkthr20.png", pixd, IFF_PNG); pixDestroy(&pixd); /* comparison 8 bpp jpeg with 2 bpp (highlight) */ pixDestroy(&pixs); pixs = pixRead("feyn.tif"); pixt = pixScaleToGray4(pixs); pixt2 = pixReduceRankBinaryCascade(pixs, 2, 2, 0, 0); pixd = pixThresholdTo2bpp(pixt, 3, 1); box = boxCreate(175, 208, 228, 88); pixSetSelectCmap(pixd, box, 2, 255, 255, 100); pixDisplay(pixd, 100, 200); cmap = pixGetColormap(pixd); pixcmapWriteStream(stderr, cmap); pixSaveTiled(pixt, pixa, 1, 1, 20, 0); pixSaveTiled(pixt2, pixa, 1, 0, 20, 0); pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr21.jpg", pixt, IFF_JFIF_JPEG); pixWrite("/tmp/junkthr22.png", pixt2, IFF_PNG); pixWrite("/tmp/junkthr23.png", pixd, IFF_PNG); pixDestroy(&pixd); pixDestroy(&pixt2); boxDestroy(&box); /* thresholding to 4 bpp (highlight); use pixt from above */ pixd = pixThresholdTo4bpp(pixt, NLEVELS, 1); box = boxCreate(175, 208, 228, 83); pixSetSelectCmap(pixd, box, NLEVELS - 1, 255, 255, 100); boxDestroy(&box); box = boxCreate(232, 298, 110, 25); pixSetSelectCmap(pixd, box, NLEVELS - 1, 100, 255, 255); boxDestroy(&box); box = boxCreate(21, 698, 246, 82); pixSetSelectCmap(pixd, box, NLEVELS - 1, 225, 100, 255); boxDestroy(&box); pixDisplay(pixd, 500, 200); cmap = pixGetColormap(pixd); pixcmapWriteStream(stderr, cmap); pixt2 = pixReduceRankBinaryCascade(pixs, 2, 2, 0, 0); pixSaveTiled(pixt2, pixa, 1, 1, 20, 0); pixSaveTiled(pixd, pixa, 1, 0, 20, 0); pixWrite("/tmp/junkthr24.png", pixt2, IFF_PNG); pixWrite("/tmp/junkthr25.png", pixd, IFF_PNG); pixDestroy(&pixt2); pixDestroy(&pixd); /* Thresholding to 4 bpp at 2, 3, 4, 5 and 6 levels */ box = boxCreate(25, 202, 136, 37); pixt1 = pixClipRectangle(pixt, box, NULL); pixt2 = pixScale(pixt1, 6., 6.); pixGetDimensions(pixt2, &w, &h, NULL); pixSaveTiled(pixt2, pixa, 1, 1, 20, 0); pixDisplay(pixt2, 0, 0); pixWrite("/tmp/junk-8.jpg", pixt2, IFF_JFIF_JPEG); pixd = pixCreate(w, 6 * h, 8); pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixt2, 0, 0); pixt3 = pixThresholdTo4bpp(pixt2, 6, 1); pixt4 = pixRemoveColormap(pixt3, REMOVE_CMAP_TO_GRAYSCALE); pixRasterop(pixd, 0, h, w, h, PIX_SRC, pixt4, 0, 0); pixSaveTiled(pixt3, pixa, 1, 0, 20, 0); pixDisplay(pixt3, 0, 100); pixWrite("/tmp/junk-4-6.png", pixt3, IFF_PNG); pixDestroy(&pixt3); pixDestroy(&pixt4); pixt3 = pixThresholdTo4bpp(pixt2, 5, 1); pixt4 = pixRemoveColormap(pixt3, REMOVE_CMAP_TO_GRAYSCALE); pixRasterop(pixd, 0, 2 * h, w, h, PIX_SRC, pixt4, 0, 0); pixSaveTiled(pixt3, pixa, 1, 0, 20, 0); pixDisplay(pixt3, 0, 200); pixWrite("/tmp/junk-4-5.png", pixt3, IFF_PNG); pixDestroy(&pixt3); pixDestroy(&pixt4); pixt3 = pixThresholdTo4bpp(pixt2, 4, 1); pixt4 = pixRemoveColormap(pixt3, REMOVE_CMAP_TO_GRAYSCALE); pixRasterop(pixd, 0, 3 * h, w, h, PIX_SRC, pixt4, 0, 0); pixSaveTiled(pixt3, pixa, 1, 0, 20, 0); pixDisplay(pixt3, 0, 300); pixWrite("/tmp/junk-4-4.png", pixt3, IFF_PNG); pixDestroy(&pixt3); pixDestroy(&pixt4); pixt3 = pixThresholdTo4bpp(pixt2, 3, 1); pixt4 = pixRemoveColormap(pixt3, REMOVE_CMAP_TO_GRAYSCALE); pixRasterop(pixd, 0, 4 * h, w, h, PIX_SRC, pixt4, 0, 0); pixSaveTiled(pixt3, pixa, 1, 1, 20, 0); pixDisplay(pixt3, 0, 400); pixWrite("/tmp/junk-4-3.png", pixt3, IFF_PNG); pixDestroy(&pixt3); pixDestroy(&pixt4); pixt3 = pixThresholdTo4bpp(pixt2, 2, 1); pixt4 = pixRemoveColormap(pixt3, REMOVE_CMAP_TO_GRAYSCALE); pixRasterop(pixd, 0, 5 * h, w, h, PIX_SRC, pixt4, 0, 0); pixDisplay(pixt3, 0, 500); pixSaveTiled(pixt3, pixa, 1, 0, 20, 0); pixWrite("/tmp/junk-4-2.png", pixt3, IFF_PNG); pixDestroy(&pixt3); pixDestroy(&pixt4); pixWrite("/tmp/junk-all.png", pixd, IFF_PNG); pixDestroy(&pixd); pixd2 = pixaDisplay(pixa, 0, 0); pixDisplay(pixd2, 100, 100); pixWrite("/tmp/junkpixd2.jpg", pixd2, IFF_JFIF_JPEG); pixDestroy(&pixd2); pixaDestroy(&pixa); #if 0 /* upscale 2x and threshold to 1 bpp; e.g., use test8.jpg */ startTimer(); pixd = pixScaleGray2xLIThresh(pixs, THRESHOLD); fprintf(stderr, " time for scale/dither = %7.3f sec\n", stopTimer()); pixWrite(fileout, pixd, IFF_PNG); pixDestroy(&pixd); #endif #if 0 /* upscale 4x and threshold to 1 bpp; e.g., use test8.jpg */ startTimer(); pixd = pixScaleGray4xLIThresh(pixs, THRESHOLD); fprintf(stderr, " time for scale/dither = %7.3f sec\n", stopTimer()); pixWrite(fileout, pixd, IFF_PNG); pixDestroy(&pixd); #endif boxDestroy(&box); pixDestroy(&pixt); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixs); /* Thresholding with fixed and arbitrary bin boundaries */ pixa = pixaCreate(0); pixs = pixRead("stampede2.jpg"); pixSaveTiled(pixs, pixa, 1, 1, 20, 8); pixt = pixThresholdTo4bpp(pixs, 5, 1); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); pixt = pixThresholdTo4bpp(pixs, 7, 1); cmap = pixGetColormap(pixt); pixcmapWriteStream(stderr, cmap); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); pixt = pixThresholdTo4bpp(pixs, 11, 1); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); pixSaveTiled(pixs, pixa, 1, 1, 20, 8); str = "45 75 115 185"; pixt = pixThresholdGrayArb(pixs, str, 8, 0, 0, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); str = "38 65 85 115 160 210"; pixt = pixThresholdGrayArb(pixs, str, 8, 0, 1, 1); cmap = pixGetColormap(pixt); pixcmapWriteStream(stderr, cmap); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); str = "38 60 75 90 110 130 155 185 208 239"; pixt = pixThresholdGrayArb(pixs, str, 8, 0, 0, 0); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); pixSaveTiled(pixs, pixa, 1, 1, 20, 8); str = "45 75 115 185"; pixt = pixThresholdGrayArb(pixs, str, 0, 1, 0, 1); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); str = "38 65 85 115 160 210"; pixt = pixThresholdGrayArb(pixs, str, 0, 1, 0, 1); cmap = pixGetColormap(pixt); pixcmapWriteStream(stderr, cmap); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); str = "38 60 75 90 110 130 155 185 208 239"; pixt = pixThresholdGrayArb(pixs, str, 4, 1, 0, 1); pixSaveTiled(pixt, pixa, 1, 0, 20, 0); pixDestroy(&pixt); pixd3 = pixaDisplay(pixa, 0, 0); pixDisplay(pixd3, 100, 100); pixWrite("/tmp/junkpixd3.jpg", pixd3, IFF_JFIF_JPEG); pixDestroy(&pixd3); pixaDestroy(&pixa); pixDestroy(&pixs); return 0; }
static l_int32 TestImage(const char *filename, l_int32 i, L_REGPARAMS *rp) { char buf[256]; l_int32 w, h; l_float32 factor; PIX *pix, *pixs, *pixc, *pix32, *pixt, *pixd; PIXA *pixa; PROCNAME("TestImage"); if ((pix = pixRead(filename)) == NULL) { rp->success = FALSE; return ERROR_INT("pix not made", procName, 1); } pixGetDimensions(pix, &w, &h, NULL); if (w > MAX_WIDTH) { factor = (l_float32)MAX_WIDTH / (l_float32)w; pixs = pixScale(pix, factor, factor); } else pixs = pixClone(pix); pixDestroy(&pix); pixa = pixaCreate(0); /* Median cut quantizer (no dither; 5 sigbits) */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 32); pixc = pixMedianCutQuantGeneral(pixs, 0, 0, 16, 5, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 0, 0, 128, 5, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 0, 0, 256, 5, 1, 1); PixSave32(pixa, pixc, rp); /* Median cut quantizer (with dither; 5 sigbits) */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 0); pixc = pixMedianCutQuantGeneral(pixs, 1, 0, 16, 5, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 1, 0, 128, 5, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 1, 0, 256, 5, 1, 1); PixSave32(pixa, pixc, rp); /* Median cut quantizer (no dither; 6 sigbits) */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 32); pixc = pixMedianCutQuantGeneral(pixs, 0, 0, 16, 6, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 0, 0, 128, 6, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 0, 0, 256, 6, 1, 1); PixSave32(pixa, pixc, rp); /* Median cut quantizer (with dither; 6 sigbits) */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 0); pixc = pixMedianCutQuantGeneral(pixs, 1, 0, 16, 6, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 1, 0, 128, 6, 1, 1); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantGeneral(pixs, 1, 0, 256, 6, 10, 1); PixSave32(pixa, pixc, rp); /* Median cut quantizer (mixed color/gray) */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 0); pixc = pixMedianCutQuantMixed(pixs, 20, 10, 0, 0, 0); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantMixed(pixs, 60, 20, 0, 0, 0); PixSave32(pixa, pixc, rp); pixc = pixMedianCutQuantMixed(pixs, 180, 40, 0, 0, 0); PixSave32(pixa, pixc, rp); /* Simple 256 cube octcube quantizer */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 0); pixc = pixFixedOctcubeQuant256(pixs, 0); /* no dither */ PixSave32(pixa, pixc, rp); pixc = pixFixedOctcubeQuant256(pixs, 1); /* dither */ PixSave32(pixa, pixc, rp); /* 2-pass octree quantizer */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 0); pixc = pixOctreeColorQuant(pixs, 128, 0); /* no dither */ PixSave32(pixa, pixc, rp); pixc = pixOctreeColorQuant(pixs, 240, 0); /* no dither */ PixSave32(pixa, pixc, rp); pixc = pixOctreeColorQuant(pixs, 128, 1); /* dither */ PixSave32(pixa, pixc, rp); pixc = pixOctreeColorQuant(pixs, 240, 1); /* dither */ PixSave32(pixa, pixc, rp); /* Simple adaptive quantization to 4 or 8 bpp, specifying ncolors */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 0); pixc = pixOctreeQuantNumColors(pixs, 8, 0); /* fixed: 8 colors */ PixSave32(pixa, pixc, rp); pixc = pixOctreeQuantNumColors(pixs, 16, 0); /* fixed: 16 colors */ PixSave32(pixa, pixc, rp); pixc = pixOctreeQuantNumColors(pixs, 64, 0); /* fixed: 64 colors */ PixSave32(pixa, pixc, rp); pixc = pixOctreeQuantNumColors(pixs, 256, 0); /* fixed: 256 colors */ PixSave32(pixa, pixc, rp); /* Quantize to fully populated octree (RGB) at given level */ pixSaveTiled(pixs, pixa, 1.0, 1, SPACE, 0); pixc = pixFixedOctcubeQuantGenRGB(pixs, 2); /* level 2 */ PixSave32(pixa, pixc, rp); pixc = pixFixedOctcubeQuantGenRGB(pixs, 3); /* level 3 */ PixSave32(pixa, pixc, rp); pixc = pixFixedOctcubeQuantGenRGB(pixs, 4); /* level 4 */ PixSave32(pixa, pixc, rp); pixc = pixFixedOctcubeQuantGenRGB(pixs, 5); /* level 5 */ PixSave32(pixa, pixc, rp); /* Generate 32 bpp RGB image with num colors <= 256 */ pixt = pixOctreeQuantNumColors(pixs, 256, 0); /* cmapped version */ pix32 = pixRemoveColormap(pixt, REMOVE_CMAP_BASED_ON_SRC); /* Quantize image with few colors at fixed octree leaf level */ pixSaveTiled(pixt, pixa, 1.0, 1, SPACE, 0); pixc = pixFewColorsOctcubeQuant1(pix32, 2); /* level 2 */ PixSave32(pixa, pixc, rp); pixc = pixFewColorsOctcubeQuant1(pix32, 3); /* level 3 */ PixSave32(pixa, pixc, rp); pixc = pixFewColorsOctcubeQuant1(pix32, 4); /* level 4 */ PixSave32(pixa, pixc, rp); pixc = pixFewColorsOctcubeQuant1(pix32, 5); /* level 5 */ PixSave32(pixa, pixc, rp); /* Quantize image by population */ pixSaveTiled(pixt, pixa, 1.0, 1, SPACE, 0); pixc = pixOctreeQuantByPopulation(pixs, 3, 0); /* level 3, no dither */ PixSave32(pixa, pixc, rp); pixc = pixOctreeQuantByPopulation(pixs, 3, 1); /* level 3, dither */ PixSave32(pixa, pixc, rp); pixc = pixOctreeQuantByPopulation(pixs, 4, 0); /* level 4, no dither */ PixSave32(pixa, pixc, rp); pixc = pixOctreeQuantByPopulation(pixs, 4, 1); /* level 4, dither */ PixSave32(pixa, pixc, rp); /* Mixed color/gray octree quantizer */ pixSaveTiled(pixt, pixa, 1.0, 1, SPACE, 0); pixc = pixOctcubeQuantMixedWithGray(pix32, 8, 64, 10); /* max delta = 10 */ PixSave32(pixa, pixc, rp); pixc = pixOctcubeQuantMixedWithGray(pix32, 8, 64, 30); /* max delta = 30 */ PixSave32(pixa, pixc, rp); pixc = pixOctcubeQuantMixedWithGray(pix32, 8, 64, 50); /* max delta = 50 */ PixSave32(pixa, pixc, rp); /* Run the high-level converter */ pixSaveTiled(pixt, pixa, 1.0, 1, SPACE, 0); pixc = pixConvertRGBToColormap(pix32, 1); PixSave32(pixa, pixc, rp); pixDestroy(&pix32); pixDestroy(&pixt); pixd = pixaDisplay(pixa, 0, 0); pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display); sprintf(buf, "/tmp/regout/disp.%d.jpg", i); pixWrite(buf, pixd, IFF_JFIF_JPEG); pixDestroy(&pixs); pixDestroy(&pixd); pixaDestroy(&pixa); return 0; }
/*! * ioFormatTest() * * Input: filename (input file) * Return: 0 if OK; 1 on error or if the test fails * * Notes: * (1) This writes and reads a set of output files losslessly * in different formats to /tmp/format/, and tests that the * result before and after is unchanged. * (2) This should work properly on input images of any depth, * with and without colormaps. * (3) All supported formats are tested for bmp, png, tiff and * non-ascii pnm. Ascii pnm also works (but who'd ever want * to use it?) We allow 2 bpp bmp, although it's not * supported elsewhere. And we don't support reading * 16 bpp png, although this can be turned on in pngio.c. * (4) This silently skips png or tiff testing if HAVE_LIBPNG * or HAVE_LIBTIFF are 0, respectively. */ l_int32 ioFormatTest(const char *filename) { l_int32 w, h, d, depth, equal, problems; l_float32 diff; BOX *box; PIX *pixs, *pixc, *pix1, *pix2; PIXCMAP *cmap; PROCNAME("ioFormatTest"); if (!filename) return ERROR_INT("filename not defined", procName, 1); /* Read the input file and limit the size */ if ((pix1 = pixRead(filename)) == NULL) return ERROR_INT("pix1 not made", procName, 1); pixGetDimensions(pix1, &w, &h, NULL); if (w > 250 && h > 250) { /* take the central 250 x 250 region */ box = boxCreate(w / 2 - 125, h / 2 - 125, 250, 250); pixs = pixClipRectangle(pix1, box, NULL); boxDestroy(&box); } else { pixs = pixClone(pix1); } pixDestroy(&pix1); lept_mkdir("lept"); /* Note that the reader automatically removes colormaps * from 1 bpp BMP images, but not from 8 bpp BMP images. * Therefore, if our 8 bpp image initially doesn't have a * colormap, we are going to need to remove it from any * pix read from a BMP file. */ pixc = pixClone(pixs); /* laziness */ /* This does not test the alpha layer pixels, because most * formats don't support it. Remove any alpha. */ if (pixGetSpp(pixc) == 4) pixSetSpp(pixc, 3); cmap = pixGetColormap(pixc); /* colormap; can be NULL */ d = pixGetDepth(pixc); problems = FALSE; /* ----------------------- BMP -------------------------- */ /* BMP works for 1, 2, 4, 8 and 32 bpp images. * It always writes colormaps for 1 and 8 bpp, so we must * remove it after readback if the input image doesn't have * a colormap. Although we can write/read 2 bpp BMP, nobody * else can read them! */ if (d == 1 || d == 8) { L_INFO("write/read bmp\n", procName); pixWrite(FILE_BMP, pixc, IFF_BMP); pix1 = pixRead(FILE_BMP); if (!cmap) pix2 = pixRemoveColormap(pix1, REMOVE_CMAP_BASED_ON_SRC); else pix2 = pixClone(pix1); pixEqual(pixc, pix2, &equal); if (!equal) { L_INFO(" **** bad bmp image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); } if (d == 2 || d == 4 || d == 32) { L_INFO("write/read bmp\n", procName); pixWrite(FILE_BMP, pixc, IFF_BMP); pix1 = pixRead(FILE_BMP); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad bmp image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); } /* ----------------------- PNG -------------------------- */ #if HAVE_LIBPNG /* PNG works for all depths, but here, because we strip * 16 --> 8 bpp on reading, we don't test png for 16 bpp. */ if (d != 16) { L_INFO("write/read png\n", procName); pixWrite(FILE_PNG, pixc, IFF_PNG); pix1 = pixRead(FILE_PNG); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad png image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); } #endif /* HAVE_LIBPNG */ /* ----------------------- TIFF -------------------------- */ #if HAVE_LIBTIFF /* TIFF works for 1, 2, 4, 8, 16 and 32 bpp images. * Because 8 bpp tiff always writes 256 entry colormaps, the * colormap sizes may be different for 8 bpp images with * colormap; we are testing if the image content is the same. * Likewise, the 2 and 4 bpp tiff images with colormaps * have colormap sizes 4 and 16, rsp. This test should * work properly on the content, regardless of the number * of color entries in pixc. */ /* tiff uncompressed works for all pixel depths */ L_INFO("write/read uncompressed tiff\n", procName); pixWrite(FILE_TIFF, pixc, IFF_TIFF); pix1 = pixRead(FILE_TIFF); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff uncompressed image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); /* tiff lzw works for all pixel depths */ L_INFO("write/read lzw compressed tiff\n", procName); pixWrite(FILE_LZW, pixc, IFF_TIFF_LZW); pix1 = pixRead(FILE_LZW); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff lzw compressed image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); /* tiff adobe deflate (zip) works for all pixel depths */ L_INFO("write/read zip compressed tiff\n", procName); pixWrite(FILE_ZIP, pixc, IFF_TIFF_ZIP); pix1 = pixRead(FILE_ZIP); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff zip compressed image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); /* tiff g4, g3, rle and packbits work for 1 bpp */ if (d == 1) { L_INFO("write/read g4 compressed tiff\n", procName); pixWrite(FILE_G4, pixc, IFF_TIFF_G4); pix1 = pixRead(FILE_G4); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff g4 image ****\n", procName); problems = TRUE; } pixDestroy(&pix1); L_INFO("write/read g3 compressed tiff\n", procName); pixWrite(FILE_G3, pixc, IFF_TIFF_G3); pix1 = pixRead(FILE_G3); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff g3 image ****\n", procName); problems = TRUE; } pixDestroy(&pix1); L_INFO("write/read rle compressed tiff\n", procName); pixWrite(FILE_RLE, pixc, IFF_TIFF_RLE); pix1 = pixRead(FILE_RLE); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff rle image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); L_INFO("write/read packbits compressed tiff\n", procName); pixWrite(FILE_PB, pixc, IFF_TIFF_PACKBITS); pix1 = pixRead(FILE_PB); pixEqual(pixc, pix1, &equal); if (!equal) { L_INFO(" **** bad tiff packbits image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); } #endif /* HAVE_LIBTIFF */ /* ----------------------- PNM -------------------------- */ /* pnm works for 1, 2, 4, 8, 16 and 32 bpp. * pnm doesn't have colormaps, so when we write colormapped * pix out as pnm, the colormap is removed. Thus for the test, * we must remove the colormap from pixc before testing. */ L_INFO("write/read pnm\n", procName); pixWrite(FILE_PNM, pixc, IFF_PNM); pix1 = pixRead(FILE_PNM); if (cmap) pix2 = pixRemoveColormap(pixc, REMOVE_CMAP_BASED_ON_SRC); else pix2 = pixClone(pixc); pixEqual(pix1, pix2, &equal); if (!equal) { L_INFO(" **** bad pnm image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); /* ----------------------- GIF -------------------------- */ #if HAVE_LIBGIF /* GIF works for only 1 and 8 bpp, colormapped */ if (d != 8 || !cmap) pix1 = pixConvertTo8(pixc, 1); else pix1 = pixClone(pixc); L_INFO("write/read gif\n", procName); pixWrite(FILE_GIF, pix1, IFF_GIF); pix2 = pixRead(FILE_GIF); pixEqual(pix1, pix2, &equal); if (!equal) { L_INFO(" **** bad gif image: d = %d ****\n", procName, d); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); #endif /* HAVE_LIBGIF */ /* ----------------------- JPEG ------------------------- */ #if HAVE_LIBJPEG /* JPEG works for only 8 bpp gray and rgb */ if (cmap || d > 8) pix1 = pixConvertTo32(pixc); else pix1 = pixConvertTo8(pixc, 0); depth = pixGetDepth(pix1); L_INFO("write/read jpeg\n", procName); pixWrite(FILE_JPG, pix1, IFF_JFIF_JPEG); pix2 = pixRead(FILE_JPG); if (depth == 8) { pixCompareGray(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); } else { pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); } if (diff > 8.0) { L_INFO(" **** bad jpeg image: d = %d, diff = %5.2f ****\n", procName, depth, diff); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); #endif /* HAVE_LIBJPEG */ /* ----------------------- WEBP ------------------------- */ #if HAVE_LIBWEBP /* WEBP works for rgb and rgba */ if (cmap || d <= 16) pix1 = pixConvertTo32(pixc); else pix1 = pixClone(pixc); depth = pixGetDepth(pix1); L_INFO("write/read webp\n", procName); pixWrite(FILE_WEBP, pix1, IFF_WEBP); pix2 = pixRead(FILE_WEBP); pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); if (diff > 5.0) { L_INFO(" **** bad webp image: d = %d, diff = %5.2f ****\n", procName, depth, diff); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); #endif /* HAVE_LIBWEBP */ /* ----------------------- JP2K ------------------------- */ #if HAVE_LIBJP2K /* JP2K works for only 8 bpp gray, rgb and rgba */ if (cmap || d > 8) pix1 = pixConvertTo32(pixc); else pix1 = pixConvertTo8(pixc, 0); depth = pixGetDepth(pix1); L_INFO("write/read jp2k\n", procName); pixWrite(FILE_JP2K, pix1, IFF_JP2); pix2 = pixRead(FILE_JP2K); if (depth == 8) { pixCompareGray(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); } else { pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); } fprintf(stderr, "diff = %7.3f\n", diff); if (diff > 7.0) { L_INFO(" **** bad jp2k image: d = %d, diff = %5.2f ****\n", procName, depth, diff); problems = TRUE; } pixDestroy(&pix1); pixDestroy(&pix2); #endif /* HAVE_LIBJP2K */ if (problems == FALSE) L_INFO("All formats read and written OK!\n", procName); pixDestroy(&pixc); pixDestroy(&pixs); return problems; }
main(int argc, char **argv) { char *errorstr; l_int32 same, error; PIX *pixs1, *pixs2, *pixs4, *pixs8, *pixs16, *pixs32, *pixd; PIX *pixc2, *pixc4, *pixc8; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIXCMAP *cmap; SARRAY *sa; static char mainName[] = "convert_reg"; if (argc != 1) exit(ERROR_INT(" Syntax: convert_rt", mainName, 1)); if ((pixs1 = pixRead("test1.png")) == NULL) exit(ERROR_INT("pixs1 not made", mainName, 1)); if ((pixs2 = pixRead("dreyfus2.png")) == NULL) exit(ERROR_INT("pixs2 not made", mainName, 1)); if ((pixc2 = pixRead("weasel2.4c.png")) == NULL) exit(ERROR_INT("pixc2 not made", mainName, 1)); if ((pixs4 = pixRead("weasel4.16g.png")) == NULL) exit(ERROR_INT("pixs4 not made", mainName, 1)); if ((pixc4 = pixRead("weasel4.11c.png")) == NULL) exit(ERROR_INT("pixc4 not made", mainName, 1)); if ((pixs8 = pixRead("karen8.jpg")) == NULL) exit(ERROR_INT("pixs8 not made", mainName, 1)); if ((pixc8 = pixRead("weasel8.240c.png")) == NULL) exit(ERROR_INT("pixc8 not made", mainName, 1)); if ((pixs16 = pixRead("test16.tif")) == NULL) exit(ERROR_INT("pixs16 not made", mainName, 1)); if ((pixs32 = pixRead("marge.jpg")) == NULL) exit(ERROR_INT("pixs32 not made", mainName, 1)); error = FALSE; sa = sarrayCreate(0); /* Conversion: 1 bpp --> 8 bpp --> 1 bpp */ pixt1 = pixConvertTo8(pixs1, FALSE); pixt2 = pixThreshold8(pixt1, 1, 0, 0); pixEqual(pixs1, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs1, 100, 100, "1 bpp, no cmap", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "1 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 1 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 1 bpp <==> 8 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 2 bpp --> 8 bpp --> 2 bpp */ /* Conversion: 2 bpp cmap --> 8 bpp cmap --> 2 bpp cmap */ pixt1 = pixRemoveColormap(pixs2, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixThreshold8(pixt1, 2, 4, 0); pixt3 = pixConvertTo8(pixt2, FALSE); pixt4 = pixThreshold8(pixt3, 2, 4, 0); pixEqual(pixt2, pixt4, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "2 bpp, no cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "2 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 8 bpp\n"); pixt5 = pixConvertTo8(pixs2, TRUE); pixt6 = pixThreshold8(pixt5, 2, 4, 1); pixEqual(pixs2, pixt6, &same); if (!same) { pixDisplayWithTitle(pixs2, 100, 100, "2 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt6, 500, 100, "2 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 8 bpp; cmap", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 8 bpp; cmap\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); /* Conversion: 4 bpp --> 8 bpp --> 4 bpp */ /* Conversion: 4 bpp cmap --> 8 bpp cmap --> 4 bpp cmap */ pixt1 = pixRemoveColormap(pixs4, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixThreshold8(pixt1, 4, 16, 0); pixt3 = pixConvertTo8(pixt2, FALSE); pixt4 = pixThreshold8(pixt3, 4, 16, 0); pixEqual(pixt2, pixt4, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "4 bpp, no cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 8 bpp\n"); pixt5 = pixConvertTo8(pixs4, TRUE); pixt6 = pixThreshold8(pixt5, 4, 16, 1); pixEqual(pixs4, pixt6, &same); if (!same) { pixDisplayWithTitle(pixs4, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt6, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 8 bpp, cmap", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 8 bpp; cmap\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); /* Conversion: 2 bpp cmap --> 2 bpp --> 2 bpp cmap --> 2 bpp */ pixt1 = pixRemoveColormap(pixs2, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixConvertGrayToColormap(pixt1); pixt3 = pixRemoveColormap(pixt2, REMOVE_CMAP_TO_GRAYSCALE); pixt4 = pixThresholdTo2bpp(pixt3, 4, 1); pixEqual(pixt1, pixt4, &same); if (!same) { pixDisplayWithTitle(pixs2, 100, 100, "2 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "2 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 2 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 2 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 4 bpp cmap --> 4 bpp --> 4 bpp cmap --> 4 bpp */ pixt1 = pixRemoveColormap(pixs4, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixConvertGrayToColormap(pixt1); pixt3 = pixRemoveColormap(pixt2, REMOVE_CMAP_TO_GRAYSCALE); pixt4 = pixThresholdTo4bpp(pixt3, 16, 1); pixEqual(pixt1, pixt4, &same); if (!same) { pixDisplayWithTitle(pixs4, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 4 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 4 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 8 bpp --> 8 bpp cmap --> 8 bpp */ pixt1 = pixConvertTo8(pixs8, TRUE); pixt2 = pixConvertTo8(pixt1, FALSE); pixEqual(pixs8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixt1, 100, 100, "8 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 8 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 2 bpp cmap --> 32 bpp --> 2 bpp cmap */ pixt1 = pixConvertTo8(pixc2, TRUE); pixt2 = pixConvertTo32(pixt1); pixt3 = pixConvertTo32(pixc2); pixEqual(pixt2, pixt3, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "32 bpp", DFLAG); pixDisplayWithTitle(pixt3, 500, 100, "32 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp ==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 32 bpp\n"); cmap = pixGetColormap(pixc2); pixt4 = pixOctcubeQuantFromCmap(pixt3, cmap, 2, 4, L_EUCLIDEAN_DISTANCE); pixEqual(pixc2, pixt4, &same); if (!same) { pixDisplayWithTitle(pixc2, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 4 bpp cmap --> 32 bpp --> 4 bpp cmap */ pixt1 = pixConvertTo8(pixc4, TRUE); pixt2 = pixConvertTo32(pixt1); pixt3 = pixConvertTo32(pixc4); pixEqual(pixt2, pixt3, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "32 bpp", DFLAG); pixDisplayWithTitle(pixt3, 500, 100, "32 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp ==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 32 bpp\n"); cmap = pixGetColormap(pixc4); pixt4 = pixOctcubeQuantFromCmap(pixt3, cmap, 2, 4, L_EUCLIDEAN_DISTANCE); pixEqual(pixc4, pixt4, &same); if (!same) { pixDisplayWithTitle(pixc4, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 8 bpp --> 32 bpp --> 8 bpp */ pixt1 = pixConvertTo32(pixs8); pixt2 = pixConvertTo8(pixt1, FALSE); pixEqual(pixs8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs8, 100, 100, "8 bpp", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp <==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 8 bpp --> 16 bpp --> 8 bpp */ pixt1 = pixConvert8To16(pixs8, 8); pixt2 = pixConvertTo8(pixt1, FALSE); pixEqual(pixs8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs8, 100, 100, "8 bpp", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp <==> 16 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 16 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 16 bpp --> 8 bpp --> 16 bpp */ pixt1 = pixConvert16To8(pixs16, 1); pixt2 = pixConvertTo16(pixt1); pixWrite("/tmp/junkpix.png", pixt2, IFF_PNG); pixEqual(pixs16, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs16, 100, 100, "16 bpp", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "16 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 16 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 16 bpp <==> 8 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 8 bpp cmap --> 32 bpp --> 8 bpp cmap */ /* Required to go to level 6 of octcube to get identical result */ pixt1 = pixConvertTo32(pixc8); cmap = pixGetColormap(pixc8); pixt2 = pixOctcubeQuantFromCmap(pixt1, cmap, 2, 6, L_EUCLIDEAN_DISTANCE); pixEqual(pixc8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixc8, 100, 100, "8 bpp cmap", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp cmap <==> 32 bpp cmap", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Summarize results */ if (error == FALSE) fprintf(stderr, "No errors found\n"); else { errorstr = sarrayToString(sa, 1); fprintf(stderr, "Errors in the following:\n %s", errorstr); lept_free(errorstr); } sarrayDestroy(&sa); pixDestroy(&pixs1); pixDestroy(&pixs2); pixDestroy(&pixs4); pixDestroy(&pixc2); pixDestroy(&pixc4); pixDestroy(&pixs8); pixDestroy(&pixc8); pixDestroy(&pixs16); pixDestroy(&pixs32); return 0; }
/*! * \brief pixWriteStreamPnm() * * \param[in] fp file stream opened for write * \param[in] pix * \return 0 if OK; 1 on error * * <pre> * Notes: * (1) This writes "raw" packed format only: * 1 bpp --\> pbm (P4) * 2, 4, 8, 16 bpp, no colormap or grayscale colormap --\> pgm (P5) * 2, 4, 8 bpp with color-valued colormap, or rgb --\> rgb ppm (P6) * (2) 24 bpp rgb are not supported in leptonica, but this will * write them out as a packed array of bytes (3 to a pixel). * </pre> */ l_int32 pixWriteStreamPnm(FILE *fp, PIX *pix) { l_uint8 val8; l_uint8 pel[4]; l_uint16 val16; l_int32 h, w, d, ds, i, j, wpls, bpl, filebpl, writeerror, maxval; l_uint32 *pword, *datas, *lines; PIX *pixs; PROCNAME("pixWriteStreamPnm"); if (!fp) return ERROR_INT("fp not defined", procName, 1); if (!pix) return ERROR_INT("pix not defined", procName, 1); pixGetDimensions(pix, &w, &h, &d); if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 24 && d != 32) return ERROR_INT("d not in {1,2,4,8,16,24,32}", procName, 1); /* If a colormap exists, remove and convert to grayscale or rgb */ if (pixGetColormap(pix) != NULL) pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); else pixs = pixClone(pix); ds = pixGetDepth(pixs); datas = pixGetData(pixs); wpls = pixGetWpl(pixs); writeerror = 0; if (ds == 1) { /* binary */ fprintf(fp, "P4\n# Raw PBM file written by leptonica " "(www.leptonica.com)\n%d %d\n", w, h); bpl = (w + 7) / 8; for (i = 0; i < h; i++) { lines = datas + i * wpls; for (j = 0; j < bpl; j++) { val8 = GET_DATA_BYTE(lines, j); fwrite(&val8, 1, 1, fp); } } } else if (ds == 2 || ds == 4 || ds == 8 || ds == 16) { /* grayscale */ maxval = (1 << ds) - 1; fprintf(fp, "P5\n# Raw PGM file written by leptonica " "(www.leptonica.com)\n%d %d\n%d\n", w, h, maxval); if (ds != 16) { for (i = 0; i < h; i++) { lines = datas + i * wpls; for (j = 0; j < w; j++) { if (ds == 2) val8 = GET_DATA_DIBIT(lines, j); else if (ds == 4) val8 = GET_DATA_QBIT(lines, j); else /* ds == 8 */ val8 = GET_DATA_BYTE(lines, j); fwrite(&val8, 1, 1, fp); } } } else { /* ds == 16 */ for (i = 0; i < h; i++) { lines = datas + i * wpls; for (j = 0; j < w; j++) { val16 = GET_DATA_TWO_BYTES(lines, j); fwrite(&val16, 2, 1, fp); } } } } else { /* rgb color */ fprintf(fp, "P6\n# Raw PPM file written by leptonica " "(www.leptonica.com)\n%d %d\n255\n", w, h); if (d == 24) { /* packed, 3 bytes to a pixel */ filebpl = 3 * w; for (i = 0; i < h; i++) { /* write out each raster line */ lines = datas + i * wpls; if (fwrite(lines, 1, filebpl, fp) != filebpl) writeerror = 1; } } else { /* 32 bpp rgb */ for (i = 0; i < h; i++) { lines = datas + i * wpls; for (j = 0; j < wpls; j++) { pword = lines + j; pel[0] = GET_DATA_BYTE(pword, COLOR_RED); pel[1] = GET_DATA_BYTE(pword, COLOR_GREEN); pel[2] = GET_DATA_BYTE(pword, COLOR_BLUE); if (fwrite(pel, 1, 3, fp) != 3) writeerror = 1; } } } } pixDestroy(&pixs); if (writeerror) return ERROR_INT("image write fail", procName, 1); return 0; }
int main(int argc, char **argv) { char dilateseq[512], erodeseq[512]; char openseq[512], closeseq[512]; char wtophatseq[512], btophatseq[512]; l_int32 w, h; PIX *pixs, *pix1, *pix2, *pix3, *pix4, *pix5; PIXA *pixa; PIXACC *pacc; PIXCMAP *cmap; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixs = pixRead("aneurisms8.jpg"); pixa = pixaCreate(0); /* =========================================================== */ /* -------- Test gray morph, including interpreter ------------ */ pix1 = pixDilateGray(pixs, WSIZE, HSIZE); sprintf(dilateseq, "D%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, dilateseq, 0, 0); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0 */ regTestComparePix(rp, pix1, pix2); /* 1 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixErodeGray(pixs, WSIZE, HSIZE); sprintf(erodeseq, "E%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, erodeseq, 0, 100); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 2 */ regTestComparePix(rp, pix1, pix2); /* 3 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixOpenGray(pixs, WSIZE, HSIZE); sprintf(openseq, "O%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, openseq, 0, 200); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 4 */ regTestComparePix(rp, pix1, pix2); /* 5 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixCloseGray(pixs, WSIZE, HSIZE); sprintf(closeseq, "C%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, closeseq, 0, 300); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 6 */ regTestComparePix(rp, pix1, pix2); /* 7 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); sprintf(wtophatseq, "Tw%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, wtophatseq, 0, 400); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 8 */ regTestComparePix(rp, pix1, pix2); /* 9 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pix1 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_BLACK); sprintf(btophatseq, "Tb%d.%d", WSIZE, HSIZE); pix2 = pixGrayMorphSequence(pixs, btophatseq, 0, 500); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 10 */ regTestComparePix(rp, pix1, pix2); /* 11 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); /* ------------- Test erode/dilate duality -------------- */ pix1 = pixDilateGray(pixs, WSIZE, HSIZE); pix2 = pixInvert(NULL, pixs); pix3 = pixErodeGray(pix2, WSIZE, HSIZE); pixInvert(pix3, pix3); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 12 */ regTestComparePix(rp, pix1, pix3); /* 13 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* ------------- Test open/close duality -------------- */ pix1 = pixOpenGray(pixs, WSIZE, HSIZE); pix2 = pixInvert(NULL, pixs); pix3 = pixCloseGray(pix2, WSIZE, HSIZE); pixInvert(pix3, pix3); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 14 */ regTestComparePix(rp, pix1, pix3); /* 15 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* ------------- Test tophat duality -------------- */ pix1 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); pix2 = pixInvert(NULL, pixs); pix3 = pixTophat(pix2, WSIZE, HSIZE, L_TOPHAT_BLACK); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 16 */ regTestComparePix(rp, pix1, pix3); /* 17 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); pix1 = pixGrayMorphSequence(pixs, "Tw9.5", 0, 100); pix2 = pixInvert(NULL, pixs); pix3 = pixGrayMorphSequence(pix2, "Tb9.5", 0, 300); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 18 */ regTestComparePix(rp, pix1, pix3); /* 19 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* ------------- Test opening/closing for large sels -------------- */ pix1 = pixGrayMorphSequence(pixs, "C9.9 + C19.19 + C29.29 + C39.39 + C49.49", 0, 100); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 20 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixGrayMorphSequence(pixs, "O9.9 + O19.19 + O29.29 + O39.39 + O49.49", 0, 400); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 21 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixaDisplayTiledInColumns(pixa, 4, 1.0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 22 */ pixDisplayWithTitle(pix1, 0, 0, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pix1); /* =========================================================== */ pixa = pixaCreate(0); /* ---------- Closing plus white tophat result ------------ * * Parameters: wsize, hsize = 9, 29 * * ---------------------------------------------------------*/ pix1 = pixCloseGray(pixs, 9, 9); pix2 = pixTophat(pix1, 9, 9, L_TOPHAT_WHITE); pix3 = pixGrayMorphSequence(pixs, "C9.9 + TW9.9", 0, 0); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 23 */ regTestComparePix(rp, pix2, pix3); /* 24 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixMaxDynamicRange(pix2, L_LINEAR_SCALE); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 25 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); pix1 = pixCloseGray(pixs, 29, 29); pix2 = pixTophat(pix1, 29, 29, L_TOPHAT_WHITE); pix3 = pixGrayMorphSequence(pixs, "C29.29 + Tw29.29", 0, 0); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 26 */ regTestComparePix(rp, pix2, pix3); /* 27 */ pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixMaxDynamicRange(pix2, L_LINEAR_SCALE); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 28 */ pixaAddPix(pixa, pix1, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* --------- hdome with parameter height = 100 ------------*/ pix1 = pixHDome(pixs, 100, 4); pix2 = pixMaxDynamicRange(pix1, L_LINEAR_SCALE); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 29 */ regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 30 */ pixaAddPix(pixa, pix1, L_INSERT); pixaAddPix(pixa, pix2, L_INSERT); /* ----- Contrast enhancement with morph parameters 9, 9 -------*/ pixGetDimensions(pixs, &w, &h, NULL); pix1 = pixInitAccumulate(w, h, 0x8000); pixAccumulate(pix1, pixs, L_ARITH_ADD); pixMultConstAccumulate(pix1, 3., 0x8000); pix2 = pixOpenGray(pixs, 9, 9); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 31 */ pixaAddPix(pixa, pix2, L_INSERT); pixAccumulate(pix1, pix2, L_ARITH_SUBTRACT); pix2 = pixCloseGray(pixs, 9, 9); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 32 */ pixaAddPix(pixa, pix2, L_INSERT); pixAccumulate(pix1, pix2, L_ARITH_SUBTRACT); pix2 = pixFinalAccumulate(pix1, 0x8000, 8); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 33 */ pixaAddPix(pixa, pix2, L_INSERT); pixDestroy(&pix1); /* Do the same thing with the Pixacc */ pacc = pixaccCreate(w, h, 1); pixaccAdd(pacc, pixs); pixaccMultConst(pacc, 3.); pix1 = pixOpenGray(pixs, 9, 9); pixaccSubtract(pacc, pix1); pixDestroy(&pix1); pix1 = pixCloseGray(pixs, 9, 9); pixaccSubtract(pacc, pix1); pixDestroy(&pix1); pix1 = pixaccFinal(pacc, 8); pixaccDestroy(&pacc); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 34 */ pixaAddPix(pixa, pix1, L_INSERT); regTestComparePix(rp, pix1, pix2); /* 35 */ pix1 = pixaDisplayTiledInColumns(pixa, 4, 1.0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 36 */ pixDisplayWithTitle(pix1, 1100, 0, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pix1); pixDestroy(&pixs); /* =========================================================== */ pixa = pixaCreate(0); /* ---- Tophat result on feynman stamp, to extract diagrams ----- */ pixs = pixRead("feynman-stamp.jpg"); pixGetDimensions(pixs, &w, &h, NULL); /* Make output image to hold five intermediate images */ pix1 = pixCreate(5 * w + 18, h + 6, 32); /* composite output image */ pixSetAllArbitrary(pix1, 0x0000ff00); /* set to blue */ /* Paste in the input image */ pix2 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); pixRasterop(pix1, 3, 3, w, h, PIX_SRC, pix2, 0, 0); /* 1st one */ regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 37 */ pixaAddPix(pixa, pix2, L_INSERT); /* Paste in the grayscale version */ cmap = pixGetColormap(pixs); if (cmap) pix2 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); else pix2 = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33); pix3 = pixConvertTo32(pix2); /* 8 --> 32 bpp */ pixRasterop(pix1, w + 6, 3, w, h, PIX_SRC, pix3, 0, 0); /* 2nd one */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 38 */ pixaAddPix(pixa, pix3, L_INSERT); /* Paste in a log dynamic range scaled version of the white tophat */ pix3 = pixTophat(pix2, 3, 3, L_TOPHAT_WHITE); pix4 = pixMaxDynamicRange(pix3, L_LOG_SCALE); pix5 = pixConvertTo32(pix4); pixRasterop(pix1, 2 * w + 9, 3, w, h, PIX_SRC, pix5, 0, 0); /* 3rd */ regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 39 */ pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix4); /* Stretch the range and threshold to binary; paste it in */ pix2 = pixGammaTRC(NULL, pix3, 1.0, 0, 80); pix4 = pixThresholdToBinary(pix2, 70); pix5 = pixConvertTo32(pix4); pixRasterop(pix1, 3 * w + 12, 3, w, h, PIX_SRC, pix5, 0, 0); /* 4th */ regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 40 */ pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix2); pixDestroy(&pix3); /* Invert; this is the final result */ pixInvert(pix4, pix4); pix5 = pixConvertTo32(pix4); pixRasterop(pix1, 4 * w + 15, 3, w, h, PIX_SRC, pix5, 0, 0); /* 5th */ regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 41 */ pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix4); pix1 = pixaDisplayTiledInRows(pixa, 32, 1700, 1.0, 0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 42 */ pixDisplayWithTitle(pix1, 0, 800, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pix1); pixDestroy(&pixs); return regTestCleanup(rp); }
/*! * \brief pixWriteStreamJpeg() * * \param[in] fp file stream * \param[in] pixs any depth; cmap is OK * \param[in] quality 1 - 100; 75 is default value; 0 is also default * \param[in] progressive 0 for baseline sequential; 1 for progressive * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) Progressive encoding gives better compression, at the * expense of slower encoding and decoding. * (2) Standard chroma subsampling is 2x2 on both the U and V * channels. For highest quality, use no subsampling; this * option is set by pixSetChromaSampling(pix, 0). * (3) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16 * and 32 bpp. However, it is possible, and in some cases desirable, * to write out a jpeg file using an rgb pix that has 24 bpp. * This can be created by appending the raster data for a 24 bpp * image (with proper scanline padding) directly to a 24 bpp * pix that was created without a data array. * (4) There are two compression paths in this function: * * Grayscale image, no colormap: compress as 8 bpp image. * * rgb full color image: copy each line into the color * line buffer, and compress as three 8 bpp images. * (5) Under the covers, the jpeg library transforms rgb to a * luminance-chromaticity triple, each component of which is * also 8 bits, and compresses that. It uses 2 Huffman tables, * a higher resolution one (with more quantization levels) * for luminosity and a lower resolution one for the chromas. * </pre> */ l_int32 pixWriteStreamJpeg(FILE *fp, PIX *pixs, l_int32 quality, l_int32 progressive) { l_int32 xres, yres; l_int32 i, j, k; l_int32 w, h, d, wpl, spp, colorflag, rowsamples; l_uint32 *ppixel, *line, *data; JSAMPROW rowbuffer; PIX *pix; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; const char *text; jmp_buf jmpbuf; /* must be local to the function */ PROCNAME("pixWriteStreamJpeg"); if (!fp) return ERROR_INT("stream not open", procName, 1); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (quality <= 0) quality = 75; /* default */ /* If necessary, convert the pix so that it can be jpeg compressed. * The colormap is removed based on the source, so if the colormap * has only gray colors, the image will be compressed with spp = 1. */ pixGetDimensions(pixs, &w, &h, &d); pix = NULL; if (pixGetColormap(pixs) != NULL) { L_INFO("removing colormap; may be better to compress losslessly\n", procName); pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); } else if (d >= 8 && d != 16) { /* normal case; no rewrite */ pix = pixClone(pixs); } else if (d < 8 || d == 16) { L_INFO("converting from %d to 8 bpp\n", procName, d); pix = pixConvertTo8(pixs, 0); /* 8 bpp, no cmap */ } else { L_ERROR("unknown pix type with d = %d and no cmap\n", procName, d); return 1; } if (!pix) return ERROR_INT("pix not made", procName, 1); rewind(fp); rowbuffer = NULL; /* Modify the jpeg error handling to catch fatal errors */ cinfo.err = jpeg_std_error(&jerr); cinfo.client_data = (void *)&jmpbuf; jerr.error_exit = jpeg_error_catch_all_1; if (setjmp(jmpbuf)) { LEPT_FREE(rowbuffer); pixDestroy(&pix); return ERROR_INT("internal jpeg error", procName, 1); } /* Initialize the jpeg structs for compression */ jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = w; cinfo.image_height = h; /* Set the color space and number of components */ d = pixGetDepth(pix); if (d == 8) { colorflag = 0; /* 8 bpp grayscale; no cmap */ cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; } else { /* d == 32 || d == 24 */ colorflag = 1; /* rgb */ cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; } jpeg_set_defaults(&cinfo); /* Setting optimize_coding to TRUE seems to improve compression * by approx 2-4 percent, and increases comp time by approx 20%. */ cinfo.optimize_coding = FALSE; /* Set resolution in pixels/in (density_unit: 1 = in, 2 = cm) */ xres = pixGetXRes(pix); yres = pixGetYRes(pix); if ((xres != 0) && (yres != 0)) { cinfo.density_unit = 1; /* designates pixels per inch */ cinfo.X_density = xres; cinfo.Y_density = yres; } /* Set the quality and progressive parameters */ jpeg_set_quality(&cinfo, quality, TRUE); if (progressive) jpeg_simple_progression(&cinfo); /* Set the chroma subsampling parameters. This is done in * YUV color space. The Y (intensity) channel is never subsampled. * The standard subsampling is 2x2 on both the U and V channels. * Notation on this is confusing. For a nice illustrations, see * http://en.wikipedia.org/wiki/Chroma_subsampling * The standard subsampling is written as 4:2:0. * We allow high quality where there is no subsampling on the * chroma channels: denoted as 4:4:4. */ if (pixs->special == L_NO_CHROMA_SAMPLING_JPEG) { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; } jpeg_start_compress(&cinfo, TRUE); if ((text = pixGetText(pix))) jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text)); /* Allocate row buffer */ spp = cinfo.input_components; rowsamples = spp * w; if ((rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), rowsamples)) == NULL) { pixDestroy(&pix); return ERROR_INT("calloc fail for rowbuffer", procName, 1); } data = pixGetData(pix); wpl = pixGetWpl(pix); for (i = 0; i < h; i++) { line = data + i * wpl; if (colorflag == 0) { /* 8 bpp gray */ for (j = 0; j < w; j++) rowbuffer[j] = GET_DATA_BYTE(line, j); } else { /* colorflag == 1 */ if (d == 24) { /* See note 3 above; special case of 24 bpp rgb */ jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1); } else { /* standard 32 bpp rgb */ ppixel = line; for (j = k = 0; j < w; j++) { rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED); rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN); rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE); ppixel++; } } } if (d != 24) jpeg_write_scanlines(&cinfo, &rowbuffer, 1); } jpeg_finish_compress(&cinfo); pixDestroy(&pix); LEPT_FREE(rowbuffer); jpeg_destroy_compress(&cinfo); return 0; }
int main(int argc, char **argv) { char dilateseq[BUF_SIZE], erodeseq[BUF_SIZE]; char openseq[BUF_SIZE], closeseq[BUF_SIZE]; char wtophatseq[BUF_SIZE], btophatseq[BUF_SIZE]; char *filein; l_int32 w, h, d; PIX *pixs, *pixt, *pixt2, *pixt3, *pixt3a, *pixt4; PIX *pixg, *pixd, *pixd1, *pixd2, *pixd3; PIXACC *pacc; PIXCMAP *cmap; static char mainName[] = "graymorph1_reg"; if (argc != 2) return ERROR_INT(" Syntax: graymorph1_reg filein", mainName, 1); filein = argv[1]; if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pixs not made", mainName, 1); pixGetDimensions(pixs, &w, &h, &d); if (d != 8) return ERROR_INT("pixs not 8 bpp", mainName, 1); /* -------- Test gray morph, including interpreter ------------ */ pixd = pixDilateGray(pixs, WSIZE, HSIZE); sprintf(dilateseq, "D%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, dilateseq, HORIZ_SEP, 0); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixErodeGray(pixs, WSIZE, HSIZE); sprintf(erodeseq, "E%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, erodeseq, HORIZ_SEP, 100); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixOpenGray(pixs, WSIZE, HSIZE); sprintf(openseq, "O%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, openseq, HORIZ_SEP, 200); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixCloseGray(pixs, WSIZE, HSIZE); sprintf(closeseq, "C%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, closeseq, HORIZ_SEP, 300); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); sprintf(wtophatseq, "Tw%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, wtophatseq, HORIZ_SEP, 400); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); pixDestroy(&pixd); pixd = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_BLACK); sprintf(btophatseq, "Tb%d.%d", WSIZE, HSIZE); pixg = pixGrayMorphSequence(pixs, btophatseq, HORIZ_SEP, 500); pixCompare(pixd, pixg, "results are the same", "results are different"); pixDestroy(&pixg); /* ------------- Test erode/dilate duality -------------- */ pixd = pixDilateGray(pixs, WSIZE, HSIZE); pixInvert(pixs, pixs); pixd2 = pixErodeGray(pixs, WSIZE, HSIZE); pixInvert(pixd2, pixd2); pixCompare(pixd, pixd2, "results are the same", "results are different"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ------------- Test open/close duality -------------- */ pixd = pixOpenGray(pixs, WSIZE, HSIZE); pixInvert(pixs, pixs); pixd2 = pixCloseGray(pixs, WSIZE, HSIZE); pixInvert(pixd2, pixd2); pixCompare(pixd, pixd2, "results are the same", "results are different"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ------------- Test tophat duality -------------- */ pixd = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_WHITE); pixInvert(pixs, pixs); pixd2 = pixTophat(pixs, WSIZE, HSIZE, L_TOPHAT_BLACK); pixCompare(pixd, pixd2, "Correct: images are duals", "Error: images are not duals"); pixDestroy(&pixd); pixDestroy(&pixd2); pixInvert(pixs, pixs); pixd = pixGrayMorphSequence(pixs, "Tw9.5", HORIZ_SEP, 100); pixInvert(pixs, pixs); pixd2 = pixGrayMorphSequence(pixs, "Tb9.5", HORIZ_SEP, 300); pixCompare(pixd, pixd2, "Correct: images are duals", "Error: images are not duals"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ------------- Test opening/closing for large sels -------------- */ pixd = pixGrayMorphSequence(pixs, "C9.9 + C19.19 + C29.29 + C39.39 + C49.49", HORIZ_SEP, 100); pixDestroy(&pixd); pixd = pixGrayMorphSequence(pixs, "O9.9 + O19.19 + O29.29 + O39.39 + O49.49", HORIZ_SEP, 400); pixDestroy(&pixd); /* ---------- Closing plus white tophat result ------------ * * Parameters: wsize, hsize = 9, 29 * * ---------------------------------------------------------*/ pixd = pixCloseGray(pixs, 9, 9); pixd1 = pixTophat(pixd, 9, 9, L_TOPHAT_WHITE); pixd2 = pixGrayMorphSequence(pixs, "C9.9 + TW9.9", HORIZ_SEP, 0); pixCompare(pixd1, pixd2, "correct: same", "wrong: different"); pixd3 = pixMaxDynamicRange(pixd1, L_LINEAR_SCALE); pixDisplayWrite(pixd3, 1); pixDestroy(&pixd); pixDestroy(&pixd1); pixDestroy(&pixd2); pixDestroy(&pixd3); pixd = pixCloseGray(pixs, 29, 29); pixd1 = pixTophat(pixd, 29, 29, L_TOPHAT_WHITE); pixd2 = pixGrayMorphSequence(pixs, "C29.29 + Tw29.29", HORIZ_SEP, 0); pixCompare(pixd1, pixd2, "correct: same", "wrong: different"); pixd3 = pixMaxDynamicRange(pixd1, L_LINEAR_SCALE); pixDisplayWrite(pixd3, 1); pixDestroy(&pixd); pixDestroy(&pixd1); pixDestroy(&pixd2); pixDestroy(&pixd3); /* --------- hdome with parameter height = 100 ------------*/ pixd = pixHDome(pixs, 100, 4); pixd2 = pixMaxDynamicRange(pixd, L_LINEAR_SCALE); pixDisplayWrite(pixd2, 1); pixDestroy(&pixd2); /* ----- Contrast enhancement with morph parameters 9, 9 -------*/ pixd1 = pixInitAccumulate(w, h, 0x8000); pixAccumulate(pixd1, pixs, L_ARITH_ADD); pixMultConstAccumulate(pixd1, 3., 0x8000); pixd2 = pixOpenGray(pixs, 9, 9); pixAccumulate(pixd1, pixd2, L_ARITH_SUBTRACT); pixDestroy(&pixd2); pixd2 = pixCloseGray(pixs, 9, 9); pixAccumulate(pixd1, pixd2, L_ARITH_SUBTRACT); pixDestroy(&pixd2); pixd = pixFinalAccumulate(pixd1, 0x8000, 8); pixDisplayWrite(pixd, 1); pixDestroy(&pixd1); /* Do the same thing with the Pixacc */ pacc = pixaccCreate(w, h, 1); pixaccAdd(pacc, pixs); pixaccMultConst(pacc, 3.); pixd1 = pixOpenGray(pixs, 9, 9); pixaccSubtract(pacc, pixd1); pixDestroy(&pixd1); pixd1 = pixCloseGray(pixs, 9, 9); pixaccSubtract(pacc, pixd1); pixDestroy(&pixd1); pixd2 = pixaccFinal(pacc, 8); pixaccDestroy(&pacc); pixDisplayWrite(pixd2, 1); pixCompare(pixd, pixd2, "Correct: same", "Wrong: different"); pixDestroy(&pixd); pixDestroy(&pixd2); /* ---- Tophat result on feynman stamp, to extract diagrams ----- */ pixDestroy(&pixs); pixs = pixRead("feynman-stamp.jpg"); /* Make output image to hold five intermediate images */ w = pixGetWidth(pixs); h = pixGetHeight(pixs); pixd = pixCreate(5 * w + 18, h + 6, 32); /* composite output image */ pixSetAllArbitrary(pixd, 0x0000ff00); /* set to blue */ /* Paste in the input image */ pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR); pixRasterop(pixd, 3, 3, w, h, PIX_SRC, pixt, 0, 0); /* 1st one */ /* pixWrite("/tmp/junkgray.jpg", pixt, IFF_JFIF_JPEG); */ pixDestroy(&pixt); /* Paste in the grayscale version */ cmap = pixGetColormap(pixs); if (cmap) pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE); else pixt = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33); pixt2 = pixConvertTo32(pixt); /* 8 --> 32 bpp */ pixRasterop(pixd, w + 6, 3, w, h, PIX_SRC, pixt2, 0, 0); /* 2nd one */ pixDestroy(&pixt2); /* Paste in a log dynamic range scaled version of the white tophat */ pixt2 = pixTophat(pixt, 3, 3, L_TOPHAT_WHITE); pixt3a = pixMaxDynamicRange(pixt2, L_LOG_SCALE); pixt3 = pixConvertTo32(pixt3a); pixRasterop(pixd, 2 * w + 9, 3, w, h, PIX_SRC, pixt3, 0, 0); /* 3rd */ /* pixWrite("/tmp/junktophat.jpg", pixt2, IFF_JFIF_JPEG); */ pixDestroy(&pixt3); pixDestroy(&pixt3a); pixDestroy(&pixt); /* Stretch the range and threshold to binary; paste it in */ pixt3a = pixGammaTRC(NULL, pixt2, 1.0, 0, 80); pixt3 = pixThresholdToBinary(pixt3a, 70); pixt4 = pixConvertTo32(pixt3); pixRasterop(pixd, 3 * w + 12, 3, w, h, PIX_SRC, pixt4, 0, 0); /* 4th */ /* pixWrite("/tmp/junkbin.png", pixt3, IFF_PNG); */ pixDestroy(&pixt2); pixDestroy(&pixt3a); pixDestroy(&pixt4); /* Invert; this is the final result */ pixInvert(pixt3, pixt3); pixt4 = pixConvertTo32(pixt3); pixRasterop(pixd, 4 * w + 15, 3, w, h, PIX_SRC, pixt4, 0, 0); /* 5th */ pixWrite("/tmp/junkbininvert.png", pixt3, IFF_PNG); pixDisplayWrite(pixd, 1); /* pixWrite("/tmp/junkall.jpg", pixd, IFF_JFIF_JPEG); */ pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixd); pixDisplayMultiple("/tmp/display/file*"); pixDestroy(&pixs); 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) { const char nametif[] = "/tmp/junk_convert_ps_embed.tif"; const char namejpg[] = "/tmp/junk_convert_ps_embed.jpg"; l_int32 d, format; FILE *fp; 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", 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 */ if ((fp = fopen(filein, "rb")) == NULL) return ERROR_INT("filein not found", procName, 1); findFileFormat(fp, &format); fclose(fp); if (format == IFF_JFIF_JPEG) { convertJpegToPSEmbed(filein, fileout); return 0; } else if (format == IFF_TIFF_G4) { convertTiffG4ToPSEmbed(filein, fileout); return 0; } /* 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); if (d == 1) { pixWrite(nametif, pix, IFF_TIFF_G4); convertTiffG4ToPSEmbed(nametif, fileout); } else { pixWrite(namejpg, pix, IFF_JFIF_JPEG); convertJpegToPSEmbed(namejpg, fileout); } pixDestroy(&pix); pixDestroy(&pixs); return 0; }
/*! * pixWriteMemWebP() * * Input: &encdata (<return> webp encoded data of pixs) * &encsize (<return> size of webp encoded data) * pixs (any depth, cmapped OK) * quality (0 - 100; default ~80) * lossless (use 1 for lossless; 0 for lossy) * Return: 0 if OK, 1 on error * * Notes: * (1) Lossless and lossy encoding are entirely different in webp. * @quality applies to lossy, and is ignored for lossless. * (2) The input image is converted to RGB if necessary. If spp == 3, * we set the alpha channel to fully opaque (255), and * WebPEncodeRGBA() then removes the alpha chunk when encoding, * setting the internal header field has_alpha to 0. */ l_int32 pixWriteMemWebP(l_uint8 **pencdata, size_t *pencsize, PIX *pixs, l_int32 quality, l_int32 lossless) { l_int32 w, h, d, wpl, stride; l_uint32 *data; PIX *pix1, *pix2; PROCNAME("pixWriteMemWebP"); if (!pencdata) return ERROR_INT("&encdata not defined", procName, 1); *pencdata = NULL; if (!pencsize) return ERROR_INT("&encsize not defined", procName, 1); *pencsize = 0; if (!pixs) return ERROR_INT("&pixs not defined", procName, 1); if (lossless == 0 && (quality < 0 || quality > 100)) return ERROR_INT("quality not in [0 ... 100]", procName, 1); if ((pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL) return ERROR_INT("failure to remove color map", procName, 1); /* Convert to rgb if not 32 bpp; pix2 must not be a clone of pixs. */ if (pixGetDepth(pix1) != 32) pix2 = pixConvertTo32(pix1); else pix2 = pixCopy(NULL, pix1); pixDestroy(&pix1); pixGetDimensions(pix2, &w, &h, &d); if (w <= 0 || h <= 0 || d != 32) { pixDestroy(&pix2); return ERROR_INT("pix2 not 32 bpp or of 0 size", procName, 1); } /* If spp == 3, need to set alpha layer to opaque (all 1s). */ if (pixGetSpp(pix2) == 3) pixSetComponentArbitrary(pix2, L_ALPHA_CHANNEL, 255); /* Webp encoder assumes big-endian byte order for RGBA components */ pixEndianByteSwap(pix2); wpl = pixGetWpl(pix2); data = pixGetData(pix2); stride = wpl * 4; if (lossless) { *pencsize = WebPEncodeLosslessRGBA((uint8_t *)data, w, h, stride, pencdata); } else { *pencsize = WebPEncodeRGBA((uint8_t *)data, w, h, stride, quality, pencdata); } pixDestroy(&pix2); if (*pencsize == 0) { free(pencdata); *pencdata = NULL; return ERROR_INT("webp encoding failed", procName, 1); } return 0; }
int main(int argc, char **argv) { char textstr[256]; l_int32 w, h, d, i; l_uint32 srcval, dstval; l_float32 scalefact, sat, fract; L_BMF *bmf8; L_KERNEL *kel; NUMA *na; PIX *pix, *pixs, *pixs1, *pixs2, *pixd; PIX *pixt0, *pixt1, *pixt2, *pixt3, *pixt4; PIXA *pixa, *pixaf; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pix = pixRead(filein); pixGetDimensions(pix, &w, &h, &d); if (d != 32) return ERROR_INT("file not 32 bpp", argv[0], 1); scalefact = (l_float32)WIDTH / (l_float32)w; pixs = pixScale(pix, scalefact, scalefact); w = pixGetWidth(pixs); pixaf = pixaCreate(5); /* TRC: vary gamma */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixGammaTRC(NULL, pixs, 0.3 + 0.15 * i, 0, 255); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 32); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 0 */ pixDisplayWithTitle(pixt1, 0, 100, "TRC Gamma", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* TRC: vary black point */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixGammaTRC(NULL, pixs, 1.0, 5 * i, 255); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 1 */ pixDisplayWithTitle(pixt1, 300, 100, "TRC", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary hue */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixModifyHue(NULL, pixs, 0.01 + 0.05 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 2 */ pixDisplayWithTitle(pixt1, 600, 100, "Hue", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary saturation */ pixa = pixaCreate(20); na = numaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixModifySaturation(NULL, pixs, -0.9 + 0.1 * i); pixMeasureSaturation(pixt0, 1, &sat); pixaAddPix(pixa, pixt0, L_INSERT); numaAddNumber(na, sat); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); gplotSimple1(na, GPLOT_PNG, "/tmp/regout/enhance.7", "Average Saturation"); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 3 */ pixDisplayWithTitle(pixt1, 900, 100, "Saturation", rp->display); numaDestroy(&na); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary contrast */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixContrastTRC(NULL, pixs, 0.1 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 4 */ pixDisplayWithTitle(pixt1, 0, 400, "Contrast", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary sharpening */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixUnsharpMasking(pixs, 3, 0.01 + 0.15 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 5 */ pixDisplayWithTitle(pixt1, 300, 400, "Sharp", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Hue constant mapping to lighter background */ pixa = pixaCreate(11); bmf8 = bmfCreate("fonts", 8); pixt0 = pixRead("candelabrum-11.jpg"); composeRGBPixel(230, 185, 144, &srcval); /* select typical bg pixel */ for (i = 0; i <= 10; i++) { fract = 0.10 * i; pixelFractionalShift(230, 185, 144, fract, &dstval); pixt1 = pixLinearMapToTargetColor(NULL, pixt0, srcval, dstval); snprintf(textstr, 50, "Fract = %5.1f", fract); pixt2 = pixAddSingleTextblock(pixt1, bmf8, textstr, 0xff000000, L_ADD_BELOW, NULL); pixSaveTiledOutline(pixt2, pixa, 1.0, (i % 4 == 0) ? 1 : 0, 30, 2, 32); pixDestroy(&pixt1); pixDestroy(&pixt2); } pixDestroy(&pixt0); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 6 */ pixDisplayWithTitle(pixd, 600, 400, "Constant hue", rp->display); bmfDestroy(&bmf8); pixaDestroy(&pixa); pixDestroy(&pixd); /* Delayed testing of saturation plot */ regTestCheckFile(rp, "/tmp/regout/enhance.7.png"); /* 7 */ /* Display results */ pixd = pixaDisplay(pixaf, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 8 */ pixDisplayWithTitle(pixd, 100, 100, "All", rp->display); pixDestroy(&pixd); pixaDestroy(&pixaf); pixDestroy(&pix); pixDestroy(&pixs); /* -----------------------------------------------* * Test global color transforms * * -----------------------------------------------*/ /* Make identical cmap and rgb images */ pix = pixRead("wet-day.jpg"); pixs1 = pixOctreeColorQuant(pix, 200, 0); pixs2 = pixRemoveColormap(pixs1, REMOVE_CMAP_TO_FULL_COLOR); regTestComparePix(rp, pixs1, pixs2); /* 9 */ /* Make a diagonal color transform matrix */ kel = kernelCreate(3, 3); kernelSetElement(kel, 0, 0, 0.7); kernelSetElement(kel, 1, 1, 0.4); kernelSetElement(kel, 2, 2, 1.3); /* Apply to both cmap and rgb images. */ pixt1 = pixMultMatrixColor(pixs1, kel); pixt2 = pixMultMatrixColor(pixs2, kel); regTestComparePix(rp, pixt1, pixt2); /* 10 */ kernelDestroy(&kel); /* Apply the same transform in the simpler interface */ pixt3 = pixMultConstantColor(pixs1, 0.7, 0.4, 1.3); pixt4 = pixMultConstantColor(pixs2, 0.7, 0.4, 1.3); regTestComparePix(rp, pixt3, pixt4); /* 11 */ regTestComparePix(rp, pixt1, pixt3); /* 12 */ regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 13 */ pixDestroy(&pix); pixDestroy(&pixs1); pixDestroy(&pixs2); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); return regTestCleanup(rp); }