Exemplo n.º 1
0
/*!
 *  pixBilinearColor()
 *
 *      Input:  pixs (32 bpp)
 *              vc  (vector of 8 coefficients for bilinear transformation)
 *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
 *      Return: pixd, or null on error
 */
PIX *
pixBilinearColor(PIX *pixs,
                 l_float32 *vc,
                 l_uint32 colorval) {
    l_int32 i, j, w, h, d, wpls, wpld;
    l_uint32 val;
    l_uint32 *datas, *datad, *lined;
    l_float32 x, y;
    PIX *pix1, *pix2, *pixd;

    PROCNAME("pixBilinearColor");

    if (!pixs)
        return (PIX *) ERROR_PTR("pixs not defined", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if (d != 32)
        return (PIX *) ERROR_PTR("pixs must be 32 bpp", procName, NULL);
    if (!vc)
        return (PIX *) ERROR_PTR("vc not defined", procName, NULL);

    datas = pixGetData(pixs);
    wpls = pixGetWpl(pixs);
    pixd = pixCreateTemplate(pixs);
    pixSetAllArbitrary(pixd, colorval);
    datad = pixGetData(pixd);
    wpld = pixGetWpl(pixd);

    /* Iterate over destination pixels */
    for (i = 0; i < h; i++) {
        lined = datad + i * wpld;
        for (j = 0; j < w; j++) {
            /* Compute float src pixel location corresponding to (i,j) */
            bilinearXformPt(vc, j, i, &x, &y);
            linearInterpolatePixelColor(datas, wpls, w, h, x, y, colorval,
                                        &val);
            *(lined + j) = val;
        }
    }

    /* If rgba, transform the pixs alpha channel and insert in pixd */
    if (pixGetSpp(pixs) == 4) {
        pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
        pix2 = pixBilinearGray(pix1, vc, 255);  /* bring in opaque */
        pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }

    return pixd;
}
Exemplo n.º 2
0
/*!
 * \brief   pixRotate3Shear()
 *
 * \param[in]    pixs
 * \param[in]    xcen, ycen center of rotation
 * \param[in]    angle radians
 * \param[in]    incolor L_BRING_IN_WHITE, L_BRING_IN_BLACK;
 * \return  pixd, or NULL on error.
 *
 * <pre>
 * Notes:
 *      (1) This rotates the image about the given point, using the 3-shear
 *          method.  It should only be used for angles smaller than
 *          LIMIT_SHEAR_ANGLE.  For larger angles, a warning is issued.
 *      (2) A positive angle gives a clockwise rotation.
 *      (3) 3-shear rotation by a specified angle is equivalent
 *          to the sequential transformations
 *            y' = y + tan(angle/2) * (x - xcen)     for first y-shear
 *            x' = x + sin(angle) * (y - ycen)       for x-shear
 *            y' = y + tan(angle/2) * (x - xcen)     for second y-shear
 *      (4) Computation of tan(angle) is performed in the shear operations.
 *      (5) This brings in 'incolor' pixels from outside the image.
 *      (6) If the image has an alpha layer, it is rotated separately by
 *          two shears.
 *      (7) The algorithm was published by Alan Paeth: "A Fast Algorithm
 *          for General Raster Rotation," Graphics Interface '86,
 *          pp. 77-81, May 1986.  A description of the method, along with
 *          an implementation, can be found in Graphics Gems, p. 179,
 *          edited by Andrew Glassner, published by Academic Press, 1990.
 * </pre>
 */
PIX *
pixRotate3Shear(PIX       *pixs,
                l_int32    xcen,
                l_int32    ycen,
                l_float32  angle,
                l_int32    incolor)
{
l_float32  hangle;
PIX       *pix1, *pix2, *pixd;

    PROCNAME("pixRotate3Shear");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
        return (PIX *)(PIX *)ERROR_PTR("invalid incolor value", procName, NULL);

    if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
        return pixClone(pixs);
    if (L_ABS(angle) > LIMIT_SHEAR_ANGLE) {
        L_WARNING("%6.2f radians; large angle for 3-shear rotation\n",
                  procName, L_ABS(angle));
    }

    hangle = atan(sin(angle));
    if ((pixd = pixVShear(NULL, pixs, xcen, angle / 2., incolor)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    if ((pix1 = pixHShear(NULL, pixd, ycen, hangle, incolor)) == NULL) {
        pixDestroy(&pixd);
        return (PIX *)ERROR_PTR("pix1 not made", procName, NULL);
    }
    pixVShear(pixd, pix1, xcen, angle / 2., incolor);
    pixDestroy(&pix1);

    if (pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4) {
        pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
            /* L_BRING_IN_WHITE brings in opaque for the alpha component */
        pix2 = pixRotate3Shear(pix1, xcen, ycen, angle, L_BRING_IN_WHITE);
        pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }
    return pixd;
}
Exemplo n.º 3
0
/*!
 *  pixRotateAMColorCorner()
 *
 *      Input:  pixs
 *              angle (radians; clockwise is positive)
 *              colorval (e.g., 0 to bring in BLACK, 0xffffff00 for WHITE)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) Rotates the image about the UL corner.
 *      (2) A positive angle gives a clockwise rotation.
 *      (3) Specify the color to be brought in from outside the image.
 */
PIX *
pixRotateAMColorCorner(PIX       *pixs,
                       l_float32  angle,
                       l_uint32   fillval)
{
l_int32    w, h, wpls, wpld;
l_uint32  *datas, *datad;
PIX       *pix1, *pix2, *pixd;

    PROCNAME("pixRotateAMColorCorner");

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

    if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
        return pixClone(pixs);

    pixGetDimensions(pixs, &w, &h, NULL);
    datas = pixGetData(pixs);
    wpls = pixGetWpl(pixs);
    pixd = pixCreateTemplate(pixs);
    datad = pixGetData(pixd);
    wpld = pixGetWpl(pixd);

    rotateAMColorCornerLow(datad, w, h, wpld, datas, wpls, angle, fillval);
    if (pixGetSpp(pixs) == 4) {
        pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
        pix2 = pixRotateAMGrayCorner(pix1, angle, 255);  /* bring in opaque */
        pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }

    return pixd;
}
Exemplo n.º 4
0
/*!
 *  pixWriteMemWebP()
 *
 *      Input:  &encdata (<return> webp encoded data of pixs)
 *              &encsize (<return> size of webp encoded data)
 *              pixs (any depth, cmapped OK)
 *              quality (0 - 100; default ~80)
 *              lossless (use 1 for lossless; 0 for lossy)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) Lossless and lossy encoding are entirely different in webp.
 *          @quality applies to lossy, and is ignored for lossless.
 *      (2) The input image is converted to RGB if necessary.  If spp == 3,
 *          we set the alpha channel to fully opaque (255), and
 *          WebPEncodeRGBA() then removes the alpha chunk when encoding,
 *          setting the internal header field has_alpha to 0.
 */
l_int32
pixWriteMemWebP(l_uint8  **pencdata,
                size_t    *pencsize,
                PIX       *pixs,
                l_int32    quality,
                l_int32    lossless)
{
l_int32    w, h, d, wpl, stride;
l_uint32  *data;
PIX       *pix1, *pix2;

    PROCNAME("pixWriteMemWebP");

    if (!pencdata)
        return ERROR_INT("&encdata not defined", procName, 1);
    *pencdata = NULL;
    if (!pencsize)
        return ERROR_INT("&encsize not defined", procName, 1);
    *pencsize = 0;
    if (!pixs)
        return ERROR_INT("&pixs not defined", procName, 1);
    if (lossless == 0 && (quality < 0 || quality > 100))
        return ERROR_INT("quality not in [0 ... 100]", procName, 1);

    if ((pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL)
        return ERROR_INT("failure to remove color map", procName, 1);

        /* Convert to rgb if not 32 bpp; pix2 must not be a clone of pixs. */
    if (pixGetDepth(pix1) != 32)
        pix2 = pixConvertTo32(pix1);
    else
        pix2 = pixCopy(NULL, pix1);
    pixDestroy(&pix1);
    pixGetDimensions(pix2, &w, &h, &d);
    if (w <= 0 || h <= 0 || d != 32) {
        pixDestroy(&pix2);
        return ERROR_INT("pix2 not 32 bpp or of 0 size", procName, 1);
    }

        /* If spp == 3, need to set alpha layer to opaque (all 1s). */
    if (pixGetSpp(pix2) == 3)
        pixSetComponentArbitrary(pix2, L_ALPHA_CHANNEL, 255);

        /* Webp encoder assumes big-endian byte order for RGBA components */
    pixEndianByteSwap(pix2);
    wpl = pixGetWpl(pix2);
    data = pixGetData(pix2);
    stride = wpl * 4;
    if (lossless) {
        *pencsize = WebPEncodeLosslessRGBA((uint8_t *)data, w, h,
                                           stride, pencdata);
    } else {
        *pencsize = WebPEncodeRGBA((uint8_t *)data, w, h, stride,
                                   quality, pencdata);
    }
    pixDestroy(&pix2);

    if (*pencsize == 0) {
        free(pencdata);
        *pencdata = NULL;
        return ERROR_INT("webp encoding failed", procName, 1);
    }

    return 0;
}
Exemplo n.º 5
0
/*!
 *  pixDisplayWithTitle()
 *
 *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
 *              x, y  (location of display frame)
 *              title (<optional> on frame; can be NULL);
 *              dispflag (1 to write, else disabled)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) See notes for pixDisplay().
 *      (2) This displays the image if dispflag == 1.
 */
l_int32
pixDisplayWithTitle(PIX         *pixs,
                    l_int32      x,
                    l_int32      y,
                    const char  *title,
                    l_int32      dispflag)
{
char           *tempname;
char            buffer[L_BUF_SIZE];
static l_int32  index = 0;  /* caution: not .so or thread safe */
l_int32         w, h, d, spp, maxheight, opaque, threeviews, ignore;
l_float32       ratw, rath, ratmin;
PIX            *pix0, *pix1, *pix2;
PIXCMAP        *cmap;
#ifndef _WIN32
l_int32         wt, ht;
#else
char           *pathname;
char            fullpath[_MAX_PATH];
#endif  /* _WIN32 */

    PROCNAME("pixDisplayWithTitle");

    if (dispflag != 1) return 0;
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (var_DISPLAY_PROG != L_DISPLAY_WITH_XZGV &&
        var_DISPLAY_PROG != L_DISPLAY_WITH_XLI &&
        var_DISPLAY_PROG != L_DISPLAY_WITH_XV &&
        var_DISPLAY_PROG != L_DISPLAY_WITH_IV &&
        var_DISPLAY_PROG != L_DISPLAY_WITH_OPEN) {
        return ERROR_INT("no program chosen for display", procName, 1);
    }

        /* Display with three views if either spp = 4 or if colormapped
         * and the alpha component is not fully opaque */
    opaque = TRUE;
    if ((cmap = pixGetColormap(pixs)) != NULL)
        pixcmapIsOpaque(cmap, &opaque);
    spp = pixGetSpp(pixs);
    threeviews = (spp == 4 || !opaque) ? TRUE : FALSE;

        /* If colormapped and not opaque, remove the colormap to RGBA */
    if (!opaque)
        pix0 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA);
    else
        pix0 = pixClone(pixs);

        /* Scale if necessary; this will also remove a colormap */
    pixGetDimensions(pix0, &w, &h, &d);
    maxheight = (threeviews) ? MAX_DISPLAY_HEIGHT / 3 : MAX_DISPLAY_HEIGHT;
    if (w <= MAX_DISPLAY_WIDTH && h <= maxheight) {
        if (d == 16)  /* take MSB */
            pix1 = pixConvert16To8(pix0, 1);
        else
            pix1 = pixClone(pix0);
    } else {
        ratw = (l_float32)MAX_DISPLAY_WIDTH / (l_float32)w;
        rath = (l_float32)maxheight / (l_float32)h;
        ratmin = L_MIN(ratw, rath);
        if (ratmin < 0.125 && d == 1)
            pix1 = pixScaleToGray8(pix0);
        else if (ratmin < 0.25 && d == 1)
            pix1 = pixScaleToGray4(pix0);
        else if (ratmin < 0.33 && d == 1)
            pix1 = pixScaleToGray3(pix0);
        else if (ratmin < 0.5 && d == 1)
            pix1 = pixScaleToGray2(pix0);
        else
            pix1 = pixScale(pix0, ratmin, ratmin);
    }
    pixDestroy(&pix0);
    if (!pix1)
        return ERROR_INT("pix1 not made", procName, 1);

        /* Generate the three views if required */
    if (threeviews)
        pix2 = pixDisplayLayersRGBA(pix1, 0xffffff00, 0);
    else
        pix2 = pixClone(pix1);

    if (index == 0) {
        lept_rmdir("disp");
        lept_mkdir("disp");
    }

    index++;
    if (pixGetDepth(pix2) < 8 ||
        (w < MAX_SIZE_FOR_PNG && h < MAX_SIZE_FOR_PNG)) {
        snprintf(buffer, L_BUF_SIZE, "/tmp/disp/write.%03d.png", index);
        pixWrite(buffer, pix2, IFF_PNG);
    } else {
        snprintf(buffer, L_BUF_SIZE, "/tmp/disp/write.%03d.jpg", index);
        pixWrite(buffer, pix2, IFF_JFIF_JPEG);
    }
    tempname = stringNew(buffer);

#ifndef _WIN32

        /* Unix */
    if (var_DISPLAY_PROG == L_DISPLAY_WITH_XZGV) {
            /* no way to display title */
        pixGetDimensions(pix2, &wt, &ht, NULL);
        snprintf(buffer, L_BUF_SIZE,
                 "xzgv --geometry %dx%d+%d+%d %s &", wt + 10, ht + 10,
                 x, y, tempname);
    } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XLI) {
        if (title) {
            snprintf(buffer, L_BUF_SIZE,
               "xli -dispgamma 1.0 -quiet -geometry +%d+%d -title \"%s\" %s &",
               x, y, title, tempname);
        } else {
            snprintf(buffer, L_BUF_SIZE,
               "xli -dispgamma 1.0 -quiet -geometry +%d+%d %s &",
               x, y, tempname);
        }
    } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_XV) {
        if (title) {
            snprintf(buffer, L_BUF_SIZE,
                     "xv -quit -geometry +%d+%d -name \"%s\" %s &",
                     x, y, title, tempname);
        } else {
            snprintf(buffer, L_BUF_SIZE,
                     "xv -quit -geometry +%d+%d %s &", x, y, tempname);
        }
    } else if (var_DISPLAY_PROG == L_DISPLAY_WITH_OPEN) {
        snprintf(buffer, L_BUF_SIZE, "open %s &", tempname);
    }
    ignore = system(buffer);

#else  /* _WIN32 */

        /* Windows: L_DISPLAY_WITH_IV */
    pathname = genPathname(tempname, NULL);
    _fullpath(fullpath, pathname, sizeof(fullpath));
    if (title) {
        snprintf(buffer, L_BUF_SIZE,
                 "i_view32.exe \"%s\" /pos=(%d,%d) /title=\"%s\"",
                 fullpath, x, y, title);
    } else {
        snprintf(buffer, L_BUF_SIZE, "i_view32.exe \"%s\" /pos=(%d,%d)",
                 fullpath, x, y);
    }
    ignore = system(buffer);
    FREE(pathname);

#endif  /* _WIN32 */

    pixDestroy(&pix1);
    pixDestroy(&pix2);
    FREE(tempname);
    return 0;
}
Exemplo n.º 6
0
bool TessPDFRenderer::imageToPDFObj(Pix *pix,
                                    char *filename,
                                    long int objnum,
                                    char **pdf_object,
                                    long int *pdf_object_size) {
    size_t n;
    char b0[kBasicBufSize];
    char b1[kBasicBufSize];
    char b2[kBasicBufSize];
    if (!pdf_object_size || !pdf_object)
        return false;
    *pdf_object = NULL;
    *pdf_object_size = 0;
    if (!filename)
        return false;

    L_COMP_DATA *cid = NULL;
    const int kJpegQuality = 85;

    // TODO(jbreiden) Leptonica 1.71 doesn't correctly handle certain
    // types of PNG files, especially if there are 2 samples per pixel.
    // We can get rid of this logic after Leptonica 1.72 is released and
    // has propagated everywhere. Bug discussion as follows.
    // https://code.google.com/p/tesseract-ocr/issues/detail?id=1300
    int format, sad;
    findFileFormat(filename, &format);
    if (pixGetSpp(pix) == 4 && format == IFF_PNG) {
        pixSetSpp(pix, 3);
        sad = pixGenerateCIData(pix, L_FLATE_ENCODE, 0, 0, &cid);
    } else {
        sad = l_generateCIDataForPdf(filename, pix, kJpegQuality, &cid);
    }

    if (sad || !cid) {
        l_CIDataDestroy(&cid);
        return false;
    }

    const char *group4 = "";
    const char *filter;
    switch (cid->type) {
    case L_FLATE_ENCODE:
        filter = "/FlateDecode";
        break;
    case L_JPEG_ENCODE:
        filter = "/DCTDecode";
        break;
    case L_G4_ENCODE:
        filter = "/CCITTFaxDecode";
        group4 = "    /K -1\n";
        break;
    case L_JP2K_ENCODE:
        filter = "/JPXDecode";
        break;
    default:
        l_CIDataDestroy(&cid);
        return false;
    }

    // Maybe someday we will accept RGBA but today is not that day.
    // It requires creating an /SMask for the alpha channel.
    // http://stackoverflow.com/questions/14220221
    const char *colorspace;
    if (cid->ncolors > 0) {
        n = snprintf(b0, sizeof(b0),
                     "  /ColorSpace [ /Indexed /DeviceRGB %d %s ]\n",
                     cid->ncolors - 1, cid->cmapdatahex);
        if (n >= sizeof(b0)) {
            l_CIDataDestroy(&cid);
            return false;
        }
        colorspace = b0;
    } else {
        switch (cid->spp) {
        case 1:
            colorspace = "  /ColorSpace /DeviceGray\n";
            break;
        case 3:
            colorspace = "  /ColorSpace /DeviceRGB\n";
            break;
        default:
            l_CIDataDestroy(&cid);
            return false;
        }
    }

    int predictor = (cid->predictor) ? 14 : 1;

    // IMAGE
    n = snprintf(b1, sizeof(b1),
                 "%ld 0 obj\n"
                 "<<\n"
                 "  /Length %ld\n"
                 "  /Subtype /Image\n",
                 objnum, (unsigned long) cid->nbytescomp);
    if (n >= sizeof(b1)) {
        l_CIDataDestroy(&cid);
        return false;
    }

    n = snprintf(b2, sizeof(b2),
                 "  /Width %d\n"
                 "  /Height %d\n"
                 "  /BitsPerComponent %d\n"
                 "  /Filter %s\n"
                 "  /DecodeParms\n"
                 "  <<\n"
                 "    /Predictor %d\n"
                 "    /Colors %d\n"
                 "%s"
                 "    /Columns %d\n"
                 "    /BitsPerComponent %d\n"
                 "  >>\n"
                 ">>\n"
                 "stream\n",
                 cid->w, cid->h, cid->bps, filter, predictor, cid->spp,
                 group4, cid->w, cid->bps);
    if (n >= sizeof(b2)) {
        l_CIDataDestroy(&cid);
        return false;
    }

    const char *b3 =
        "endstream\n"
        "endobj\n";

    size_t b1_len = strlen(b1);
    size_t b2_len = strlen(b2);
    size_t b3_len = strlen(b3);
    size_t colorspace_len = strlen(colorspace);

    *pdf_object_size =
        b1_len + colorspace_len + b2_len + cid->nbytescomp + b3_len;
    *pdf_object = new char[*pdf_object_size];
    if (!pdf_object) {
        l_CIDataDestroy(&cid);
        return false;
    }

    char *p = *pdf_object;
    memcpy(p, b1, b1_len);
    p += b1_len;
    memcpy(p, colorspace, colorspace_len);
    p += colorspace_len;
    memcpy(p, b2, b2_len);
    p += b2_len;
    memcpy(p, cid->datacomp, cid->nbytescomp);
    p += cid->nbytescomp;
    memcpy(p, b3, b3_len);
    l_CIDataDestroy(&cid);
    return true;
}
Exemplo n.º 7
0
/*!
 *  ioFormatTest()
 *
 *      Input:  filename (input file)
 *      Return: 0 if OK; 1 on error or if the test fails
 *
 *  Notes:
 *      (1) This writes and reads a set of output files losslessly
 *          in different formats to /tmp/format/, and tests that the
 *          result before and after is unchanged.
 *      (2) This should work properly on input images of any depth,
 *          with and without colormaps.
 *      (3) All supported formats are tested for bmp, png, tiff and
 *          non-ascii pnm.  Ascii pnm also works (but who'd ever want
 *          to use it?)   We allow 2 bpp bmp, although it's not
 *          supported elsewhere.  And we don't support reading
 *          16 bpp png, although this can be turned on in pngio.c.
 *      (4) This silently skips png or tiff testing if HAVE_LIBPNG
 *          or HAVE_LIBTIFF are 0, respectively.
 */
l_int32
ioFormatTest(const char  *filename)
{
l_int32   d, equal, problems;
PIX      *pixs, *pixc, *pix1, *pix2;
PIXCMAP  *cmap;

    PROCNAME("ioFormatTest");

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

    if ((pixs = pixRead(filename)) == NULL)
        return ERROR_INT("pixs not made", procName, 1);

    lept_mkdir("lept");

        /* Note that the reader automatically removes colormaps
         * from 1 bpp BMP images, but not from 8 bpp BMP images.
         * Therefore, if our 8 bpp image initially doesn't have a
         * colormap, we are going to need to remove it from any
         * pix read from a BMP file. */
    pixc = pixClone(pixs);  /* laziness */

        /* This does not test the alpha layer pixels, because most
         * formats don't support it.  Remove any alpha.  */
    if (pixGetSpp(pixc) == 4)
        pixSetSpp(pixc, 3);
    cmap = pixGetColormap(pixc);  /* colormap; can be NULL */
    d = pixGetDepth(pixc);

    problems = FALSE;

        /* ----------------------- BMP -------------------------- */

        /* BMP works for 1, 2, 4, 8 and 32 bpp images.
         * It always writes colormaps for 1 and 8 bpp, so we must
         * remove it after readback if the input image doesn't have
         * a colormap.  Although we can write/read 2 bpp BMP, nobody
         * else can read them! */
    if (d == 1 || d == 8) {
        L_INFO("write/read bmp\n", procName);
        pixWrite(FILE_BMP, pixc, IFF_BMP);
        pix1 = pixRead(FILE_BMP);
        if (!cmap)
            pix2 = pixRemoveColormap(pix1, REMOVE_CMAP_BASED_ON_SRC);
        else
            pix2 = pixClone(pix1);
        pixEqual(pixc, pix2, &equal);
        if (!equal) {
            L_INFO("   **** bad bmp image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }

    if (d == 2 || d == 4 || d == 32) {
        L_INFO("write/read bmp\n", procName);
        pixWrite(FILE_BMP, pixc, IFF_BMP);
        pix1 = pixRead(FILE_BMP);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad bmp image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
    }

        /* ----------------------- PNG -------------------------- */
#if HAVE_LIBPNG
        /* PNG works for all depths, but here, because we strip
         * 16 --> 8 bpp on reading, we don't test png for 16 bpp. */
    if (d != 16) {
        L_INFO("write/read png\n", procName);
        pixWrite(FILE_PNG, pixc, IFF_PNG);
        pix1 = pixRead(FILE_PNG);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad png image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
    }
#endif  /* HAVE_LIBPNG */

        /* ----------------------- TIFF -------------------------- */
#if HAVE_LIBTIFF
        /* TIFF works for 1, 2, 4, 8, 16 and 32 bpp images.
         * Because 8 bpp tiff always writes 256 entry colormaps, the
         * colormap sizes may be different for 8 bpp images with
         * colormap; we are testing if the image content is the same.
         * Likewise, the 2 and 4 bpp tiff images with colormaps
         * have colormap sizes 4 and 16, rsp.  This test should
         * work properly on the content, regardless of the number
         * of color entries in pixc. */

        /* tiff uncompressed works for all pixel depths */
    L_INFO("write/read uncompressed tiff\n", procName);
    pixWrite(FILE_TIFF, pixc, IFF_TIFF);
    pix1 = pixRead(FILE_TIFF);
    pixEqual(pixc, pix1, &equal);
    if (!equal) {
        L_INFO("   **** bad tiff uncompressed image: d = %d ****\n",
               procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);

        /* tiff lzw works for all pixel depths */
    L_INFO("write/read lzw compressed tiff\n", procName);
    pixWrite(FILE_LZW, pixc, IFF_TIFF_LZW);
    pix1 = pixRead(FILE_LZW);
    pixEqual(pixc, pix1, &equal);
    if (!equal) {
        L_INFO("   **** bad tiff lzw compressed image: d = %d ****\n",
               procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);

        /* tiff adobe deflate (zip) works for all pixel depths */
    L_INFO("write/read zip compressed tiff\n", procName);
    pixWrite(FILE_ZIP, pixc, IFF_TIFF_ZIP);
    pix1 = pixRead(FILE_ZIP);
    pixEqual(pixc, pix1, &equal);
    if (!equal) {
        L_INFO("   **** bad tiff zip compressed image: d = %d ****\n",
               procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);

        /* tiff g4, g3, rle and packbits work for 1 bpp */
    if (d == 1) {
        L_INFO("write/read g4 compressed tiff\n", procName);
        pixWrite(FILE_G4, pixc, IFF_TIFF_G4);
        pix1 = pixRead(FILE_G4);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff g4 image ****\n", procName);
            problems = TRUE;
        }
        pixDestroy(&pix1);

        L_INFO("write/read g3 compressed tiff\n", procName);
        pixWrite(FILE_G3, pixc, IFF_TIFF_G3);
        pix1 = pixRead(FILE_G3);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff g3 image ****\n", procName);
            problems = TRUE;
        }
        pixDestroy(&pix1);

        L_INFO("write/read rle compressed tiff\n", procName);
        pixWrite(FILE_RLE, pixc, IFF_TIFF_RLE);
        pix1 = pixRead(FILE_RLE);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff rle image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);

        L_INFO("write/read packbits compressed tiff\n", procName);
        pixWrite(FILE_PB, pixc, IFF_TIFF_PACKBITS);
        pix1 = pixRead(FILE_PB);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff packbits image: d = %d ****\n",
                   procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
    }
#endif  /* HAVE_LIBTIFF */

        /* ----------------------- PNM -------------------------- */

        /* pnm works for 1, 2, 4, 8, 16 and 32 bpp.
         * pnm doesn't have colormaps, so when we write colormapped
         * pix out as pnm, the colormap is removed.  Thus for the test,
         * we must remove the colormap from pixc before testing.  */
    L_INFO("write/read pnm\n", procName);
    pixWrite(FILE_PNM, pixc, IFF_PNM);
    pix1 = pixRead(FILE_PNM);
    if (cmap)
        pix2 = pixRemoveColormap(pixc, REMOVE_CMAP_BASED_ON_SRC);
    else
        pix2 = pixClone(pixc);
    pixEqual(pix1, pix2, &equal);
    if (!equal) {
        L_INFO("   **** bad pnm image: d = %d ****\n", procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);
    pixDestroy(&pix2);

    if (problems == FALSE)
        L_INFO("All formats read and written OK!\n", procName);

    pixDestroy(&pixc);
    pixDestroy(&pixs);
    return problems;
}
Exemplo n.º 8
0
bool TessPDFRenderer::imageToPDFObj(Pix *pix,
                                    char *filename,
                                    long int objnum,
                                    char **pdf_object,
                                    long int *pdf_object_size) {
  size_t n;
  char b0[kBasicBufSize];
  char b1[kBasicBufSize];
  char b2[kBasicBufSize];
  if (!pdf_object_size || !pdf_object)
    return false;
  *pdf_object = nullptr;
  *pdf_object_size = 0;
  if (!filename)
    return false;

  L_Compressed_Data *cid = nullptr;
  const int kJpegQuality = 85;

  int format, sad;
  findFileFormat(filename, &format);
  if (pixGetSpp(pix) == 4 && format == IFF_PNG) {
    Pix *p1 = pixAlphaBlendUniform(pix, 0xffffff00);
    sad = pixGenerateCIData(p1, L_FLATE_ENCODE, 0, 0, &cid);
    pixDestroy(&p1);
  } else {
    sad = l_generateCIDataForPdf(filename, pix, kJpegQuality, &cid);
  }

  if (sad || !cid) {
    l_CIDataDestroy(&cid);
    return false;
  }

  const char *group4 = "";
  const char *filter;
  switch(cid->type) {
    case L_FLATE_ENCODE:
      filter = "/FlateDecode";
      break;
    case L_JPEG_ENCODE:
      filter = "/DCTDecode";
      break;
    case L_G4_ENCODE:
      filter = "/CCITTFaxDecode";
      group4 = "    /K -1\n";
      break;
    case L_JP2K_ENCODE:
      filter = "/JPXDecode";
      break;
    default:
      l_CIDataDestroy(&cid);
      return false;
  }

  // Maybe someday we will accept RGBA but today is not that day.
  // It requires creating an /SMask for the alpha channel.
  // http://stackoverflow.com/questions/14220221
  const char *colorspace;
  if (cid->ncolors > 0) {
    n = snprintf(b0, sizeof(b0),
                 "  /ColorSpace [ /Indexed /DeviceRGB %d %s ]\n",
                 cid->ncolors - 1, cid->cmapdatahex);
    if (n >= sizeof(b0)) {
      l_CIDataDestroy(&cid);
      return false;
    }
    colorspace = b0;
  } else {
    switch (cid->spp) {
      case 1:
        colorspace = "  /ColorSpace /DeviceGray\n";
        break;
      case 3:
        colorspace = "  /ColorSpace /DeviceRGB\n";
        break;
      default:
        l_CIDataDestroy(&cid);
        return false;
    }
  }

  int predictor = (cid->predictor) ? 14 : 1;

  // IMAGE
  n = snprintf(b1, sizeof(b1),
               "%ld 0 obj\n"
               "<<\n"
               "  /Length %ld\n"
               "  /Subtype /Image\n",
               objnum, (unsigned long) cid->nbytescomp);
  if (n >= sizeof(b1)) {
    l_CIDataDestroy(&cid);
    return false;
  }

  n = snprintf(b2, sizeof(b2),
               "  /Width %d\n"
               "  /Height %d\n"
               "  /BitsPerComponent %d\n"
               "  /Filter %s\n"
               "  /DecodeParms\n"
               "  <<\n"
               "    /Predictor %d\n"
               "    /Colors %d\n"
               "%s"
               "    /Columns %d\n"
               "    /BitsPerComponent %d\n"
               "  >>\n"
               ">>\n"
               "stream\n",
               cid->w, cid->h, cid->bps, filter, predictor, cid->spp,
               group4, cid->w, cid->bps);
  if (n >= sizeof(b2)) {
    l_CIDataDestroy(&cid);
    return false;
  }

  const char *b3 =
      "endstream\n"
      "endobj\n";

  size_t b1_len = strlen(b1);
  size_t b2_len = strlen(b2);
  size_t b3_len = strlen(b3);
  size_t colorspace_len = strlen(colorspace);

  *pdf_object_size =
      b1_len + colorspace_len + b2_len + cid->nbytescomp + b3_len;
  *pdf_object = new char[*pdf_object_size];

  char *p = *pdf_object;
  memcpy(p, b1, b1_len);
  p += b1_len;
  memcpy(p, colorspace, colorspace_len);
  p += colorspace_len;
  memcpy(p, b2, b2_len);
  p += b2_len;
  memcpy(p, cid->datacomp, cid->nbytescomp);
  p += cid->nbytescomp;
  memcpy(p, b3, b3_len);
  l_CIDataDestroy(&cid);
  return true;
}
Exemplo n.º 9
0
/*!
 *  ioFormatTest()
 *
 *      Input:  filename (input file)
 *      Return: 0 if OK; 1 on error or if the test fails
 *
 *  Notes:
 *      (1) This writes and reads a set of output files losslessly
 *          in different formats to /tmp/format/, and tests that the
 *          result before and after is unchanged.
 *      (2) This should work properly on input images of any depth,
 *          with and without colormaps.
 *      (3) All supported formats are tested for bmp, png, tiff and
 *          non-ascii pnm.  Ascii pnm also works (but who'd ever want
 *          to use it?)   We allow 2 bpp bmp, although it's not
 *          supported elsewhere.  And we don't support reading
 *          16 bpp png, although this can be turned on in pngio.c.
 *      (4) This silently skips png or tiff testing if HAVE_LIBPNG
 *          or HAVE_LIBTIFF are 0, respectively.
 */
l_int32
ioFormatTest(const char  *filename)
{
    l_int32    w, h, d, depth, equal, problems;
    l_float32  diff;
    BOX       *box;
    PIX       *pixs, *pixc, *pix1, *pix2;
    PIXCMAP   *cmap;

    PROCNAME("ioFormatTest");

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

    /* Read the input file and limit the size */
    if ((pix1 = pixRead(filename)) == NULL)
        return ERROR_INT("pix1 not made", procName, 1);
    pixGetDimensions(pix1, &w, &h, NULL);
    if (w > 250 && h > 250) {  /* take the central 250 x 250 region */
        box = boxCreate(w / 2 - 125, h / 2 - 125, 250, 250);
        pixs = pixClipRectangle(pix1, box, NULL);
        boxDestroy(&box);
    } else {
        pixs = pixClone(pix1);
    }
    pixDestroy(&pix1);

    lept_mkdir("lept");

    /* Note that the reader automatically removes colormaps
     * from 1 bpp BMP images, but not from 8 bpp BMP images.
     * Therefore, if our 8 bpp image initially doesn't have a
     * colormap, we are going to need to remove it from any
     * pix read from a BMP file. */
    pixc = pixClone(pixs);  /* laziness */

    /* This does not test the alpha layer pixels, because most
     * formats don't support it.  Remove any alpha.  */
    if (pixGetSpp(pixc) == 4)
        pixSetSpp(pixc, 3);
    cmap = pixGetColormap(pixc);  /* colormap; can be NULL */
    d = pixGetDepth(pixc);

    problems = FALSE;

    /* ----------------------- BMP -------------------------- */

    /* BMP works for 1, 2, 4, 8 and 32 bpp images.
     * It always writes colormaps for 1 and 8 bpp, so we must
     * remove it after readback if the input image doesn't have
     * a colormap.  Although we can write/read 2 bpp BMP, nobody
     * else can read them! */
    if (d == 1 || d == 8) {
        L_INFO("write/read bmp\n", procName);
        pixWrite(FILE_BMP, pixc, IFF_BMP);
        pix1 = pixRead(FILE_BMP);
        if (!cmap)
            pix2 = pixRemoveColormap(pix1, REMOVE_CMAP_BASED_ON_SRC);
        else
            pix2 = pixClone(pix1);
        pixEqual(pixc, pix2, &equal);
        if (!equal) {
            L_INFO("   **** bad bmp image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }

    if (d == 2 || d == 4 || d == 32) {
        L_INFO("write/read bmp\n", procName);
        pixWrite(FILE_BMP, pixc, IFF_BMP);
        pix1 = pixRead(FILE_BMP);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad bmp image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
    }

    /* ----------------------- PNG -------------------------- */
#if HAVE_LIBPNG
    /* PNG works for all depths, but here, because we strip
     * 16 --> 8 bpp on reading, we don't test png for 16 bpp. */
    if (d != 16) {
        L_INFO("write/read png\n", procName);
        pixWrite(FILE_PNG, pixc, IFF_PNG);
        pix1 = pixRead(FILE_PNG);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad png image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
    }
#endif  /* HAVE_LIBPNG */

    /* ----------------------- TIFF -------------------------- */
#if HAVE_LIBTIFF
    /* TIFF works for 1, 2, 4, 8, 16 and 32 bpp images.
     * Because 8 bpp tiff always writes 256 entry colormaps, the
     * colormap sizes may be different for 8 bpp images with
     * colormap; we are testing if the image content is the same.
     * Likewise, the 2 and 4 bpp tiff images with colormaps
     * have colormap sizes 4 and 16, rsp.  This test should
     * work properly on the content, regardless of the number
     * of color entries in pixc. */

    /* tiff uncompressed works for all pixel depths */
    L_INFO("write/read uncompressed tiff\n", procName);
    pixWrite(FILE_TIFF, pixc, IFF_TIFF);
    pix1 = pixRead(FILE_TIFF);
    pixEqual(pixc, pix1, &equal);
    if (!equal) {
        L_INFO("   **** bad tiff uncompressed image: d = %d ****\n",
               procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);

    /* tiff lzw works for all pixel depths */
    L_INFO("write/read lzw compressed tiff\n", procName);
    pixWrite(FILE_LZW, pixc, IFF_TIFF_LZW);
    pix1 = pixRead(FILE_LZW);
    pixEqual(pixc, pix1, &equal);
    if (!equal) {
        L_INFO("   **** bad tiff lzw compressed image: d = %d ****\n",
               procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);

    /* tiff adobe deflate (zip) works for all pixel depths */
    L_INFO("write/read zip compressed tiff\n", procName);
    pixWrite(FILE_ZIP, pixc, IFF_TIFF_ZIP);
    pix1 = pixRead(FILE_ZIP);
    pixEqual(pixc, pix1, &equal);
    if (!equal) {
        L_INFO("   **** bad tiff zip compressed image: d = %d ****\n",
               procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);

    /* tiff g4, g3, rle and packbits work for 1 bpp */
    if (d == 1) {
        L_INFO("write/read g4 compressed tiff\n", procName);
        pixWrite(FILE_G4, pixc, IFF_TIFF_G4);
        pix1 = pixRead(FILE_G4);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff g4 image ****\n", procName);
            problems = TRUE;
        }
        pixDestroy(&pix1);

        L_INFO("write/read g3 compressed tiff\n", procName);
        pixWrite(FILE_G3, pixc, IFF_TIFF_G3);
        pix1 = pixRead(FILE_G3);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff g3 image ****\n", procName);
            problems = TRUE;
        }
        pixDestroy(&pix1);

        L_INFO("write/read rle compressed tiff\n", procName);
        pixWrite(FILE_RLE, pixc, IFF_TIFF_RLE);
        pix1 = pixRead(FILE_RLE);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff rle image: d = %d ****\n", procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);

        L_INFO("write/read packbits compressed tiff\n", procName);
        pixWrite(FILE_PB, pixc, IFF_TIFF_PACKBITS);
        pix1 = pixRead(FILE_PB);
        pixEqual(pixc, pix1, &equal);
        if (!equal) {
            L_INFO("   **** bad tiff packbits image: d = %d ****\n",
                   procName, d);
            problems = TRUE;
        }
        pixDestroy(&pix1);
    }
#endif  /* HAVE_LIBTIFF */

    /* ----------------------- PNM -------------------------- */

    /* pnm works for 1, 2, 4, 8, 16 and 32 bpp.
     * pnm doesn't have colormaps, so when we write colormapped
     * pix out as pnm, the colormap is removed.  Thus for the test,
     * we must remove the colormap from pixc before testing.  */
    L_INFO("write/read pnm\n", procName);
    pixWrite(FILE_PNM, pixc, IFF_PNM);
    pix1 = pixRead(FILE_PNM);
    if (cmap)
        pix2 = pixRemoveColormap(pixc, REMOVE_CMAP_BASED_ON_SRC);
    else
        pix2 = pixClone(pixc);
    pixEqual(pix1, pix2, &equal);
    if (!equal) {
        L_INFO("   **** bad pnm image: d = %d ****\n", procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);
    pixDestroy(&pix2);

    /* ----------------------- GIF -------------------------- */
#if HAVE_LIBGIF
    /* GIF works for only 1 and 8 bpp, colormapped */
    if (d != 8 || !cmap)
        pix1 = pixConvertTo8(pixc, 1);
    else
        pix1 = pixClone(pixc);
    L_INFO("write/read gif\n", procName);
    pixWrite(FILE_GIF, pix1, IFF_GIF);
    pix2 = pixRead(FILE_GIF);
    pixEqual(pix1, pix2, &equal);
    if (!equal) {
        L_INFO("   **** bad gif image: d = %d ****\n", procName, d);
        problems = TRUE;
    }
    pixDestroy(&pix1);
    pixDestroy(&pix2);
#endif  /* HAVE_LIBGIF */

    /* ----------------------- JPEG ------------------------- */
#if HAVE_LIBJPEG
    /* JPEG works for only 8 bpp gray and rgb */
    if (cmap || d > 8)
        pix1 = pixConvertTo32(pixc);
    else
        pix1 = pixConvertTo8(pixc, 0);
    depth = pixGetDepth(pix1);
    L_INFO("write/read jpeg\n", procName);
    pixWrite(FILE_JPG, pix1, IFF_JFIF_JPEG);
    pix2 = pixRead(FILE_JPG);
    if (depth == 8) {
        pixCompareGray(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff,
                       NULL, NULL);
    } else {
        pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff,
                      NULL, NULL);
    }
    if (diff > 8.0) {
        L_INFO("   **** bad jpeg image: d = %d, diff = %5.2f ****\n",
               procName, depth, diff);
        problems = TRUE;
    }
    pixDestroy(&pix1);
    pixDestroy(&pix2);
#endif  /* HAVE_LIBJPEG */

    /* ----------------------- WEBP ------------------------- */
#if HAVE_LIBWEBP
    /* WEBP works for rgb and rgba */
    if (cmap || d <= 16)
        pix1 = pixConvertTo32(pixc);
    else
        pix1 = pixClone(pixc);
    depth = pixGetDepth(pix1);
    L_INFO("write/read webp\n", procName);
    pixWrite(FILE_WEBP, pix1, IFF_WEBP);
    pix2 = pixRead(FILE_WEBP);
    pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL);
    if (diff > 5.0) {
        L_INFO("   **** bad webp image: d = %d, diff = %5.2f ****\n",
               procName, depth, diff);
        problems = TRUE;
    }
    pixDestroy(&pix1);
    pixDestroy(&pix2);
#endif  /* HAVE_LIBWEBP */

    /* ----------------------- JP2K ------------------------- */
#if HAVE_LIBJP2K
    /* JP2K works for only 8 bpp gray, rgb and rgba */
    if (cmap || d > 8)
        pix1 = pixConvertTo32(pixc);
    else
        pix1 = pixConvertTo8(pixc, 0);
    depth = pixGetDepth(pix1);
    L_INFO("write/read jp2k\n", procName);
    pixWrite(FILE_JP2K, pix1, IFF_JP2);
    pix2 = pixRead(FILE_JP2K);
    if (depth == 8) {
        pixCompareGray(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff,
                       NULL, NULL);
    } else {
        pixCompareRGB(pix1, pix2, L_COMPARE_ABS_DIFF, 0, NULL, &diff,
                      NULL, NULL);
    }
    fprintf(stderr, "diff = %7.3f\n", diff);
    if (diff > 7.0) {
        L_INFO("   **** bad jp2k image: d = %d, diff = %5.2f ****\n",
               procName, depth, diff);
        problems = TRUE;
    }
    pixDestroy(&pix1);
    pixDestroy(&pix2);
#endif  /* HAVE_LIBJP2K */

    if (problems == FALSE)
        L_INFO("All formats read and written OK!\n", procName);

    pixDestroy(&pixc);
    pixDestroy(&pixs);
    return problems;
}
Exemplo n.º 10
0
/*!
 * \brief   pixWriteMemWebP()
 *
 * \param[out]   pencdata   webp encoded data of pixs
 * \param[out]   pencsize   size of webp encoded data
 * \param[in]    pixs       any depth, cmapped OK
 * \param[in]    quality    0 - 100; default ~80
 * \param[in]    lossless   use 1 for lossless; 0 for lossy
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) Lossless and lossy encoding are entirely different in webp.
 *          %quality applies to lossy, and is ignored for lossless.
 *      (2) The input image is converted to RGB if necessary.  If spp == 3,
 *          we set the alpha channel to fully opaque (255), and
 *          WebPEncodeRGBA() then removes the alpha chunk when encoding,
 *          setting the internal header field has_alpha to 0.
 * </pre>
 */
l_ok
pixWriteMemWebP(l_uint8  **pencdata,
                size_t    *pencsize,
                PIX       *pixs,
                l_int32    quality,
                l_int32    lossless)
{
l_int32    w, h, d, wpl, stride;
l_uint32  *data;
PIX       *pix1, *pix2;

    PROCNAME("pixWriteMemWebP");

    if (!pencdata)
        return ERROR_INT("&encdata not defined", procName, 1);
    *pencdata = NULL;
    if (!pencsize)
        return ERROR_INT("&encsize not defined", procName, 1);
    *pencsize = 0;
    if (!pixs)
        return ERROR_INT("&pixs not defined", procName, 1);
    if (lossless == 0 && (quality < 0 || quality > 100))
        return ERROR_INT("quality not in [0 ... 100]", procName, 1);

    if ((pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR)) == NULL)
        return ERROR_INT("failure to remove color map", procName, 1);

        /* Convert to rgb if not 32 bpp; pix2 must not be a clone of pixs. */
    if (pixGetDepth(pix1) != 32)
        pix2 = pixConvertTo32(pix1);
    else
        pix2 = pixCopy(NULL, pix1);
    pixDestroy(&pix1);
    pixGetDimensions(pix2, &w, &h, &d);
    if (w <= 0 || h <= 0 || d != 32) {
        pixDestroy(&pix2);
        return ERROR_INT("pix2 not 32 bpp or of 0 size", procName, 1);
    }

        /* If spp == 3, need to set alpha layer to opaque (all 1s). */
    if (pixGetSpp(pix2) == 3)
        pixSetComponentArbitrary(pix2, L_ALPHA_CHANNEL, 255);

        /* The WebP API expects data in RGBA order.  The pix stores
         * in host-dependent order with R as the MSB and A as the LSB.
         * On little-endian machines, the bytes in the word must
         * be swapped; e.g., R goes from byte 0 (LSB) to byte 3 (MSB).
         * No swapping is necessary for big-endians. */
    pixEndianByteSwap(pix2);
    wpl = pixGetWpl(pix2);
    data = pixGetData(pix2);
    stride = wpl * 4;
    if (lossless) {
        *pencsize = WebPEncodeLosslessRGBA((uint8_t *)data, w, h,
                                           stride, pencdata);
    } else {
        *pencsize = WebPEncodeRGBA((uint8_t *)data, w, h, stride,
                                   quality, pencdata);
    }
    pixDestroy(&pix2);

    if (*pencsize == 0) {
        free(*pencdata);
        *pencdata = NULL;
        return ERROR_INT("webp encoding failed", procName, 1);
    }

    return 0;
}
Exemplo n.º 11
0
int main(int    argc,
         char **argv)
{
l_int32       i, spp;
l_uint32      bval, wval;
PIX          *pixs, *pix1, *pix2, *pix3, *pixd;
PIXA         *pixa;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

        /* Scale each image and add a white boundary */
    pixa = pixaCreate(setsize);
    for (i = 0; i < setsize; i++) {
        pixs = pixRead(fnames[i]);
        spp = pixGetSpp(pixs);
        pixGetBlackOrWhiteVal(pixs, L_GET_WHITE_VAL, &wval);
        pixGetBlackOrWhiteVal(pixs, L_GET_BLACK_VAL, &bval);
        fprintf(stderr, "d = %d, spp = %d, bval = %x, wval = %x\n",
                pixGetDepth(pixs), spp, bval, wval);
        if (spp == 4)  /* remove alpha, using white background */
            pix1 = pixAlphaBlendUniform(pixs, wval);
        else
            pix1 = pixClone(pixs);
        pix2 = pixScaleToSize(pix1, 150, 150);
        pixGetBlackOrWhiteVal(pix2, L_GET_WHITE_VAL, &wval);
        pix3 = pixAddBorderGeneral(pix2, 30, 30, 20, 20, wval);
        pixaAddPix(pixa, pix3, L_INSERT);
        pixDestroy(&pixs);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }
    pixd = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 1, 30, 0);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);
    pixDisplayWithTitle(pixd, 0, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

        /* Scale each image and add a black boundary */
    pixa = pixaCreate(setsize);
    for (i = 0; i < setsize; i++) {
        pixs = pixRead(fnames[i]);
        spp = pixGetSpp(pixs);
        pixGetBlackOrWhiteVal(pixs, L_GET_WHITE_VAL, &wval);
        pixGetBlackOrWhiteVal(pixs, L_GET_BLACK_VAL, &bval);
        fprintf(stderr, "d = %d, spp = %d, bval = %x, wval = %x\n",
                pixGetDepth(pixs), spp, bval, wval);
        if (spp == 4)  /* remove alpha, using white background */
            pix1 = pixAlphaBlendUniform(pixs, wval);
        else
            pix1 = pixClone(pixs);
        pix2 = pixScaleToSize(pix1, 150, 150);
        pixGetBlackOrWhiteVal(pixs, L_GET_BLACK_VAL, &bval);
        pix3 = pixAddBorderGeneral(pix2, 30, 30, 20, 20, bval);
        pixaAddPix(pixa, pix3, L_INSERT);
        pixDestroy(&pixs);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }
    pixd = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 30, 0);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);
    pixDisplayWithTitle(pixd, 1000, 100, NULL, rp->display);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);

    return regTestCleanup(rp);
}
Exemplo n.º 12
0
/*!
 *  pixRotateWithAlpha()
 *
 *      Input:  pixs (32 bpp rgb or cmapped)
 *              angle (radians; clockwise is positive)
 *              pixg (<optional> 8 bpp, can be null)
 *              fract (between 0.0 and 1.0, with 0.0 fully transparent
 *                     and 1.0 fully opaque)
 *      Return: pixd (32 bpp rgba), or null on error
 *
 *  Notes:
 *      (1) The alpha channel is transformed separately from pixs,
 *          and aligns with it, being fully transparent outside the
 *          boundary of the transformed pixs.  For pixels that are fully
 *          transparent, a blending function like pixBlendWithGrayMask()
 *          will give zero weight to corresponding pixels in pixs.
 *      (2) Rotation is about the center of the image; for very small
 *          rotations, just return a clone.  The dest is automatically
 *          expanded so that no image pixels are lost.
 *      (3) Rotation is by area mapping.  It doesn't matter what
 *          color is brought in because the alpha channel will
 *          be transparent (black) there.
 *      (4) If pixg is NULL, it is generated as an alpha layer that is
 *          partially opaque, using @fract.  Otherwise, it is cropped
 *          to pixs if required and @fract is ignored.  The alpha
 *          channel in pixs is never used.
 *      (4) Colormaps are removed to 32 bpp.
 *      (5) The default setting for the border values in the alpha channel
 *          is 0 (transparent) for the outermost ring of pixels and
 *          (0.5 * fract * 255) for the second ring.  When blended over
 *          a second image, this
 *          (a) shrinks the visible image to make a clean overlap edge
 *              with an image below, and
 *          (b) softens the edges by weakening the aliasing there.
 *          Use l_setAlphaMaskBorder() to change these values.
 *      (6) A subtle use of gamma correction is to remove gamma correction
 *          before rotation and restore it afterwards.  This is done
 *          by sandwiching this function between a gamma/inverse-gamma
 *          photometric transform:
 *              pixt = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255);
 *              pixd = pixRotateWithAlpha(pixt, angle, NULL, fract);
 *              pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255);
 *              pixDestroy(&pixt);
 *          This has the side-effect of producing artifacts in the very
 *          dark regions.
 *
 *  *** Warning: implicit assumption about RGB component ordering ***
 */
PIX *
pixRotateWithAlpha(PIX *pixs,
                   l_float32 angle,
                   PIX *pixg,
                   l_float32 fract) {
    l_int32 ws, hs, d, spp;
    PIX *pixd, *pix32, *pixg2, *pixgr;

    PROCNAME("pixRotateWithAlpha");

    if (!pixs)
        return (PIX *) ERROR_PTR("pixs not defined", procName, NULL);
    pixGetDimensions(pixs, &ws, &hs, &d);
    if (d != 32 && pixGetColormap(pixs) == NULL)
        return (PIX *) ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
    if (pixg && pixGetDepth(pixg) != 8) {
        L_WARNING("pixg not 8 bpp; using @fract transparent alpha\n", procName);
        pixg = NULL;
    }
    if (!pixg && (fract < 0.0 || fract > 1.0)) {
        L_WARNING("invalid fract; using fully opaque\n", procName);
        fract = 1.0;
    }
    if (!pixg && fract == 0.0)
        L_WARNING("transparent alpha; image will not be blended\n", procName);

    /* Make sure input to rotation is 32 bpp rgb, and rotate it */
    if (d != 32)
        pix32 = pixConvertTo32(pixs);
    else
        pix32 = pixClone(pixs);
    spp = pixGetSpp(pix32);
    pixSetSpp(pix32, 3);  /* ignore the alpha channel for the rotation */
    pixd = pixRotate(pix32, angle, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, ws, hs);
    pixSetSpp(pix32, spp);  /* restore initial value in case it's a clone */
    pixDestroy(&pix32);

    /* Set up alpha layer with a fading border and rotate it */
    if (!pixg) {
        pixg2 = pixCreate(ws, hs, 8);
        if (fract == 1.0)
            pixSetAll(pixg2);
        else if (fract > 0.0)
            pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
    } else {
        pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
    }
    if (ws > 10 && hs > 10) {  /* see note 8 */
        pixSetBorderRingVal(pixg2, 1,
                            (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
        pixSetBorderRingVal(pixg2, 2,
                            (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));
    }
    pixgr = pixRotate(pixg2, angle, L_ROTATE_AREA_MAP,
                      L_BRING_IN_BLACK, ws, hs);

    /* Combine into a 4 spp result */
    pixSetRGBComponent(pixd, pixgr, L_ALPHA_CHANNEL);

    pixDestroy(&pixg2);
    pixDestroy(&pixgr);
    return pixd;
}
Exemplo n.º 13
0
/*!
 *  pixConvertToOpjImage()
 *
 *      Input:  pix  (8 or 32 bpp)
 *      Return: opj_image, or NULL on error
 *
 *  Notes:
 *      (1) Input pix is 8 bpp grayscale, 32 bpp rgb, or 32 bpp rgba.
 *      (2) Gray + alpha pix are all represented as rgba.
 */
static opj_image_t *
pixConvertToOpjImage(PIX  *pix)
{
l_int32               i, j, k, w, h, d, spp, wpl;
OPJ_COLOR_SPACE       colorspace;
l_int32              *ir = NULL;
l_int32              *ig = NULL;
l_int32              *ib = NULL;
l_int32              *ia = NULL;
l_uint32             *line, *data;
opj_image_t          *image;
opj_image_cmptparm_t  cmptparm[4];

    PROCNAME("pixConvertToOpjImage");

    if (!pix)
        return (opj_image_t *)ERROR_PTR("pix not defined", procName, NULL);
    pixGetDimensions(pix, &w, &h, &d);
    if (d != 8 && d != 32) {
        L_ERROR("invalid depth: %d\n", procName, d);
        return NULL;
    }

        /* Allocate the opj_image. */
    spp = pixGetSpp(pix);
    memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
    for (i = 0; i < spp; i++) {
        cmptparm[i].prec = 8;
        cmptparm[i].bpp = 8;
        cmptparm[i].sgnd = 0;
        cmptparm[i].dx = 1;
        cmptparm[i].dy = 1;
        cmptparm[i].w = w;
        cmptparm[i].h = h;
    }
    colorspace = (spp == 1) ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB;
    if ((image = opj_image_create(spp, &cmptparm[0], colorspace)) == NULL)
        return (opj_image_t *)ERROR_PTR("image not made", procName, NULL);
    image->x0 = 0;
    image->y0 = 0;
    image->x1 = w;
    image->y1 = h;

        /* Set the component pointers */
    ir = image->comps[0].data;
    if (spp > 1) {
        ig = image->comps[1].data;
        ib = image->comps[2].data;
    }
    if(spp == 4)
        ia = image->comps[3].data;

        /* Transfer the data from the pix */
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    for (i = 0, k = 0; i < h; i++) {
        line = data + i * wpl;
        for (j = 0; j < w; j++, k++) {
            if (spp == 1) {
                ir[k] = GET_DATA_BYTE(line, j);
            } else if (spp > 1) {
                ir[k] = GET_DATA_BYTE(line + j, COLOR_RED);
                ig[k] = GET_DATA_BYTE(line + j, COLOR_GREEN);
                ib[k] = GET_DATA_BYTE(line + j, COLOR_BLUE);
            }
            if (spp == 4)
                ia[k] = GET_DATA_BYTE(line + j, L_ALPHA_CHANNEL);
        }
    }

    return image;
}