Пример #1
0
/*!
 *  pixRotate180()
 *
 *      Input:  pixd  (<optional>; can be null, equal to pixs,
 *                     or different from pixs)
 *              pixs (all depths)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) This does a 180 rotation of the image about the center,
 *          which is equivalent to a left-right flip about a vertical
 *          line through the image center, followed by a top-bottom
 *          flip about a horizontal line through the image center.
 *      (2) There are 3 cases for input:
 *          (a) pixd == null (creates a new pixd)
 *          (b) pixd == pixs (in-place operation)
 *          (c) pixd != pixs (existing pixd)
 *      (3) For clarity, use these three patterns, respectively:
 *          (a) pixd = pixRotate180(NULL, pixs);
 *          (b) pixRotate180(pixs, pixs);
 *          (c) pixRotate180(pixd, pixs);
 */
PIX *
pixRotate180(PIX  *pixd,
             PIX  *pixs)
{
l_int32  d;

    PROCNAME("pixRotate180");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    d = pixGetDepth(pixs);
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
        return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
                                procName, NULL);

        /* Prepare pixd for in-place operation */
    if ((pixd = pixCopy(pixd, pixs)) == NULL)
	return (PIX *)ERROR_PTR("pixd not made", procName, NULL);

    pixFlipLR(pixd, pixd);
    pixFlipTB(pixd, pixd);
    return pixd;
}
Пример #2
0
void
RotateOrthTest(PIX          *pixs,
               L_REGPARAMS  *rp)
{
l_int32   zero, count;
PIX      *pixt, *pixd;
PIXCMAP  *cmap;

    cmap = pixGetColormap(pixs);

	/* Test 4 successive 90 degree rotations */
    pixt = pixRotate90(pixs, 1);
    pixd = pixRotate90(pixt, 1);
    pixDestroy(&pixt);
    pixt = pixRotate90(pixd, 1);
    pixDestroy(&pixd);
    pixd = pixRotate90(pixt, 1);
    pixDestroy(&pixt);
    regTestComparePix(rp, pixs, pixd);
    if (!cmap) {
        pixXor(pixd, pixd, pixs);
        pixZero(pixd, &zero);
        if (zero)
            fprintf(stderr, "OK.  Four 90-degree rotations gives I\n");
        else {
             pixCountPixels(pixd, &count, NULL);
             fprintf(stderr, "Failure for four 90-degree rots; count = %d\n",
                     count);
        }
    }
    pixDestroy(&pixd);

	/* Test 2 successive 180 degree rotations */
    pixt = pixRotate180(NULL, pixs);
    pixRotate180(pixt, pixt);
    regTestComparePix(rp, pixs, pixt);
    if (!cmap) {
        pixXor(pixt, pixt, pixs);
        pixZero(pixt, &zero);
        if (zero)
            fprintf(stderr, "OK.  Two 180-degree rotations gives I\n");
        else {
            pixCountPixels(pixt, &count, NULL);
            fprintf(stderr, "Failure for two 180-degree rots; count = %d\n",
                    count);
        }
    }
    pixDestroy(&pixt);

	/* Test 2 successive LR flips */
    pixt = pixFlipLR(NULL, pixs);
    pixFlipLR(pixt, pixt);
    regTestComparePix(rp, pixs, pixt);
    if (!cmap) {
        pixXor(pixt, pixt, pixs);
        pixZero(pixt, &zero);
        if (zero)
            fprintf(stderr, "OK.  Two LR flips gives I\n");
        else {
            pixCountPixels(pixt, &count, NULL);
            fprintf(stderr, "Failure for two LR flips; count = %d\n", count);
        }
    }
    pixDestroy(&pixt);

	/* Test 2 successive TB flips */
    pixt = pixFlipTB(NULL, pixs);
    pixFlipTB(pixt, pixt);
    regTestComparePix(rp, pixs, pixt);
    if (!cmap) {
        pixXor(pixt, pixt, pixs);
        pixZero(pixt, &zero);
        if (zero)
            fprintf(stderr, "OK.  Two TB flips gives I\n");
        else {
            pixCountPixels(pixt, &count, NULL);
            fprintf(stderr, "Failure for two TB flips; count = %d\n", count);
        }
    }
    pixDestroy(&pixt);
    return;
}
Пример #3
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, depth, d;
l_int32    offset, width, height, height_neg, 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;
#if defined(__GNUC__)
BMP_HEADER *bmph;
#define bmpih (&bmph->bmpih)
#else
BMP_IH    *bmpih;
#endif
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 = bmpfh->bfType[0] + ((l_int32)bmpfh->bfType[1] << 8);
    if (bftype != BMP_ID)
        return (PIX *)ERROR_PTR("not bmf format", procName, NULL);
#if defined(__GNUC__)
    bmph = (BMP_HEADER *)bmpfh;
#else
    bmpih = (BMP_IH *)(cdata + BMP_FHBYTES);
#endif
    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 = bmpfh->bfOffBits[0];
    offset += (l_int32)bmpfh->bfOffBits[1] << 8;
    offset += (l_int32)bmpfh->bfOffBits[2] << 16;
    offset += (l_int32)bmpfh->bfOffBits[3] << 24;
    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, resolution 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 == 0 || height < -L_MAX_ALLOWED_HEIGHT ||
        height > L_MAX_ALLOWED_HEIGHT)
        return (PIX *)ERROR_PTR("invalid height", procName, NULL);
    if (xres < 0 || xres > L_MAX_ALLOWED_RES ||
        yres < 0 || yres > L_MAX_ALLOWED_RES)
        return (PIX *)ERROR_PTR("invalid resolution", procName, NULL);
    height_neg = 0;
    if (height < 0) {
        height_neg = 1;
        height = -height;
    }
    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);
    if (height_neg)
        pixFlipTB(pix, 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;
}
Пример #4
0
/*!
 *  pixGetWindowsHBITMAP()
 *
 *      Input:  pix
 *      Return: Windows hBitmap, or null on error
 *
 *  Notes:
 *      (1) It's the responsibility of the caller to destroy the
 *          returned hBitmap with a call to DeleteObject (or with
 *          something that eventually calls DeleteObject).
 */
HBITMAP
pixGetWindowsHBITMAP(PIX  *pix)
{
l_int32    width, height, depth;
l_uint32  *data;
HBITMAP    hBitmap = NULL;
BITMAP     bm;
DWORD      imageBitsSize;
PIX       *pixt = NULL;
PIXCMAP   *cmap;

    PROCNAME("pixGetWindowsHBITMAP");
    if (!pix)
        return (HBITMAP)ERROR_PTR("pix not defined", procName, NULL);

    pixGetDimensions(pix, &width, &height, &depth);
    cmap = pixGetColormap(pix);

    if (depth == 24) depth = 32;
    if (depth == 2) {
        pixt = pixConvert2To8(pix, 0, 85, 170, 255, TRUE);
        if (!pixt)
            return (HBITMAP)ERROR_PTR("unable to convert pix from 2bpp to 8bpp",
                    procName, NULL);
        depth = pixGetDepth(pixt);
        cmap = pixGetColormap(pixt);
    }

    if (depth < 16) {
        if (!cmap)
            cmap = pixcmapCreateLinear(depth, 1<<depth);
    }

    hBitmap = DSCreateDIBSection(width, height, depth, cmap);
    if (!hBitmap)
        return (HBITMAP)ERROR_PTR("Unable to create HBITMAP", procName, NULL);

        /* By default, Windows assumes bottom up images */
    if (pixt)
        pixt = pixFlipTB(pixt, pixt);
    else
        pixt = pixFlipTB(NULL, pix);

        /* "standard" color table assumes bit off=black */
    if (depth == 1) {
        pixInvert(pixt, pixt);
    }

        /* Don't byte swap until done manipulating pix! */
    if (depth <= 16)
        pixEndianByteSwap(pixt);

    GetObject (hBitmap, sizeof(BITMAP), &bm);
    imageBitsSize = ImageBitsSize(hBitmap);
    data = pixGetData(pixt);
    if (data) {
        memcpy (bm.bmBits, data, imageBitsSize);
    } else {
        DeleteObject (hBitmap);
        hBitmap = NULL;
    }
    pixDestroy(&pixt);

    return hBitmap;
}