Example #1
0
static l_int32
test_1bpp_color(L_REGPARAMS  *rp)
{
l_int32   same, transp;
FILE     *fp;
PIX      *pix1, *pix2;
PIXCMAP  *cmap;

    pix1 = pixRead("feyn-fract2.tif");
    cmap = pixcmapCreate(1);
    pixSetColormap(pix1, cmap);
    pixcmapAddRGBA(cmap, 180, 130, 220, 255);  /* color, opaque */
    pixcmapAddRGBA(cmap, 20, 120, 0, 255);  /* color, opaque */
    pixWrite("/tmp/regout/1bpp-color.png", pix1, IFF_PNG);
    pix2 = pixRead("/tmp/regout/1bpp-color.png");
    pixEqual(pix1, pix2, &same);
    if (same)
        fprintf(stderr, "1bpp_color: success\n");
    else
        fprintf(stderr, "1bpp_color: bad output\n");
    pixDisplayWithTitle(pix2, 700, 100, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    fp = fopenReadStream("/tmp/regout/1bpp-color.png");
    fgetPngColormapInfo(fp, &cmap, &transp);
    fclose(fp);
    if (transp)
        fprintf(stderr, "1bpp_color: error -- transparency found!\n");
    else
        fprintf(stderr, "1bpp_color: correct -- no transparency found\n");
    if (rp->display) pixcmapWriteStream(stderr, cmap);
    pixcmapDestroy(&cmap);
    return same;
}
/*!
 *  pixCopyColormap()
 *
 *      Input:  src and dest Pix
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This always destroys any colormap in pixd (except if
 *          the operation is a no-op.
 */
l_int32
pixCopyColormap(PIX  *pixd,
                PIX  *pixs)
{
PIXCMAP  *cmaps, *cmapd;

    PROCNAME("pixCopyColormap");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (!pixd)
        return ERROR_INT("pixd not defined", procName, 1);
    if (pixs == pixd)
        return 0;   /* no-op */

    pixDestroyColormap(pixd);
    if ((cmaps = pixGetColormap(pixs)) == NULL)  /* not an error */
        return 0;

    if ((cmapd = pixcmapCopy(cmaps)) == NULL)
        return ERROR_INT("cmapd not made", procName, 1);
    pixSetColormap(pixd, cmapd);

    return 0;
}
Example #3
0
/*!
 *  pixDisplayHitMissSel()
 *
 *      Input:  pixs (1 bpp)
 *              sel (hit-miss in general)
 *              scalefactor (an integer >= 1; use 0 for default)
 *              hitcolor (RGB0 color for center of hit pixels)
 *              misscolor (RGB0 color for center of miss pixels)
 *      Return: pixd (RGB showing both pixs and sel), or null on error
 *  Notes:
 *    (1) We don't allow scalefactor to be larger than MAX_SEL_SCALEFACTOR
 *    (2) The colors are conveniently given as 4 bytes in hex format,
 *        such as 0xff008800.  The least significant byte is ignored.
 */
PIX *
pixDisplayHitMissSel(PIX      *pixs,
                     SEL      *sel,
                     l_int32   scalefactor,
                     l_uint32  hitcolor,
                     l_uint32  misscolor)
{
l_int32    i, j, type;
l_float32  fscale;
PIX       *pixt, *pixd;
PIXCMAP   *cmap;

    PROCNAME("pixDisplayHitMissSel");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 1)
        return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
    if (!sel)
        return (PIX *)ERROR_PTR("sel not defined", procName, NULL);

    if (scalefactor <= 0)
        scalefactor = DEFAULT_SEL_SCALEFACTOR;
    if (scalefactor > MAX_SEL_SCALEFACTOR) {
        L_WARNING("scalefactor too large; using max value", procName);
        scalefactor = MAX_SEL_SCALEFACTOR;
    }

        /* Generate a version of pixs with a colormap */
    pixt = pixConvert1To8(NULL, pixs, 0, 1);
    cmap = pixcmapCreate(8);
    pixcmapAddColor(cmap, 255, 255, 255);
    pixcmapAddColor(cmap, 0, 0, 0);
    pixcmapAddColor(cmap, hitcolor >> 24, (hitcolor >> 16) & 0xff,
                    (hitcolor >> 8) & 0xff);
    pixcmapAddColor(cmap, misscolor >> 24, (misscolor >> 16) & 0xff,
                    (misscolor >> 8) & 0xff);
    pixSetColormap(pixt, cmap);

        /* Color the hits and misses */
    for (i = 0; i < sel->sy; i++) {
        for (j = 0; j < sel->sx; j++) {
            selGetElement(sel, i, j, &type);
            if (type == SEL_DONT_CARE)
                continue;
            if (type == SEL_HIT)
                pixSetPixel(pixt, j, i, 2);
            else  /* type == SEL_MISS */
                pixSetPixel(pixt, j, i, 3);
        }
    }

        /* Scale it up */
    fscale = (l_float32)scalefactor;
    pixd = pixScaleBySampling(pixt, fscale, fscale);

    pixDestroy(&pixt);
    return pixd;
}
Example #4
0
/*!
 * \brief   pixColorSegmentCluster()
 *
 * \param[in]    pixs  32 bpp; 24-bit color
 * \param[in]    maxdist max euclidean dist to existing cluster
 * \param[in]    maxcolors max number of colors allowed in first pass
 * \param[in]    debugflag  1 for debug output; 0 otherwise
 * \return  pixd 8 bit with colormap, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) This is phase 1.  See description in pixColorSegment().
 *      (2) Greedy unsupervised classification.  If the limit 'maxcolors'
 *          is exceeded, the computation is repeated with a larger
 *          allowed cluster size.
 *      (3) On each successive iteration, 'maxdist' is increased by a
 *          constant factor.  See comments in pixColorSegment() for
 *          a guideline on parameter selection.
 *          Note that the diagonal of the 8-bit rgb color cube is about
 *          440, so for 'maxdist' = 440, you are guaranteed to get 1 color!
 * </pre>
 */
PIX *
pixColorSegmentCluster(PIX     *pixs,
                       l_int32  maxdist,
                       l_int32  maxcolors,
                       l_int32  debugflag)
{
l_int32   w, h, newmaxdist, ret, niters, ncolors, success;
PIX      *pixd;
PIXCMAP  *cmap;

    PROCNAME("pixColorSegmentCluster");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 32)
        return (PIX *)ERROR_PTR("must be rgb color", procName, NULL);

    pixGetDimensions(pixs, &w, &h, NULL);
    if ((pixd = pixCreate(w, h, 8)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    cmap = pixcmapCreate(8);
    pixSetColormap(pixd, cmap);
    pixCopyResolution(pixd, pixs);

    newmaxdist = maxdist;
    niters = 0;
    success = TRUE;
    while (1) {
        ret = pixColorSegmentTryCluster(pixd, pixs, newmaxdist,
                                        maxcolors, debugflag);
        niters++;
        if (!ret) {
            ncolors = pixcmapGetCount(cmap);
            if (debugflag)
                L_INFO("Success with %d colors after %d iters\n", procName,
                       ncolors, niters);
            break;
        }
        if (niters == MAX_ALLOWED_ITERATIONS) {
            L_WARNING("too many iters; newmaxdist = %d\n",
                      procName, newmaxdist);
            success = FALSE;
            break;
        }
        newmaxdist = (l_int32)(DIST_EXPAND_FACT * (l_float32)newmaxdist);
    }

    if (!success) {
        pixDestroy(&pixd);
        return (PIX *)ERROR_PTR("failure in phase 1", procName, NULL);
    }

    return pixd;
}
Example #5
0
/*!
 *  pixaDisplayRandomCmap()
 *
 *      Input:  pixa (of 1 bpp components, with boxa)
 *              w, h (if set to 0, determines the size from the
 *                    b.b. of the components in pixa)
 *      Return: pix (8 bpp, cmapped, with random colors on the components),
 *              or null on error
 *
 *  Notes:
 *      (1) This uses the boxes to place each pix in the rendered composite.
 *      (2) By default, the background color is: black, cmap index 0.
 *          This can be changed by pixcmapResetColor()
 */
PIX *
pixaDisplayRandomCmap(PIXA    *pixa,
                      l_int32  w,
                      l_int32  h)
{
l_int32   i, n, d, index, xb, yb, wb, hb;
BOXA     *boxa;
PIX      *pixs, *pixt, *pixd;
PIXCMAP  *cmap;

    PROCNAME("pixaDisplayRandomCmap");

    if (!pixa)
        return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
    
    n = pixaGetCount(pixa);
    if (n == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);

        /* Use the first pix in pixa to verify depth is 1 bpp  */
    pixs = pixaGetPix(pixa, 0, L_CLONE);
    d = pixGetDepth(pixs);
    pixDestroy(&pixs);
    if (d != 1)
        return (PIX *)ERROR_PTR("components not 1 bpp", procName, NULL);

        /* If w and h not input, determine the minimum size required
         * to contain the origin and all c.c. */
    if (w == 0 || h == 0) {
        boxa = pixaGetBoxa(pixa, L_CLONE);
        boxaGetExtent(boxa, &w, &h, NULL);
        boxaDestroy(&boxa);
    }

        /* Set up an 8 bpp dest pix, with a colormap with 254 random colors */
    if ((pixd = pixCreate(w, h, 8)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    cmap = pixcmapCreateRandom(8, 1, 1);
    pixSetColormap(pixd, cmap);

        /* Color each component and blit it in */
    for (i = 0; i < n; i++) {
        index = 1 + (i % 254);
        pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
        pixs = pixaGetPix(pixa, i, L_CLONE);
        pixt = pixConvert1To8(NULL, pixs, 0, index);
        pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pixt, 0, 0);
        pixDestroy(&pixs);
        pixDestroy(&pixt);
    }

    return pixd;
}
/*!
 *  pixTransferAllData()
 *
 *      Input:  pixd (must be different from pixs)
 *              &pixs (will be nulled if refcount goes to 0)
 *              copytext (1 to copy the text field; 0 to skip)
 *              copyformat (1 to copy the informat field; 0 to skip)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This does a complete data transfer from pixs to pixd,
 *          followed by the destruction of pixs (refcount permitting).
 *      (2) If the refcount of pixs is 1, pixs is destroyed.  Otherwise,
 *          the data in pixs is copied (rather than transferred) to pixd.
 *      (3) This operation, like all others with a pre-existing pixd,
 *          will side-effect any existing clones of pixd.  The pixd
 *          refcount does not change.
 *      (4) When might you use this?  Suppose you have an in-place Pix
 *          function (returning void) with the typical signature:
 *              void function-inplace(PIX *pix, ...)
 *          where "..." are non-pointer input parameters, and suppose
 *          further that you sometimes want to return an arbitrary Pix
 *          in place of the input Pix.  There are two ways you can do this:
 *          (a) The straightforward way is to change the function
 *              signature to take the address of the Pix ptr:
 *                  void function-inplace(PIX **ppix, ...) {
 *                      PIX *pixt = function-makenew(*ppix);
 *                      pixDestroy(ppix);
 *                      *ppix = pixt;
 *                      return;
 *                  }
 *              Here, the input and returned pix are different, as viewed
 *              by the calling function, and the inplace function is
 *              expected to destroy the input pix to avoid a memory leak.
 *          (b) Keep the signature the same and use pixTransferAllData()
 *              to return the new Pix in the input Pix struct:
 *                  void function-inplace(PIX *pix, ...) {
 *                      PIX *pixt = function-makenew(pix);
 *                      pixTransferAllData(pix, &pixt);  // pixt is destroyed
 *                      return;
 *                  }
 *              Here, the input and returned pix are the same, as viewed
 *              by the calling function, and the inplace function must
 *              never destroy the input pix, because the calling function
 *              maintains an unchanged handle to it.
 */
l_int32
pixTransferAllData(PIX     *pixd,
                   PIX    **ppixs,
                   l_int32  copytext,
                   l_int32  copyformat)
{
l_int32  nbytes;
PIX     *pixs;

    PROCNAME("pixTransferAllData");

    if (!ppixs)
        return ERROR_INT("&pixs not defined", procName, 1);
    if ((pixs = *ppixs) == NULL)
        return ERROR_INT("pixs not defined", procName, 1);
    if (!pixd)
        return ERROR_INT("pixd not defined", procName, 1);
    if (pixs == pixd)  /* no-op */
        return ERROR_INT("pixd == pixs", procName, 1);

    if (pixGetRefcount(pixs) == 1) {  /* transfer the data, cmap, text */
        pixFreeData(pixd);  /* dealloc any existing data */
        pixSetData(pixd, pixGetData(pixs));  /* transfer new data from pixs */
        pixs->data = NULL;  /* pixs no longer owns data */
        pixSetColormap(pixd, pixGetColormap(pixs));  /* frees old; sets new */
        pixs->colormap = NULL;  /* pixs no longer owns colormap */
        if (copytext) {
            pixSetText(pixd, pixGetText(pixs));
            pixSetText(pixs, NULL);
        }
    } else {  /* preserve pixs by making a copy of the data, cmap, text */
        pixResizeImageData(pixd, pixs);
        nbytes = 4 * pixGetWpl(pixs) * pixGetHeight(pixs);
        memcpy((char *)pixGetData(pixd), (char *)pixGetData(pixs), nbytes);
        pixCopyColormap(pixd, pixs);
        if (copytext)
            pixCopyText(pixd, pixs);
    }
  
    pixCopyResolution(pixd, pixs);
    pixCopyDimensions(pixd, pixs);
    if (copyformat)
        pixCopyInputFormat(pixd, pixs);

        /* This will destroy pixs if data was transferred;
         * otherwise, it just decrements its refcount. */
    pixDestroy(ppixs);
    return 0;
}
Example #7
0
/*!
 *  pixDeserializeFromMemory()
 *
 *      Input:  data (serialized data in memory)
 *              nbytes (number of bytes in data string)
 *      Return: pix, or NULL on error
 *
 *  Notes:
 *      (1) See pixSerializeToMemory() for the binary format.
 */
PIX *
pixDeserializeFromMemory(const l_uint32  *data,
                         size_t           nbytes)
{
char      *id;
l_int32    w, h, d, imdatasize, ncolors;
l_uint32  *imdata;  /* data in pix raster */
PIX       *pixd;
PIXCMAP   *cmap;

    PROCNAME("pixDeserializeFromMemory");

    if (!data)
        return (PIX *)ERROR_PTR("data not defined", procName, NULL);
    if (nbytes < 28)
        return (PIX *)ERROR_PTR("invalid data", procName, NULL);

    id = (char *)data;
    if (id[0] != 's' || id[1] != 'p' || id[2] != 'i' || id[3] != 'x')
        return (PIX *)ERROR_PTR("invalid id string", procName, NULL);
    w = data[1];
    h = data[2];
    d = data[3];
    if ((pixd = pixCreate(w, h, d)) == NULL)
        return (PIX *)ERROR_PTR("pix not made", procName, NULL);

    ncolors = data[5];
    if (ncolors > 0) {
        cmap = pixcmapDeserializeFromMemory((l_uint8 *)(&data[6]), 4, ncolors);
        if (!cmap)
            return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
        pixSetColormap(pixd, cmap);
    }

    imdata = pixGetData(pixd);
    imdatasize = nbytes - 24 - 4 * ncolors - 4;
    if (imdatasize != data[6 + ncolors])
        L_ERROR("imdatasize is inconsistent with nbytes\n", procName);
    memcpy((char *)imdata, (char *)(data + 7 + ncolors), imdatasize);

#if  DEBUG_SERIALIZE
    fprintf(stderr, "Deserialize: "
            "raster size = %d, ncolors in cmap = %d, total bytes = %lu\n",
            imdatasize, ncolors, nbytes);
#endif  /* DEBUG_SERIALIZE */

    return pixd;
}
Example #8
0
static l_int32
test_1bpp_bw2(L_REGPARAMS  *rp)
{
l_int32   same;
PIX      *pix1, *pix2;
PIXCMAP  *cmap;

    pix1 = pixRead("feyn-fract2.tif");
    cmap = pixcmapCreate(1);
    pixSetColormap(pix1, cmap);
    pixcmapAddRGBA(cmap, 255, 255, 255, 255);  /* white, opaque */
    pixcmapAddRGBA(cmap, 0, 0, 0, 255);  /* black, opaque */
    pixWrite("/tmp/regout/1bpp-bw2.png", pix1, IFF_PNG);
    pix2 = pixRead("/tmp/regout/1bpp-bw2.png");
    pixEqual(pix1, pix2, &same);
    if (same)
        fprintf(stderr, "1bpp_bw2: success\n");
    else
        fprintf(stderr, "1bpp_bw2: bad output\n");
    pixDisplayWithTitle(pix2, 700, 400, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    return same;
}
Example #9
0
static PIX *
FakeReconstructByBand(L_REGPARAMS  *rp,
                      const char   *fname)
{
l_int32   i, jlow, jup, n, nbands;
l_int32   rval1, gval1, bval1, rval2, gval2, bval2, rval, gval, bval;
PIX      *pixs, *pixm, *pixd;
PIXCMAP  *cmaps, *cmapd;

    pixs = pixRead(fname);
    cmaps = pixGetColormap(pixs);
    n = pixcmapGetCount(cmaps);
    nbands = (n + 1) / 2;
    pixd = pixCreateTemplate(pixs);
    cmapd = pixcmapCreate(pixGetDepth(pixs));
    pixSetColormap(pixd, cmapd);
    for (i = 0; i < nbands; i++) {
        jlow = 2 * i;
        jup = L_MIN(jlow + 1, n - 1);
        pixm = pixGenerateMaskByBand(pixs, jlow, jup, 1, 1);

            /* Get average color in the band */
        pixcmapGetColor(cmaps, jlow, &rval1, &gval1, &bval1);
        pixcmapGetColor(cmaps, jup, &rval2, &gval2, &bval2);
        rval = (rval1 + rval2) / 2;
        gval = (gval1 + gval2) / 2;
        bval = (bval1 + bval2) / 2;

        pixcmapAddColor(cmapd, rval, gval, bval);
        pixSetMaskedCmap(pixd, pixm, 0, 0, rval, gval, bval);
        pixDestroy(&pixm);
    }

    pixDestroy(&pixs);
    return pixd;
}
Example #10
0
main(int    argc,
     char **argv)
{
l_int32       i, w, h, bx, by, bw, bh, index, rval, gval, bval;
BOX          *box;
BOXA         *boxa;
PIX          *pixm, *pixs, *pixg, *pixt, *pixd;
PIXA         *pixa;
PIXCMAP      *cmap;
PTA          *pta;
PTAA         *ptaa;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
	return 1;
    pixa = pixaCreate(0);

    /* ---------------- Shortest path in binary maze ---------------- */
        /* Generate the maze */
    pixm = generateBinaryMaze(200, 200, 20, 20, 0.65, 0.25);
    pixd = pixExpandBinaryReplicate(pixm, 3);
    pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32);
    pixDestroy(&pixd);

        /* Find the shortest path between two points */
    pta = pixSearchBinaryMaze(pixm, 20, 20, 170, 170, NULL);
    pixt = pixDisplayPta(NULL, pixm, pta);
    pixd = pixScaleBySampling(pixt, 3., 3.);
    pixSaveTiledOutline(pixd, pixa, 1, 0, 20, 2, 32);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 0 */
    ptaDestroy(&pta);
    pixDestroy(&pixt);
    pixDestroy(&pixd);
    pixDestroy(&pixm);


    /* ---------------- Shortest path in gray maze ---------------- */
    pixg = pixRead("test8.jpg");
    pixGetDimensions(pixg, &w, &h, NULL);
    ptaa = ptaaCreate(NPATHS);
    for (i = 0; i < NPATHS; i++) {
        if (x0[i] >= w || x1[i] >= w || y0[i] >= h || y1[i] >= h) {
            fprintf(stderr, "path %d extends beyond image; skipping\n", i);
            continue;
        }
        pta = pixSearchGrayMaze(pixg, x0[i], y0[i], x1[i], y1[i], NULL);
        ptaaAddPta(ptaa, pta, L_INSERT);
    }

    pixt = pixDisplayPtaa(pixg, ptaa);
    pixd = pixScaleBySampling(pixt, 2., 2.);
    pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 1 */
    ptaaDestroy(&ptaa);
    pixDestroy(&pixg);
    pixDestroy(&pixt);
    pixDestroy(&pixd);


    /* ---------------- Largest rectangles in image ---------------- */
    pixs = pixRead("test1.png");
    pixd = pixConvertTo8(pixs, FALSE);
    cmap = pixcmapCreateRandom(8, 1, 1);
    pixSetColormap(pixd, cmap);

    boxa = boxaCreate(0);
    for (i = 0; i < NBOXES; i++) {
        pixFindLargestRectangle(pixs, POLARITY, &box, NULL);
        boxGetGeometry(box, &bx, &by, &bw, &bh);
        pixSetInRect(pixs, box);
        fprintf(stderr, "bx = %5d, by = %5d, bw = %5d, bh = %5d, area = %d\n",
                bx, by, bw, bh, bw * bh);
        boxaAddBox(boxa, box, L_INSERT);
    }

    for (i = 0; i < NBOXES; i++) {
        index = 32 + (i & 254);
        pixcmapGetColor(cmap, index, &rval, &gval, &bval);
        box = boxaGetBox(boxa, i, L_CLONE);
        pixRenderHashBoxArb(pixd, box, 6, 2, L_NEG_SLOPE_LINE, 1,
                            rval, gval, bval);
        boxDestroy(&box);
    }
    pixSaveTiledOutline(pixd, pixa, 1, 1, 20, 2, 32);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 2 */
    pixDestroy(&pixs);
    pixDestroy(&pixd);
    boxaDestroy(&boxa);

    pixd = pixaDisplay(pixa, 0, 0);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 3 */
    pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    return regTestCleanup(rp);
}
Example #11
0
/*!
 *  pixReadStreamJpeg()
 *
 *      Input:  stream
 *              colormap flag (0 means return RGB image if color;
 *                             1 means create colormap and return 8 bpp
 *                               palette image if color)
 *              reduction (scaling factor: 1, 2, 4 or 8)
 *              &pnwarn (<optional return> number of warnings)
 *              hint: (a bitwise OR of L_HINT_* values); use 0 for no hints
 *      Return: pix, or null on error
 *
 *  Usage: see pixReadJpeg()
 */
PIX *
pixReadStreamJpeg(FILE     *fp,
                  l_int32   cmflag,
                  l_int32   reduction,
                  l_int32  *pnwarn,
                  l_int32   hint)
{
l_uint8                        cyan, yellow, magenta, black, white;
l_int32                        rval, gval, bval;
l_int32                        i, j, k;
l_int32                        w, h, wpl, spp, ncolors, cindex, ycck, cmyk;
l_uint32                      *data;
l_uint32                      *line, *ppixel;
JSAMPROW                       rowbuffer;
PIX                           *pix;
PIXCMAP                       *cmap;
struct jpeg_decompress_struct  cinfo;
struct jpeg_error_mgr          jerr;
l_uint8                       *comment = NULL;

    PROCNAME("pixReadStreamJpeg");

    if (!fp)
        return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
    if (pnwarn)
        *pnwarn = 0;  /* init */
    if (cmflag != 0 && cmflag != 1)
        cmflag = 0;  /* default */
    if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
        return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", procName, NULL);

    if (BITS_IN_JSAMPLE != 8)  /* set in jmorecfg.h */
        return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", procName, NULL);

    rewind(fp);

    pix = NULL;  /* init */
    if (setjmp(jpeg_jmpbuf)) {
        pixDestroy(&pix);
        FREE(rowbuffer);
        return (PIX *)ERROR_PTR("internal jpeg error", procName, NULL);
    }

    rowbuffer = NULL;
    cinfo.err = jpeg_std_error(&jerr);
    jerr.error_exit = jpeg_error_do_not_exit; /* catch error; do not exit! */

    jpeg_create_decompress(&cinfo);

    cinfo.client_data = &comment;
    jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback);
    jpeg_stdio_src(&cinfo, fp);
    jpeg_read_header(&cinfo, TRUE);
    cinfo.scale_denom = reduction;
    cinfo.scale_num = 1;
    if (hint & L_HINT_GRAY)
        cinfo.out_color_space = JCS_GRAYSCALE;
    jpeg_calc_output_dimensions(&cinfo);

        /* Allocate the image and a row buffer */
    spp = cinfo.out_color_components;
    w = cinfo.output_width;
    h = cinfo.output_height;
    ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmflag == 0);
    cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmflag == 0);
    if (spp != 1 && spp != 3 && !ycck && !cmyk) {
        if (comment) FREE(comment);
        return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK",
                                procName, NULL);
    }
    if ((spp == 3 && cmflag == 0) || ycck || cmyk) {  /* rgb or 4 bpp color */
        rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), spp * w);
        pix = pixCreate(w, h, 32);
    }
    else {  /* 8 bpp gray or colormapped */
        rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), w);
        pix = pixCreate(w, h, 8);
    }
    if (!rowbuffer || !pix) {
        if (comment) FREE(comment);
	if (rowbuffer) FREE(rowbuffer);
	pixDestroy(&pix);
        return (PIX *)ERROR_PTR("rowbuffer or pix not made", procName, NULL);
    }

    if (comment) {
        pixSetText(pix, (char *)comment);
	FREE(comment);
    }

    if (spp == 1)  /* Grayscale or colormapped */
        jpeg_start_decompress(&cinfo);
    else  {        /* Color; spp == 3 or YCCK or CMYK */
        if (cmflag == 0) {   /* -- 24 bit color in 32 bit pix or YCCK/CMYK -- */
            cinfo.quantize_colors = FALSE;
            jpeg_start_decompress(&cinfo);
        }
        else {      /* Color quantize to 8 bits */
            cinfo.quantize_colors = TRUE;
            cinfo.desired_number_of_colors = 256;
            jpeg_start_decompress(&cinfo);

                /* Construct a pix cmap */
            cmap = pixcmapCreate(8);
            ncolors = cinfo.actual_number_of_colors;
            for (cindex = 0; cindex < ncolors; cindex++)
            {
                rval = cinfo.colormap[0][cindex];
                gval = cinfo.colormap[1][cindex];
                bval = cinfo.colormap[2][cindex];
                pixcmapAddColor(cmap, rval, gval, bval);
            }
            pixSetColormap(pix, cmap);
        }
    }
    wpl  = pixGetWpl(pix);
    data = pixGetData(pix);

        /* Decompress */
    if ((spp == 3 && cmflag == 0) || ycck || cmyk) {   /* -- 24 bit color -- */
        for (i = 0; i < h; i++) {
            if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1)
                return (PIX *)ERROR_PTR("bad read scanline", procName, NULL);
            ppixel = data + i * wpl;
            if (spp == 3) {
                for (j = k = 0; j < w; j++) {
                    SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]);
                    SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]);
                    SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]);
                    ppixel++;
                }
            } else {
                    /* This is a conversion from CMYK -> RGB that ignores
                       color profiles, and is invoked when the image header
                       claims to be in CMYK or YCCK colorspace.  If in YCCK,
                       libjpeg may be doing YCCK -> CMYK under the hood.
                       To understand why the colors are inverted on read-in,
                       see the "Special color spaces" section of
                       "Using the IJG JPEG Library" by Thomas G. Lane.  */
                for (j = k = 0; j < w; j++) {
                    cyan = 255 - rowbuffer[k++];
                    magenta = 255 - rowbuffer[k++];
                    yellow = 255 - rowbuffer[k++];
                    white = rowbuffer[k++];
                    black = 255 - white;
                    rval = 255 - (cyan    * white) / 255 - black;
                    gval = 255 - (magenta * white) / 255 - black;
                    bval = 255 - (yellow  * white) / 255 - black;
                    rval = L_MIN(L_MAX(rval, 0), 255);
                    gval = L_MIN(L_MAX(gval, 0), 255);
                    bval = L_MIN(L_MAX(bval, 0), 255);
                    composeRGBPixel(rval, gval, bval, ppixel);
                    ppixel++;
                }
            }
        }
    }
    else {    /* 8 bpp grayscale or colormapped pix */
        for (i = 0; i < h; i++) {
            if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1)
                return (PIX *)ERROR_PTR("bad read scanline", procName, NULL);
            line = data + i * wpl;
            for (j = 0; j < w; j++)
                SET_DATA_BYTE(line, j, rowbuffer[j]);
        }
    }

    if (pnwarn)
        *pnwarn = cinfo.err->num_warnings;

    switch (cinfo.density_unit)
    {
    case 1:  /* pixels per inch */
        pixSetXRes(pix, cinfo.X_density);
        pixSetYRes(pix, cinfo.Y_density);
        break;
    case 2:  /* pixels per centimeter */
        pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5));
        pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5));
        break;
    default:   /* the pixel density may not be defined; ignore */
        break;
    }

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    FREE(rowbuffer);

    return pix;
}
Example #12
0
/*!
 * \brief   pixToGif()
 *
 * \param[in]    pix 1, 2, 4, 8, 16 or 32 bpp
 * \param[in]    gif  opened gif stream
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This encodes the pix to the gif stream. The stream is not
 *          closes by this function.
 *      (2) It is static to make this function private.
 * </pre>
 */
static l_int32
pixToGif(PIX *pix, GifFileType *gif)
{
char            *text;
l_int32          wpl, i, j, w, h, d, ncolor, rval, gval, bval;
l_int32          gif_ncolor = 0;
l_uint32        *data, *line;
PIX             *pixd;
PIXCMAP         *cmap;
ColorMapObject  *gif_cmap;
GifByteType     *gif_line;
#if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5
int              giferr;
#endif  /* 5.1 and beyond */

    PROCNAME("pixToGif");

    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);
    if (!gif)
        return ERROR_INT("gif not defined", procName, 1);

    d = pixGetDepth(pix);
    if (d == 32) {
        pixd = pixConvertRGBToColormap(pix, 1);
    } else if (d > 1) {
        pixd = pixConvertTo8(pix, TRUE);
    } else {  /* d == 1; make sure there's a colormap */
        pixd = pixClone(pix);
        if (!pixGetColormap(pixd)) {
            cmap = pixcmapCreate(1);
            pixcmapAddColor(cmap, 255, 255, 255);
            pixcmapAddColor(cmap, 0, 0, 0);
            pixSetColormap(pixd, cmap);
        }
    }

    if (!pixd)
        return ERROR_INT("failed to convert image to indexed", procName, 1);
    d = pixGetDepth(pixd);

    if ((cmap = pixGetColormap(pixd)) == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("cmap is missing", procName, 1);
    }

        /* 'Round' the number of gif colors up to a power of 2 */
    ncolor = pixcmapGetCount(cmap);
    for (i = 0; i <= 8; i++) {
        if ((1 << i) >= ncolor) {
            gif_ncolor = (1 << i);
            break;
        }
    }
    if (gif_ncolor < 1) {
        pixDestroy(&pixd);
        return ERROR_INT("number of colors is invalid", procName, 1);
    }

        /* Save the cmap colors in a gif_cmap */
    if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("failed to create GIF color map", procName, 1);
    }
    for (i = 0; i < gif_ncolor; i++) {
        rval = gval = bval = 0;
        if (ncolor > 0) {
            if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) {
                pixDestroy(&pixd);
                GifFreeMapObject(gif_cmap);
                return ERROR_INT("failed to get color from color map",
                                 procName, 1);
            }
            ncolor--;
        }
        gif_cmap->Colors[i].Red = rval;
        gif_cmap->Colors[i].Green = gval;
        gif_cmap->Colors[i].Blue = bval;
    }

    pixGetDimensions(pixd, &w, &h, NULL);
    if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap)
        != GIF_OK) {
        pixDestroy(&pixd);
        GifFreeMapObject(gif_cmap);
        return ERROR_INT("failed to write screen description", procName, 1);
    }
    GifFreeMapObject(gif_cmap); /* not needed after this point */

    if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) {
        pixDestroy(&pixd);
        return ERROR_INT("failed to image screen description", procName, 1);
    }

    data = pixGetData(pixd);
    wpl = pixGetWpl(pixd);
    if (d != 1 && d != 2 && d != 4 && d != 8) {
        pixDestroy(&pixd);
        return ERROR_INT("image depth is not in {1, 2, 4, 8}", procName, 1);
    }

    if ((gif_line = (GifByteType *)LEPT_CALLOC(sizeof(GifByteType), w))
        == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("mem alloc fail for data line", procName, 1);
    }

    for (i = 0; i < h; i++) {
        line = data + i * wpl;
            /* Gif's way of setting the raster line up for compression */
        for (j = 0; j < w; j++) {
            switch(d)
            {
            case 8:
                gif_line[j] = GET_DATA_BYTE(line, j);
                break;
            case 4:
                gif_line[j] = GET_DATA_QBIT(line, j);
                break;
            case 2:
                gif_line[j] = GET_DATA_DIBIT(line, j);
                break;
            case 1:
                gif_line[j] = GET_DATA_BIT(line, j);
                break;
            }
        }

            /* Compress and save the line */
        if (EGifPutLine(gif, gif_line, w) != GIF_OK) {
            LEPT_FREE(gif_line);
            pixDestroy(&pixd);
            return ERROR_INT("failed to write data line into GIF", procName, 1);
        }
    }

        /* Write a text comment.  This must be placed after writing the
         * data (!!)  Note that because libgif does not provide a function
         * for reading comments from file, you will need another way
         * to read comments. */
    if ((text = pixGetText(pix)) != NULL) {
        if (EGifPutComment(gif, text) != GIF_OK)
            L_WARNING("gif comment not written\n", procName);
    }

    LEPT_FREE(gif_line);
    pixDestroy(&pixd);
    return 0;
}
Example #13
0
/*!
 * \brief   gifToPix()
 *
 * \param[in]    gif  opened gif stream
 * \return  pix, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) This decodes the pix from the compressed gif stream and
 *          closes the stream.
 *      (2) It is static so that the stream is not exposed to clients.
 * </pre>
 */
static PIX *
gifToPix(GifFileType  *gif)
{
l_int32          wpl, i, j, w, h, d, cindex, ncolors;
l_int32          rval, gval, bval;
l_uint32        *data, *line;
PIX             *pixd, *pixdi;
PIXCMAP         *cmap;
ColorMapObject  *gif_cmap;
SavedImage       si;
#if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5
int              giferr;
#endif  /* 5.1 and beyond */

    PROCNAME("gifToPix");

        /* Read all the data, but use only the first image found */
    if (DGifSlurp(gif) != GIF_OK) {
        DGifCloseFile(gif, &giferr);
        return (PIX *)ERROR_PTR("failed to read GIF data", procName, NULL);
    }

    if (gif->SavedImages == NULL) {
        DGifCloseFile(gif, &giferr);
        return (PIX *)ERROR_PTR("no images found in GIF", procName, NULL);
    }

    si = gif->SavedImages[0];
    w = si.ImageDesc.Width;
    h = si.ImageDesc.Height;
    if (w <= 0 || h <= 0) {
        DGifCloseFile(gif, &giferr);
        return (PIX *)ERROR_PTR("invalid image dimensions", procName, NULL);
    }

    if (si.RasterBits == NULL) {
        DGifCloseFile(gif, &giferr);
        return (PIX *)ERROR_PTR("no raster data in GIF", procName, NULL);
    }

    if (si.ImageDesc.ColorMap) {
            /* private cmap for this image */
        gif_cmap = si.ImageDesc.ColorMap;
    } else if (gif->SColorMap) {
            /* global cmap for whole picture */
        gif_cmap = gif->SColorMap;
    } else {
            /* don't know where to take cmap from */
        DGifCloseFile(gif, &giferr);
        return (PIX *)ERROR_PTR("color map is missing", procName, NULL);
    }

    ncolors = gif_cmap->ColorCount;
    if (ncolors <= 2)
        d = 1;
    else if (ncolors <= 4)
        d = 2;
    else if (ncolors <= 16)
        d = 4;
    else
        d = 8;
    if ((cmap = pixcmapCreate(d)) == NULL) {
        DGifCloseFile(gif, &giferr);
        return (PIX *)ERROR_PTR("cmap creation failed", procName, NULL);
    }

    for (cindex = 0; cindex < ncolors; cindex++) {
        rval = gif_cmap->Colors[cindex].Red;
        gval = gif_cmap->Colors[cindex].Green;
        bval = gif_cmap->Colors[cindex].Blue;
        pixcmapAddColor(cmap, rval, gval, bval);
    }

    if ((pixd = pixCreate(w, h, d)) == NULL) {
        DGifCloseFile(gif, &giferr);
        pixcmapDestroy(&cmap);
        return (PIX *)ERROR_PTR("failed to allocate pixd", procName, NULL);
    }
    pixSetInputFormat(pixd, IFF_GIF);
    pixSetColormap(pixd, cmap);

    wpl = pixGetWpl(pixd);
    data = pixGetData(pixd);
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (d == 1) {
            for (j = 0; j < w; j++) {
                if (si.RasterBits[i * w + j])
                    SET_DATA_BIT(line, j);
            }
        } else if (d == 2) {
            for (j = 0; j < w; j++)
                SET_DATA_DIBIT(line, j, si.RasterBits[i * w + j]);
        } else if (d == 4) {
            for (j = 0; j < w; j++)
                SET_DATA_QBIT(line, j, si.RasterBits[i * w + j]);
        } else {  /* d == 8 */
            for (j = 0; j < w; j++)
                SET_DATA_BYTE(line, j, si.RasterBits[i * w + j]);
        }
    }

        /* If the image has been interlaced (for viewing in a browser),
         * this restores the raster lines to normal order. */
    if (gif->Image.Interlace) {
        pixdi = pixUninterlaceGIF(pixd);
        pixTransferAllData(pixd, &pixdi, 0, 0);
    }

    DGifCloseFile(gif, &giferr);
    return pixd;
}
Example #14
0
int main(int    argc,
         char **argv)
{
char         filename[BUF_SIZE];
char        *dirin, *rootname, *fname;
l_int32      i, j, w, h, firstpage, npages, nfiles, ncomp;
l_int32      index, ival, rval, gval, bval;
BOX         *box;
BOXA        *boxa;
BOXAA       *baa;
JBDATA      *data;
JBCLASSER   *classer;
NUMA        *nai;
NUMAA       *naa;
SARRAY      *safiles;
PIX         *pixs, *pixt1, *pixt2, *pixd;
PIXCMAP     *cmap;
static char  mainName[] = "wordsinorder";

    if (argc != 3 && argc != 5)
        return ERROR_INT(
            " Syntax: wordsinorder dirin rootname [firstpage, npages]",
            mainName, 1);

    dirin = argv[1];
    rootname = argv[2];

    if (argc == 3) {
        firstpage = 0;
        npages = 0;
    }
    else {
        firstpage = atoi(argv[3]);
        npages = atoi(argv[4]);
    }

        /* Compute the word bounding boxes at 2x reduction, along with
         * the textlines that they are in. */
    safiles = getSortedPathnamesInDirectory(dirin, NULL, firstpage, npages);
    nfiles = sarrayGetCount(safiles);
    baa = boxaaCreate(nfiles);
    naa = numaaCreate(nfiles);
    for (i = 0; i < nfiles; i++) {
        fname = sarrayGetString(safiles, i, 0);
        if ((pixs = pixRead(fname)) == NULL) {
            L_WARNING("image file %d not read\n", mainName, i);
            continue;
        }
        pixGetWordBoxesInTextlines(pixs, 2, MIN_WORD_WIDTH, MIN_WORD_HEIGHT,
                                   MAX_WORD_WIDTH, MAX_WORD_HEIGHT,
                                   &boxa, &nai);
        boxaaAddBoxa(baa, boxa, L_INSERT);
        numaaAddNuma(naa, nai, L_INSERT);

#if  RENDER_PAGES
            /* Show the results on a 2x reduced image, where each
             * word is outlined and the color of the box depends on the
             * computed textline. */
        pixt1 = pixReduceRankBinary2(pixs, 2, NULL);
        pixGetDimensions(pixt1, &w, &h, NULL);
        pixd = pixCreate(w, h, 8);
        cmap = pixcmapCreateRandom(8, 1, 1);  /* first color is black */
        pixSetColormap(pixd, cmap);

        pixt2 = pixUnpackBinary(pixt1, 8, 1);
        pixRasterop(pixd, 0, 0, w, h, PIX_SRC | PIX_DST, pixt2, 0, 0);
        ncomp = boxaGetCount(boxa);
        for (j = 0; j < ncomp; j++) {
            box = boxaGetBox(boxa, j, L_CLONE);
            numaGetIValue(nai, j, &ival);
            index = 1 + (ival % 254);  /* omit black and white */
            pixcmapGetColor(cmap, index, &rval, &gval, &bval);
            pixRenderBoxArb(pixd, box, 2, rval, gval, bval);
            boxDestroy(&box);
        }

        snprintf(filename, BUF_SIZE, "%s.%05d", rootname, i);
        fprintf(stderr, "filename: %s\n", filename);
        pixWrite(filename, pixd, IFF_PNG);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
        pixDestroy(&pixs);
        pixDestroy(&pixd);
#endif  /* RENDER_PAGES */
    }

    boxaaDestroy(&baa);
    numaaDestroy(&naa);
    sarrayDestroy(&safiles);
    return 0;
}
Example #15
0
/*!
 *  pixReadStreamPng()
 *
 *      Input:  stream
 *      Return: pix, or null on error
 *
 *  Notes:
 *      (1) If called from pixReadStream(), the stream is positioned
 *          at the beginning of the file.
 *      (2) To do sequential reads of png format images from a stream,
 *          use pixReadStreamPng()
 */
PIX *
pixReadStreamPng(FILE  *fp)
{
l_uint8      rval, gval, bval;
l_int32      i, j, k;
l_int32      wpl, d, spp, cindex;
l_uint32     png_transforms;
l_uint32    *data, *line, *ppixel;
int          num_palette, num_text;
png_byte     bit_depth, color_type, channels;
png_uint_32  w, h, rowbytes;
png_uint_32  xres, yres;
png_bytep    rowptr;
png_bytep   *row_pointers;
png_structp  png_ptr;
png_infop    info_ptr, end_info;
png_colorp   palette;
png_textp    text_ptr;  /* ptr to text_chunk */
PIX         *pix;
PIXCMAP     *cmap;

    PROCNAME("pixReadStreamPng");

    if (!fp)
        return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
    pix = NULL;

        /* Allocate the 3 data structures */
    if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                   (png_voidp)NULL, NULL, NULL)) == NULL)
        return (PIX *)ERROR_PTR("png_ptr not made", procName, NULL);

    if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        return (PIX *)ERROR_PTR("info_ptr not made", procName, NULL);
    }

    if ((end_info = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        return (PIX *)ERROR_PTR("end_info not made", procName, NULL);
    }

        /* Set up png setjmp error handling */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return (PIX *)ERROR_PTR("internal png error", procName, NULL);
    }

    png_init_io(png_ptr, fp);

        /* ---------------------------------------------------------- *
         *  Set the transforms flags.  Whatever happens here,
         *  NEVER invert 1 bpp using PNG_TRANSFORM_INVERT_MONO.
         * ---------------------------------------------------------- */
        /* To strip 16 --> 8 bit depth, use PNG_TRANSFORM_STRIP_16 */
    if (var_PNG_STRIP_16_TO_8 == 1)   /* our default */
        png_transforms = PNG_TRANSFORM_STRIP_16;
    else
        png_transforms = PNG_TRANSFORM_IDENTITY;
        /* To remove alpha channel, use PNG_TRANSFORM_STRIP_ALPHA */
    if (var_PNG_STRIP_ALPHA == 1)   /* our default */
        png_transforms |= PNG_TRANSFORM_STRIP_ALPHA;

        /* Read it */
    png_read_png(png_ptr, info_ptr, png_transforms, NULL);

    row_pointers = png_get_rows(png_ptr, info_ptr);
    w = png_get_image_width(png_ptr, info_ptr);
    h = png_get_image_height(png_ptr, info_ptr);
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    color_type = png_get_color_type(png_ptr, info_ptr);
    channels = png_get_channels(png_ptr, info_ptr);
    spp = channels;

    if (spp == 1)
        d = bit_depth;
    else if (spp == 2) {
        d = 2 * bit_depth;
        L_WARNING("there shouldn't be 2 spp!", procName);
    }
    else  /* spp == 3 (rgb), spp == 4 (rgba) */
        d = 4 * bit_depth;

        /* Remove if/when this is implemented for all bit_depths */
    if (spp == 3 && bit_depth != 8) {
        fprintf(stderr, "Help: spp = 3 and depth = %d != 8\n!!", bit_depth);
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return (PIX *)ERROR_PTR("not implemented for this depth",
            procName, NULL);
    }

    if (color_type == PNG_COLOR_TYPE_PALETTE ||
        color_type == PNG_COLOR_MASK_PALETTE) {   /* generate a colormap */
        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
        cmap = pixcmapCreate(d);  /* spp == 1 */
        for (cindex = 0; cindex < num_palette; cindex++) {
            rval = palette[cindex].red;
            gval = palette[cindex].green;
            bval = palette[cindex].blue;
            pixcmapAddColor(cmap, rval, gval, bval);
        }
    }
    else
        cmap = NULL;

    if ((pix = pixCreate(w, h, d)) == NULL) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return (PIX *)ERROR_PTR("pix not made", procName, NULL);
    }
    wpl = pixGetWpl(pix);
    data = pixGetData(pix);
    pixSetColormap(pix, cmap);

    if (spp == 1) {   /* copy straight from buffer to pix */
        for (i = 0; i < h; i++) {
            line = data + i * wpl;
            rowptr = row_pointers[i];
            for (j = 0; j < rowbytes; j++) {
                SET_DATA_BYTE(line, j, rowptr[j]);
            }
        }
    }
    else  {   /* spp == 3 or spp == 4 */
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            rowptr = row_pointers[i];
            for (j = k = 0; j < w; j++) {
                SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k++]);
                SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k++]);
                SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
                if (spp == 4)
                    SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
                ppixel++;
            }
        }
    }

#if  DEBUG
    if (cmap) {
        for (i = 0; i < 16; i++) {
            fprintf(stderr, "[%d] = %d\n", i,
                   ((l_uint8 *)(cmap->array))[i]);
        }
    }
#endif  /* DEBUG */

        /* If there is no colormap, PNG defines black = 0 and
         * white = 1 by default for binary monochrome.  Therefore,
         * since we use the opposite definition, we must invert
         * the image colors in either of these cases:
         *    (i) there is no colormap (default)
         *    (ii) there is a colormap which defines black to
         *         be 0 and white to be 1.
         * We cannot use the PNG_TRANSFORM_INVERT_MONO flag
         * because that flag (since version 1.0.9) inverts 8 bpp
         * grayscale as well, which we don't want to do.
         * (It also doesn't work if there is a colormap.)
         * If there is a colormap that defines black = 1 and
         * white = 0, we don't need to do anything.
         *
         * How do we check the polarity of the colormap?
         * The colormap determines the values of black and
         * white pixels in the following way:
         *     if black = 1 (255), white = 0
         *          255, 255, 255, 0, 0, 0, 0, 0, 0
         *     if black = 0, white = 1 (255)
         *          0, 0, 0, 0, 255, 255, 255, 0
         * So we test the first byte to see if it is 0;
         * if so, invert the colors.
         *
         * If there is a colormap, after inverting the pixels it is
         * necessary to destroy the colormap.  Otherwise, if someone were
         * to call pixRemoveColormap(), this would cause the pixel
         * values to be inverted again!
         */
    if (d == 1 && (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) {
/*        fprintf(stderr, "Inverting binary data on png read\n"); */
        pixInvert(pix, pix);
        pixDestroyColormap(pix);
    }

    xres = png_get_x_pixels_per_meter(png_ptr, info_ptr);
    yres = png_get_y_pixels_per_meter(png_ptr, info_ptr);
    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 */

        /* Get the text if there is any */
    png_get_text(png_ptr, info_ptr, &text_ptr, &num_text);
    if (num_text && text_ptr)
        pixSetText(pix, text_ptr->text);

    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    return pix;
}
Example #16
0
/*!
 * \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;
}
Example #17
0
int main(int    argc,
          char **argv)
{
char         *filein;
char         *fileout = NULL;
l_int32       d, same;
PIX          *pixs, *pixd, *pix1, *pix2, *pix3, *pix4;
static char   mainName[] = "converttogray";

    if (argc != 2 && argc != 3)
        return ERROR_INT(" Syntax:  converttogray filein [fileout]",
                         mainName, 1);

    filein = argv[1];
    if (argc == 3) fileout = argv[2];
    if ((pixs = pixRead(filein)) == NULL)
        return ERROR_INT("pixs not made", mainName, 1);

    if (fileout) {
        pixd = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33);
        pixWrite(fileout, pixd, IFF_PNG);
        pixDestroy(&pixs);
        pixDestroy(&pixd);
        return 0;
    }

    d = pixGetDepth(pixs);
    if (d == 2) {
        pix1 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE);
        pix2 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE);
        pixEqual(pix1, pix2, &same);
        if (same)
            fprintf(stderr, "images are the same\n");
        else
            fprintf(stderr, "images are different!\n");
        pixWrite("/tmp/pix1.png", pix1, IFF_PNG);
        pixWrite("/tmp/pix2.png", pix2, IFF_PNG);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
        pixSetColormap(pixs, NULL);
        pix3 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE);
        pix4 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE);
        pixEqual(pix3, pix4, &same);
        if (same)
            fprintf(stderr, "images are the same\n");
        else
            fprintf(stderr, "images are different!\n");
        pixWrite("/tmp/pix3.png", pix3, IFF_PNG);
        pixWrite("/tmp/pix4.png", pix4, IFF_PNG);
        pixDestroy(&pix3);
        pixDestroy(&pix4);
    } else if (d == 4) {
        pix1 = pixConvert4To8(pixs, TRUE);
        pix2 = pixConvert4To8(pixs, FALSE);
        pixEqual(pix1, pix2, &same);
        if (same)
            fprintf(stderr, "images are the same\n");
        else
            fprintf(stderr, "images are different!\n");
        pixWrite("/tmp/pix1.png", pix1, IFF_PNG);
        pixWrite("/tmp/pix2.png", pix2, IFF_PNG);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
        pixSetColormap(pixs, NULL);
        pix3 = pixConvert4To8(pixs, TRUE);
        pix4 = pixConvert4To8(pixs, FALSE);
        pixEqual(pix3, pix4, &same);
        if (same)
            fprintf(stderr, "images are the same\n");
        else
            fprintf(stderr, "images are different!\n");
        pixWrite("/tmp/pix3.png", pix3, IFF_PNG);
        pixWrite("/tmp/pix4.png", pix4, IFF_PNG);
        pixDestroy(&pix3);
        pixDestroy(&pix4);
    } else {
        L_INFO("only converts 2 and 4 bpp; d = %d\n", mainName, d);
    }

    pixDestroy(&pixs);
    return 0;
}
Example #18
0
/*!
 *  pixReadStreamGif()
 *
 *      Input:  stream
 *      Return: pix, or null on error
 */
PIX *
pixReadStreamGif(FILE  *fp)
{
l_int32          fd, wpl, i, j, w, h, d, cindex, ncolors;
l_int32          rval, gval, bval;
l_uint32        *data, *line;
GifFileType     *gif;
PIX             *pixd, *pixdi;
PIXCMAP         *cmap;
ColorMapObject  *gif_cmap;
SavedImage       si;

    PROCNAME("pixReadStreamGif");

    if ((fd = fileno(fp)) < 0)
        return (PIX *)ERROR_PTR("invalid file descriptor", procName, NULL);
#ifndef _MSC_VER
    lseek(fd, 0, SEEK_SET);
#else
    _lseek(fd, 0, SEEK_SET);
#endif  /* _MSC_VER */

    if ((gif = DGifOpenFileHandle(fd)) == NULL)
        return (PIX *)ERROR_PTR("invalid file or file not found",
                                procName, NULL);

        /* Read all the data, but use only the first image found */
    if (DGifSlurp(gif) != GIF_OK) {
        DGifCloseFile(gif);
        return (PIX *)ERROR_PTR("failed to read GIF data", procName, NULL);
    }

    if (gif->SavedImages == NULL) {
        DGifCloseFile(gif);
        return (PIX *)ERROR_PTR("no images found in GIF", procName, NULL);
    }

    si = gif->SavedImages[0];
    w = si.ImageDesc.Width;
    h = si.ImageDesc.Height;
    if (w <= 0 || h <= 0) {
        DGifCloseFile(gif);
        return (PIX *)ERROR_PTR("invalid image dimensions", procName, NULL);
    }

    if (si.RasterBits == NULL) {
        DGifCloseFile(gif);
        return (PIX *)ERROR_PTR("no raster data in GIF", procName, NULL);
    }

    if (si.ImageDesc.ColorMap) {
            /* private cmap for this image */
        gif_cmap = si.ImageDesc.ColorMap;
    }
    else if (gif->SColorMap) {
            /* global cmap for whole picture */
        gif_cmap = gif->SColorMap;
    }
    else {
            /* don't know where to take cmap from */
        DGifCloseFile(gif);
        return (PIX *)ERROR_PTR("color map is missing", procName, NULL);
    }

    ncolors = gif_cmap->ColorCount;
    if (ncolors <= 2)
        d = 1;
    else if (ncolors <= 4)
        d = 2;
    else if (ncolors <= 16)
        d = 4;
    else
        d = 8;
    if ((cmap = pixcmapCreate(d)) == NULL)
        return (PIX *)ERROR_PTR("cmap creation failed", procName, NULL);

    for (cindex = 0; cindex < ncolors; cindex++) {
        rval = gif_cmap->Colors[cindex].Red;
        gval = gif_cmap->Colors[cindex].Green;
        bval = gif_cmap->Colors[cindex].Blue;
        pixcmapAddColor(cmap, rval, gval, bval);
    }

    if ((pixd = pixCreate(w, h, d)) == NULL) {
        DGifCloseFile(gif);
        pixcmapDestroy(&cmap);
        return (PIX *)ERROR_PTR("failed to allocate pixd", procName, NULL);
    }
    pixSetColormap(pixd, cmap);

    wpl = pixGetWpl(pixd);
    data = pixGetData(pixd);
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (d == 1) {
            for (j = 0; j < w; j++) {
                if (si.RasterBits[i * w + j])
                    SET_DATA_BIT(line, j);
            }
        }
        else if (d == 2) {
            for (j = 0; j < w; j++)
                SET_DATA_DIBIT(line, j, si.RasterBits[i * w + j]);
        }
        else if (d == 4) {
            for (j = 0; j < w; j++)
                SET_DATA_QBIT(line, j, si.RasterBits[i * w + j]);
        }
        else {  /* d == 8 */
            for (j = 0; j < w; j++)
                SET_DATA_BYTE(line, j, si.RasterBits[i * w + j]);
        }
    }

    if (gif->Image.Interlace) {
        pixdi = pixInterlaceGIF(pixd);
        pixTransferAllData(pixd, &pixdi, 0, 0);
    }

    DGifCloseFile(gif);
    return pixd;
}
main(int    argc,
     char **argv)
{
l_int32      w, h;
BOXA        *boxa;
PIX         *pixs, *pixt1, *pixt2, *pixg, *pixb, *pixd, *pixc;
PIX         *pixm, *pixm2, *pixd2, *pixs2;
PIXA        *pixa, *pixac;
PIXCMAP     *cmap, *cmapg;
static char  mainName[] = "misctest1";

    pixac = pixaCreate(0);

        /* Combine two grayscale images using a mask */
    pixd = pixRead("feyn.tif");
    pixs = pixRead("rabi.png");
    pixm = pixRead("pageseg2-seed.png");
    pixd2 = pixScaleToGray2(pixd);
    pixs2 = pixScaleToGray2(pixs);
    pixSaveTiled(pixd2, pixac, 2, 1, 40, 32);
    pixSaveTiled(pixs2, pixac, 2, 0, 40, 0);
    pixSaveTiled(pixm, pixac, 2, 0, 40, 0);
    pixCombineMaskedGeneral(pixd2, pixs2, pixm, 100, 100);
    pixSaveTiled(pixd2, pixac, 2, 1, 40, 0);
    pixDisplayWithTitle(pixd2, 100, 100, NULL, SHOW);
    pixDestroy(&pixd2);
    pixDestroy(&pixs2);

        /* Combine two binary images using a mask */
    pixm2 = pixExpandBinaryReplicate(pixm, 2);
    pixt1 = pixCopy(NULL, pixd);
    pixCombineMaskedGeneral(pixd, pixs, pixm2, 200, 200);
    pixSaveTiled(pixd, pixac, 4, 0, 40, 0);
    pixDisplayWithTitle(pixd, 700, 100, NULL, SHOW);
    pixCombineMasked(pixt1, pixs, pixm2);
    pixSaveTiled(pixt1, pixac, 4, 0, 40, 0);
    pixDestroy(&pixd);
    pixDestroy(&pixt1);
    pixDestroy(&pixs);
    pixDestroy(&pixm);
    pixDestroy(&pixm2);

        /* Do a restricted seedfill */
    pixs = pixRead("pageseg2-seed.png");
    pixm = pixRead("pageseg2-mask.png");
    pixd = pixSeedfillBinaryRestricted(NULL, pixs, pixm, 8, 50, 175);
    pixSaveTiled(pixs, pixac, 2, 1, 40, 0);
    pixSaveTiled(pixm, pixac, 2, 0, 40, 0);
    pixSaveTiled(pixd, pixac, 2, 0, 40, 0);
    pixDestroy(&pixs);
    pixDestroy(&pixm);
    pixDestroy(&pixd);

        /* Colorize a grayscale image */
    pixs = pixRead("lucasta.150.jpg");
    pixGetDimensions(pixs, &w, &h, NULL);
    pixb = pixThresholdToBinary(pixs, 128);
    boxa = pixConnComp(pixb, &pixa, 8);
    pixSaveTiled(pixs, pixac, 1, 1, 40, 0);
    cmap = pixcmapGrayToColor(0x6f90c0);
    pixSetColormap(pixs, cmap);
    pixSaveTiled(pixs, pixac, 1, 0, 40, 0);
    pixc = pixaDisplayRandomCmap(pixa, w, h);
    pixcmapResetColor(pixGetColormap(pixc), 0, 255, 255, 255);
    pixSaveTiled(pixc, pixac, 1, 0, 40, 0);
    pixDestroy(&pixs);
    pixDestroy(&pixb);
    pixDestroy(&pixc);
    boxaDestroy(&boxa);
    pixaDestroy(&pixa);

        /* Convert color to gray */
    pixs = pixRead("weasel4.16c.png");
    pixSaveTiled(pixs, pixac, 1, 1, 20, 0);
    pixc = pixConvertTo32(pixs);
    pixt1 = pixConvertRGBToGray(pixc, 3., 7., 5.);
    pixSaveTiled(pixt1, pixac, 1, 0, 20, 0);
    pixt2 = pixConvertRGBToGrayFast(pixc);
    pixSaveTiled(pixt2, pixac, 1, 0, 20, 0);
    pixg = pixCopy(NULL, pixs);
    cmap = pixGetColormap(pixs);
    cmapg = pixcmapColorToGray(cmap, 4., 6., 3.);
    pixSetColormap(pixg, cmapg);
    pixSaveTiled(pixg, pixac, 1, 0, 20, 0);
    pixDestroy(&pixs);
    pixDestroy(&pixc);
    pixDestroy(&pixt1);
    pixDestroy(&pixt2);
    pixDestroy(&pixg);

    pixd = pixaDisplay(pixac, 0, 0);
    pixDisplayWithTitle(pixd, 100, 100, NULL, 1);
    pixWrite("junkmisc1.png", pixd, IFF_PNG);
    pixDestroy(&pixd);
    pixaDestroy(&pixac);

    return 0;
}
Example #20
0
/*!
 * \brief   pixReadStreamJpeg()
 *
 * \param[in]    fp file stream
 * \param[in]    cmapflag 0 for no colormap in returned pix;
 *                        1 to return an 8 bpp cmapped pix if spp = 3 or 4
 * \param[in]    reduction scaling factor: 1, 2, 4 or 8
 * \param[out]   pnwarn [optional] number of warnings
 * \param[in]    hint a bitwise OR of L_JPEG_* values; 0 for default
 * \return  pix, or NULL on error
 *
 *  Usage: see pixReadJpeg
 * <pre>
 * Notes:
 *      (1) The jpeg comment, if it exists, is not stored in the pix.
 * </pre>
 */
PIX *
pixReadStreamJpeg(FILE     *fp,
                  l_int32   cmapflag,
                  l_int32   reduction,
                  l_int32  *pnwarn,
                  l_int32   hint)
{
l_int32                        cyan, yellow, magenta, black, nwarn;
l_int32                        i, j, k, rval, gval, bval;
l_int32                        w, h, wpl, spp, ncolors, cindex, ycck, cmyk;
l_uint32                      *data;
l_uint32                      *line, *ppixel;
JSAMPROW                       rowbuffer;
PIX                           *pix;
PIXCMAP                       *cmap;
struct jpeg_decompress_struct  cinfo;
struct jpeg_error_mgr          jerr;
jmp_buf                        jmpbuf;  /* must be local to the function */

    PROCNAME("pixReadStreamJpeg");

    if (pnwarn) *pnwarn = 0;
    if (!fp)
        return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
    if (cmapflag != 0 && cmapflag != 1)
        cmapflag = 0;  /* default */
    if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8)
        return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", procName, NULL);

    if (BITS_IN_JSAMPLE != 8)  /* set in jmorecfg.h */
        return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", procName, NULL);

    rewind(fp);
    pix = NULL;
    rowbuffer = NULL;

        /* Modify the jpeg error handling to catch fatal errors  */
    cinfo.err = jpeg_std_error(&jerr);
    jerr.error_exit = jpeg_error_catch_all_1;
    cinfo.client_data = (void *)&jmpbuf;
    if (setjmp(jmpbuf)) {
        pixDestroy(&pix);
        LEPT_FREE(rowbuffer);
        return (PIX *)ERROR_PTR("internal jpeg error", procName, NULL);
    }

        /* Initialize jpeg structs for decompression */
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, fp);
    jpeg_read_header(&cinfo, TRUE);
    cinfo.scale_denom = reduction;
    cinfo.scale_num = 1;
    jpeg_calc_output_dimensions(&cinfo);
    if (hint & L_JPEG_READ_LUMINANCE) {
        cinfo.out_color_space = JCS_GRAYSCALE;
        spp = 1;
        L_INFO("reading luminance channel only\n", procName);
    } else {
        spp = cinfo.out_color_components;
    }

        /* Allocate the image and a row buffer */
    w = cinfo.output_width;
    h = cinfo.output_height;
    ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmapflag == 0);
    cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmapflag == 0);
    if (spp != 1 && spp != 3 && !ycck && !cmyk) {
        return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK",
                                procName, NULL);
    }
    if ((spp == 3 && cmapflag == 0) || ycck || cmyk) {  /* rgb or 4 bpp color */
        rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), spp * w);
        pix = pixCreate(w, h, 32);
    } else {  /* 8 bpp gray or colormapped */
        rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), w);
        pix = pixCreate(w, h, 8);
    }
    pixSetInputFormat(pix, IFF_JFIF_JPEG);
    if (!rowbuffer || !pix) {
        LEPT_FREE(rowbuffer);
        pixDestroy(&pix);
        return (PIX *)ERROR_PTR("rowbuffer or pix not made", procName, NULL);
    }

        /* Initialize decompression.  Set up a colormap for color
         * quantization if requested. */
    if (spp == 1) {  /* Grayscale or colormapped */
        jpeg_start_decompress(&cinfo);
    } else {        /* Color; spp == 3 or YCCK or CMYK */
        if (cmapflag == 0) {   /* 24 bit color in 32 bit pix or YCCK/CMYK */
            cinfo.quantize_colors = FALSE;
            jpeg_start_decompress(&cinfo);
        } else {      /* Color quantize to 8 bits */
            cinfo.quantize_colors = TRUE;
            cinfo.desired_number_of_colors = 256;
            jpeg_start_decompress(&cinfo);

                /* Construct a pix cmap */
            cmap = pixcmapCreate(8);
            ncolors = cinfo.actual_number_of_colors;
            for (cindex = 0; cindex < ncolors; cindex++) {
                rval = cinfo.colormap[0][cindex];
                gval = cinfo.colormap[1][cindex];
                bval = cinfo.colormap[2][cindex];
                pixcmapAddColor(cmap, rval, gval, bval);
            }
            pixSetColormap(pix, cmap);
        }
    }
    wpl  = pixGetWpl(pix);
    data = pixGetData(pix);

        /* Decompress.  Unfortunately, we cannot use the return value
         * from jpeg_read_scanlines() to determine if there was a problem
         * with the data; it always appears to return 1.  We can only
         * tell from the warnings during decoding, such as "premature
         * end of data segment".  The default behavior is to return an
         * image even if there are warnings.  However, by setting the
         * hint to have the same bit flag as L_JPEG_FAIL_ON_BAD_DATA,
         * no image will be returned if there are any warnings. */
    for (i = 0; i < h; i++) {
        if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) == 0) {
            L_ERROR("read error at scanline %d\n", procName, i);
            pixDestroy(&pix);
            jpeg_destroy_decompress(&cinfo);
            LEPT_FREE(rowbuffer);
            return (PIX *)ERROR_PTR("bad data", procName, NULL);
        }

            /* -- 24 bit color -- */
        if ((spp == 3 && cmapflag == 0) || ycck || cmyk) {
            ppixel = data + i * wpl;
            if (spp == 3) {
                for (j = k = 0; j < w; j++) {
                    SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]);
                    SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]);
                    SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]);
                    ppixel++;
                }
            } else {
                    /* This is a conversion from CMYK -> RGB that ignores
                       color profiles, and is invoked when the image header
                       claims to be in CMYK or YCCK colorspace.  If in YCCK,
                       libjpeg may be doing YCCK -> CMYK under the hood.
                       To understand why the colors need to be inverted on
                       read-in for the Adobe marker, see the "Special
                       color spaces" section of "Using the IJG JPEG
                       Library" by Thomas G. Lane:
                         http://www.jpegcameras.com/libjpeg/libjpeg-3.html#ss3.1
                       The non-Adobe conversion is equivalent to:
                           rval = black - black * cyan / 255
                           ...
                       The Adobe conversion is equivalent to:
                           rval = black - black * (255 - cyan) / 255
                           ...
                       Note that cyan is the complement to red, and we
                       are subtracting the complement color (weighted
                       by black) from black.  For Adobe conversions,
                       where they've already inverted the CMY but not
                       the K, we have to invert again.  The results
                       must be clipped to [0 ... 255]. */
                for (j = k = 0; j < w; j++) {
                    cyan = rowbuffer[k++];
                    magenta = rowbuffer[k++];
                    yellow = rowbuffer[k++];
                    black = rowbuffer[k++];
                    if (cinfo.saw_Adobe_marker) {
                        rval = (black * cyan) / 255;
                        gval = (black * magenta) / 255;
                        bval = (black * yellow) / 255;
                    } else {
                        rval = black * (255 - cyan) / 255;
                        gval = black * (255 - magenta) / 255;
                        bval = black * (255 - yellow) / 255;
                    }
                    rval = L_MIN(L_MAX(rval, 0), 255);
                    gval = L_MIN(L_MAX(gval, 0), 255);
                    bval = L_MIN(L_MAX(bval, 0), 255);
                    composeRGBPixel(rval, gval, bval, ppixel);
                    ppixel++;
                }
            }
        } else {    /* 8 bpp grayscale or colormapped pix */
            line = data + i * wpl;
            for (j = 0; j < w; j++)
                SET_DATA_BYTE(line, j, rowbuffer[j]);
        }
    }

    nwarn = cinfo.err->num_warnings;
    if (pnwarn) *pnwarn = nwarn;

        /* If the pixel density is neither 1 nor 2, it may not be defined.
         * In that case, don't set the resolution.  */
    if (cinfo.density_unit == 1) {  /* pixels per inch */
        pixSetXRes(pix, cinfo.X_density);
        pixSetYRes(pix, cinfo.Y_density);
    } else if (cinfo.density_unit == 2) {  /* pixels per centimeter */
        pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5));
        pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5));
    }

    if (cinfo.output_components != spp)
        fprintf(stderr, "output spp = %d, spp = %d\n",
                cinfo.output_components, spp);

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    LEPT_FREE(rowbuffer);

    if (nwarn > 0) {
        if (hint & L_JPEG_FAIL_ON_BAD_DATA) {
            L_ERROR("fail with %d warning(s) of bad data\n", procName, nwarn);
            pixDestroy(&pix);
        } else {
            L_WARNING("%d warning(s) of bad data\n", procName, nwarn);
        }
    }

    return pix;
}
Example #21
0
main(int    argc,
     char **argv)
{
char         *filein, *fileout;
l_int32       d, same;
PIX          *pixs, *pixd, *pixt0, *pixt1, *pixt2, *pixt3, *pixt4, *pixt5;
static char   mainName[] = "converttogray";

    if (argc != 2 && argc != 3)
	exit(ERROR_INT(" Syntax:  converttogray filein [fileout]",
	               mainName, 1));

    filein = argv[1];
    fileout = argv[2];

    if ((pixs = pixRead(filein)) == NULL)
	exit(ERROR_INT("pixs not made", mainName, 1));

#if 0
    pixd = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33);
    pixWrite(fileout, pixd, IFF_PNG);
    pixDestroy(&pixd);
#endif

#if 1
    d = pixGetDepth(pixs);
    if (d == 2) {
	pixt1 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE);
	pixt2 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE);
	pixEqual(pixt1, pixt2, &same);
	if (same)
	    fprintf(stderr, "images are the same\n");
	else
	    fprintf(stderr, "images are different!\n");
	pixWrite("/tmp/junkpixt1", pixt1, IFF_PNG);
	pixWrite("/tmp/junkpixt2", pixt2, IFF_PNG);
	pixDestroy(&pixt1);
	pixDestroy(&pixt2);
	pixSetColormap(pixs, NULL);
	pixt3 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE);
	pixt4 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE);
	pixEqual(pixt3, pixt4, &same);
	if (same)
	    fprintf(stderr, "images are the same\n");
	else
	    fprintf(stderr, "images are different!\n");
	pixWrite("/tmp/junkpixt3", pixt3, IFF_PNG);
	pixWrite("/tmp/junkpixt4", pixt4, IFF_PNG);
	pixDestroy(&pixt3);
	pixDestroy(&pixt4);
    }
    else if (d == 4) {
	pixt1 = pixConvert4To8(pixs, TRUE);
	pixt2 = pixConvert4To8(pixs, FALSE);
	pixEqual(pixt1, pixt2, &same);
	if (same)
	    fprintf(stderr, "images are the same\n");
	else
	    fprintf(stderr, "images are different!\n");
	pixWrite("/tmp/junkpixt1", pixt1, IFF_PNG);
	pixWrite("/tmp/junkpixt2", pixt2, IFF_PNG);
	pixDestroy(&pixt1);
	pixDestroy(&pixt2);
	pixSetColormap(pixs, NULL);
	pixt3 = pixConvert4To8(pixs, TRUE);
	pixt4 = pixConvert4To8(pixs, FALSE);
	pixEqual(pixt3, pixt4, &same);
	if (same)
	    fprintf(stderr, "images are the same\n");
	else
	    fprintf(stderr, "images are different!\n");
	pixWrite("/tmp/junkpixt3", pixt3, IFF_PNG);
	pixWrite("/tmp/junkpixt4", pixt4, IFF_PNG);
	pixDestroy(&pixt3);
	pixDestroy(&pixt4);
    }
#endif

    pixDestroy(&pixs);
    return 0;
}