Ejemplo n.º 1
0
static l_int32
test_8bpp_trans(L_REGPARAMS  *rp)
{
l_int32   same, transp;
FILE     *fp;
PIX      *pix1, *pix2, *pix3;
PIXCMAP  *cmap;

    pix1 = pixRead("wyom.jpg");
    pix2 = pixColorSegment(pix1, 75, 10, 8, 7);
    cmap = pixGetColormap(pix2);
    pixcmapSetAlpha(cmap, 0, 0);  /* set blueish sky color to transparent */
    pixWrite("/tmp/regout/8bpp-trans.png", pix2, IFF_PNG);
    pix3 = pixRead("/tmp/regout/8bpp-trans.png");
    pixEqual(pix2, pix3, &same);
    if (same)
        fprintf(stderr, "8bpp_trans: success\n");
    else
        fprintf(stderr, "8bpp_trans: bad output\n");
    pixDisplayWithTitle(pix3, 700, 0, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    fp = fopenReadStream("/tmp/regout/8bpp-trans.png");
    fgetPngColormapInfo(fp, &cmap, &transp);
    fclose(fp);
    if (transp)
        fprintf(stderr, "8bpp_trans: correct -- transparency found\n");
    else
        fprintf(stderr, "8bpp_trans: error -- no transparency found!\n");
    if (rp->display) pixcmapWriteStream(stderr, cmap);
    pixcmapDestroy(&cmap);
    return same;
}
Ejemplo n.º 2
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;
}