Ejemplo n.º 1
0
/*!
 *  recogCreateFromPixa()
 *
 *      Input:  pixa (of labelled, 1 bpp images)
 *              scalew  (scale all widths to this; use 0 for no scaling)
 *              scaleh  (scale all heights to this; use 0 for no scaling)
 *              templ_type (L_USE_AVERAGE or L_USE_ALL)
 *              threshold (for binarization; typically ~128)
 *              maxyshift (from nominal centroid alignment; typically 0 or 1)
 *              fontdir  (<optional> directory for bitmap fonts for debugging)
 *      Return: recog, or null on error
 *
 *  Notes:
 *      (1) This is a convenience function for training from labelled data.
 *          The pixa can be read from file.
 *      (2) The pixa should contain the unscaled bitmaps used for training.
 *      (3) The characters here should work as a single "font", because
 *          each image example is put into a class defined by its
 *          character label.  All examples in the same class should be
 *          similar.
 */
L_RECOG *
recogCreateFromPixa(PIXA        *pixa,
                    l_int32      scalew,
                    l_int32      scaleh,
                    l_int32      templ_type,
                    l_int32      threshold,
                    l_int32      maxyshift,
                    const char  *fontdir)
{
char     *text;
l_int32   full, n, i, ntext;
L_RECOG  *recog;
PIX      *pix;

    PROCNAME("recogCreateFromPixa");

    if (!pixa)
        return (L_RECOG *)ERROR_PTR("pixa not defined", procName, NULL);
    if (pixaVerifyDepth(pixa, NULL) != 1)
        return (L_RECOG *)ERROR_PTR("not all pix are 1 bpp", procName, NULL);

    pixaIsFull(pixa, &full, NULL);
    if (!full)
        return (L_RECOG *)ERROR_PTR("not all pix are present", procName, NULL);

    n = pixaGetCount(pixa);
    pixaCountText(pixa, &ntext);
    if (ntext == 0)
        return (L_RECOG *)ERROR_PTR("no pix have text strings", procName, NULL);
    if (ntext < n)
        L_ERROR("%d text strings < %d pix\n", procName, ntext, n);

    recog = recogCreate(scalew, scaleh, templ_type, threshold,
                        maxyshift, fontdir);
    if (!recog)
        return (L_RECOG *)ERROR_PTR("recog not made", procName, NULL);
    for (i = 0; i < n; i++) {
        pix = pixaGetPix(pixa, i, L_CLONE);
        text = pixGetText(pix);
        if (!text || strlen(text) == 0) {
            L_ERROR("pix[%d] has no text\n", procName, i);
            pixDestroy(&pix);
            continue;
        }
        recogTrainLabelled(recog, pix, NULL, text, 0, 0);
        pixDestroy(&pix);
    }

    recogTrainingFinished(recog, 0);
    return recog;
}
Ejemplo n.º 2
0
/*!
 *  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;
}
Ejemplo n.º 3
0
/*!
 *  pixAddText()
 *
 *      Input:  pix
 *              textstring
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This adds the new textstring to any existing text.
 *      (2) Either or both the existing text and the new text
 *          string can be null.
 */
l_int32
pixAddText(PIX         *pix,
           const char  *textstring)
{
char  *newstring;

    PROCNAME("pixAddText");

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

    newstring = stringJoin(pixGetText(pix), textstring);
    stringReplace(&pix->text, newstring);
    FREE(newstring);
    return 0;
}
Ejemplo n.º 4
0
l_int32
pixCopyText(PIX  *pixd,
            PIX  *pixs)
{
    PROCNAME("pixCopyText");

    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 */

    pixSetText(pixd, pixGetText(pixs));
    return 0;
}
Ejemplo n.º 5
0
void MainWindow::imageInfo() {
  QString aboutImage = tr("<h1>Image info</h1>");
  aboutImage.append(tr("<p style='color:blue'>"));
  aboutImage.append(tr("width in pixels: %1<br/>").arg(pixs->w));
  aboutImage.append(tr("height in pixels: %1<br/>").arg(pixs->h));
  aboutImage.append(tr("depth in bits (bpp): %1<br/>").arg(pixs->d));
  aboutImage.append(tr("number of samples per pixel [spp]: %1<br/>")
                    .arg(pixs->spp));
  aboutImage.append(tr("32-bit words/line [wpl]: %1<br/>").arg(pixs->wpl));
  aboutImage.append(tr("resolution: %1x%2<br/>").arg(pixs->xres)
                    .arg(pixs->yres));
  aboutImage.append(tr("input format: %1</p>").arg(pixGetInputFormat(pixs)));
  char *text = pixGetText(pixs);
  if (text)
    aboutImage.append(tr("text string associated with pix: %1</p>")
                      .arg(text));
  QMessageBox::about(this, tr("About image"), aboutImage);
}
Ejemplo n.º 6
0
/*!
 *  pixFree()
 *
 *      Input:  pix
 *      Return: void
 *
 *  Notes:
 *      (1) Decrements the ref count and, if 0, destroys the pix.
 */
static void
pixFree(PIX  *pix)
{
l_uint32  *data;
char      *text;

    if (!pix) return;

    pixChangeRefcount(pix, -1);
    if (pixGetRefcount(pix) <= 0) {
        if ((data = pixGetData(pix)) != NULL)
            pix_free(data);
        if ((text = pixGetText(pix)) != NULL)
            FREE(text);
        pixDestroyColormap(pix);
        FREE(pix);
    }
    return;
}
Ejemplo n.º 7
0
l_int32 main(int    argc,
             char **argv)
{
char      *boxatxt;
l_int32    i;
BOXA      *boxa1, *boxa2, *boxa3;
BOXAA     *baa, *baa1;
NUMAA     *naa1;
PIX       *pixdb, *pix1, *pix2, *pix3, *pix4;
PIXA      *pixa1, *pixa2, *pixa3, *pixat;
L_RECOG   *recog;
L_RECOGA  *recoga;
SARRAY    *sa1;

    /* ----- Example identifying samples using training data ----- */
#if 1
        /* Read the training data */
    pixat = pixaRead("recog/sets/train06.pa");
    recog = recogCreateFromPixa(pixat, 0, 0, L_USE_ALL, 128, 1);
    recoga = recogaCreateFromRecog(recog);
    pixaDestroy(&pixat);

        /* Read the data from all samples */
    pix1 = pixRead("recog/sets/samples06.png");
    boxatxt = pixGetText(pix1);
    boxa1 = boxaReadMem((l_uint8 *)boxatxt, strlen(boxatxt));
    pixa1 = pixaCreateFromBoxa(pix1, boxa1, NULL);
    pixDestroy(&pix1);  /* destroys boxa1 */

        /* Identify components in the sample data */
    pixa2 = pixaCreate(0);
    pixa3 = pixaCreate(0);
    for (i = 0; i < 9; i++) {
/*        if (i != 4) continue; */  /* dots form separate boxa */
/*        if (i != 8) continue; */  /* broken 2 in '24' */
        pix1 = pixaGetPix(pixa1, i, L_CLONE);

            /* Show the 2d box data in the sample */
        boxa2 = pixConnComp(pix1, NULL, 8);
        baa = boxaSort2d(boxa2, NULL, 6, 6, 5);
        pix2 = boxaaDisplay(baa, 3, 1, 0xff000000, 0x00ff0000, 0, 0);
        pixaAddPix(pixa3, pix2, L_INSERT);
        boxaaDestroy(&baa);
        boxaDestroy(&boxa2);

            /* Get the numbers in the sample */
        recogaIdentifyMultiple(recoga, pix1, 0, 5, 3, &boxa3, NULL, &pixdb, 0);
        sa1 = recogaExtractNumbers(recoga, boxa3, 0.7, -1, &baa1, &naa1);
        sarrayWriteStream(stderr, sa1);
        boxaaWriteStream(stderr, baa1);
        numaaWriteStream(stderr, naa1);
        pixaAddPix(pixa2, pixdb, L_INSERT);
/*        pixaWrite("/tmp/pixa.pa", pixa2); */
        pixDestroy(&pix1);
        boxaDestroy(&boxa3);
        boxaaDestroy(&baa1);
        numaaDestroy(&naa1);
        sarrayDestroy(&sa1);
    }

    pix3 = pixaDisplayLinearly(pixa2, L_VERT, 1.0, 0, 20, 1, NULL);
    pixWrite("/tmp/pix3.png", pix3, IFF_PNG);
    pix4 = pixaDisplayTiledInRows(pixa3, 32, 1500, 1.0, 0, 20, 2);
    pixDisplay(pix4, 500, 0);
    pixWrite("/tmp/pix4.png", pix4, IFF_PNG);
    pixaDestroy(&pixa2);
    pixaDestroy(&pixa3);
    pixDestroy(&pix1);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixaDestroy(&pixa1);
    boxaDestroy(&boxa1);
    recogaDestroy(&recoga);
#endif

    return 0;
}
Ejemplo n.º 8
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;
}
Ejemplo n.º 9
0
/*!
 *  pixWriteStreamPng()
 *
 *      Input:  stream
 *              pix
 *              gamma (use 0.0 if gamma is not defined)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) If called from pixWriteStream(), the stream is positioned
 *          at the beginning of the file.
 *      (2) To do sequential writes of png format images to a stream,
 *          use pixWriteStreamPng() directly.
 *      (3) gamma is an optional png chunk.  If no gamma value is to be
 *          placed into the file, use gamma = 0.0.  Otherwise, if
 *          gamma > 0.0, its value is written into the header.
 *      (4) The use of gamma in png is highly problematic.  For an illuminating
 *          discussion, see:  http://hsivonen.iki.fi/png-gamma/
 *      (5) What is the effect/meaning of gamma in the png file?  This
 *          gamma, which we can call the 'source' gamma, is the
 *          inverse of the gamma that was used in enhance.c to brighten
 *          or darken images.  The 'source' gamma is supposed to indicate
 *          the intensity mapping that was done at the time the
 *          image was captured.  Display programs typically apply a
 *          'display' gamma of 2.2 to the output, which is intended
 *          to linearize the intensity based on the response of
 *          thermionic tubes (CRTs).  Flat panel LCDs have typically
 *          been designed to give a similar response as CRTs (call it
 *          "backward compatibility").  The 'display' gamma is
 *          in some sense the inverse of the 'source' gamma.
 *          jpeg encoders attached to scanners and cameras will lighten
 *          the pixels, applying a gamma corresponding to approximately
 *          a square-root relation of output vs input:
 *                output = input^(gamma)
 *          where gamma is often set near 0.4545  (1/gamma is 2.2).
 *          This is stored in the image file.  Then if the display
 *          program reads the gamma, it will apply a display gamma,
 *          typically about 2.2; the product is 1.0, and the
 *          display program produces a linear output.  This works because
 *          the dark colors were appropriately boosted by the scanner,
 *          as described by the 'source' gamma, so they should not
 *          be further boosted by the display program.
 *      (6) As an example, with xv and display, if no gamma is stored,
 *          the program acts as if gamma were 0.4545, multiplies this by 2.2,
 *          and does a linear rendering.  Taking this as a baseline
 *          brightness, if the stored gamma is:
 *              > 0.4545, the image is rendered lighter than baseline
 *              < 0.4545, the image is rendered darker than baseline
 *          In contrast, gqview seems to ignore the gamma chunk in png.
 *      (7) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
 *          and 32.  However, it is possible, and in some cases desirable,
 *          to write out a png file using an rgb pix that has 24 bpp.
 *          For example, the open source xpdf SplashBitmap class generates
 *          24 bpp rgb images.  Consequently, we anble writing 24 bpp pix.
 *          To generate such a pix, you can make a 24 bpp pix without data
 *          and assign the data array to the pix; e.g.,
 *              pix = pixCreateHeader(w, h, 24);
 *              pixSetData(pix, rgbdata);
 *          See pixConvert32To24() for an example, where we get rgbdata
 *          from the 32 bpp pix.  Caution: do not call pixSetPadBits(),
 *          because the alignment is wrong and you may erase part of the
 *          last pixel on each line.
 */
l_int32
pixWriteStreamPng(FILE      *fp,
                  PIX       *pix,
                  l_float32  gamma)
{
char         commentstring[] = "Comment";
l_int32      i, j, k;
l_int32      wpl, d, cmflag;
l_int32      ncolors;
l_int32     *rmap, *gmap, *bmap;
l_uint32    *data, *ppixel;
png_byte     bit_depth, color_type;
png_uint_32  w, h;
png_uint_32  xres, yres;
png_bytep   *row_pointers;
png_bytep    rowbuffer;
png_structp  png_ptr;
png_infop    info_ptr;
png_colorp   palette;
PIX         *pixt;
PIXCMAP     *cmap;
char        *text;

    PROCNAME("pixWriteStreamPng");

    if (!fp)
        return ERROR_INT("stream not open", procName, 1);
    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);

        /* Allocate the 2 data structures */
    if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                   (png_voidp)NULL, NULL, NULL)) == NULL)
        return ERROR_INT("png_ptr not made", procName, 1);

    if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        return ERROR_INT("info_ptr not made", procName, 1);
    }

        /* Set up png setjmp error handling */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return ERROR_INT("internal png error", procName, 1);
    }

    png_init_io(png_ptr, fp);

        /* With best zlib compression (9), get between 1 and 10% improvement
         * over default (5), but the compression is 3 to 10 times slower.
         * Our default compression is the zlib default (5). */
    png_set_compression_level(png_ptr, var_ZLIB_COMPRESSION);

    w = pixGetWidth(pix);
    h = pixGetHeight(pix);
    d = pixGetDepth(pix);
    if ((cmap = pixGetColormap(pix)))
        cmflag = 1;
    else
        cmflag = 0;

        /* Set the color type and bit depth. */
    if (d == 32 && var_PNG_WRITE_ALPHA == 1) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGBA;   /* 6 */
        cmflag = 0;  /* ignore if it exists */
    }
    else if (d == 24 || d == 32) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGB;   /* 2 */
        cmflag = 0;  /* ignore if it exists */
    }
    else {
        bit_depth = d;
        color_type = PNG_COLOR_TYPE_GRAY;  /* 0 */
    }
    if (cmflag)
        color_type = PNG_COLOR_TYPE_PALETTE;  /* 3 */

#if  DEBUG
    fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n",
            cmflag, bit_depth, color_type);
#endif  /* DEBUG */

    png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);

        /* Store resolution in ppm, if known */
    xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
    yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
    if ((xres == 0) || (yres == 0))
        png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN);
    else
        png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER);

    if (cmflag) {
        pixcmapToArrays(cmap, &rmap, &gmap, &bmap);
        ncolors = pixcmapGetCount(cmap);

            /* Make and save the palette */
        if ((palette = (png_colorp)(CALLOC(ncolors, sizeof(png_color))))
                == NULL)
            return ERROR_INT("palette not made", procName, 1);

        for (i = 0; i < ncolors; i++) {
            palette[i].red = (png_byte)rmap[i];
            palette[i].green = (png_byte)gmap[i];
            palette[i].blue = (png_byte)bmap[i];
        }

        png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors);
        FREE(rmap);
        FREE(gmap);
        FREE(bmap);
    }

        /* 0.4545 is treated as the default by some image
         * display programs (not gqview).  A value > 0.4545 will
         * lighten an image as displayed by xv, display, etc. */
    if (gamma > 0.0)
        png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma);

    if ((text = pixGetText(pix))) {
        png_text text_chunk;
        text_chunk.compression = PNG_TEXT_COMPRESSION_NONE;
        text_chunk.key = commentstring;
        text_chunk.text = text;
        text_chunk.text_length = strlen(text);
#ifdef PNG_ITXT_SUPPORTED
        text_chunk.itxt_length = 0;
        text_chunk.lang = NULL;
        text_chunk.lang_key = NULL;
#endif
        png_set_text(png_ptr, info_ptr, &text_chunk, 1);
    }

        /* Write header and palette info */
    png_write_info(png_ptr, info_ptr);

    if ((d != 32) && (d != 24)) {  /* not rgb color */
            /* Generate a temporary pix with bytes swapped.
             * For a binary image, there are two conditions in
             * which you must first invert the data for writing png:
             *    (a) no colormap
             *    (b) colormap with BLACK set to 0
             * png writes binary with BLACK = 0, unless contradicted
             * by a colormap.  If the colormap has BLACK = "1"
             * (typ. about 255), do not invert the data.  If there
             * is no colormap, you must invert the data to store
             * in default BLACK = 0 state.  */
        if (d == 1 &&
            (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) {
            pixt = pixInvert(NULL, pix);
            pixEndianByteSwap(pixt);
        }
        else
            pixt = pixEndianByteSwapNew(pix);
        if (!pixt) {
            png_destroy_write_struct(&png_ptr, &info_ptr);
            return ERROR_INT("pixt not made", procName, 1);
        }

            /* Make and assign array of image row pointers */
        if ((row_pointers = (png_bytep *)CALLOC(h, sizeof(png_bytep))) == NULL)
            return ERROR_INT("row-pointers not made", procName, 1);
        wpl = pixGetWpl(pixt);
        data = pixGetData(pixt);
        for (i = 0; i < h; i++)
            row_pointers[i] = (png_bytep)(data + i * wpl);
        png_set_rows(png_ptr, info_ptr, row_pointers);

            /* Transfer the data */
        png_write_image(png_ptr, row_pointers);
        png_write_end(png_ptr, info_ptr);

        if (cmflag)
            FREE(palette);
        FREE(row_pointers);
        pixDestroy(&pixt);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return 0;
    }

        /* For rgb, compose and write a row at a time */
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    if (d == 24) {  /* See note 7 above: special case of 24 bpp rgb */
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            png_write_rows(png_ptr, (png_bytepp)&ppixel, 1);
        }
    }
    else {  /* 32 bpp rgb and rgba */
        if ((rowbuffer = (png_bytep)CALLOC(w, 4)) == NULL)
            return ERROR_INT("rowbuffer not made", procName, 1);
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            for (j = k = 0; j < w; j++) {
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                if (var_PNG_WRITE_ALPHA == 1)
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
                ppixel++;
            }

            png_write_rows(png_ptr, &rowbuffer, 1);
        }
        FREE(rowbuffer);
    }

    png_write_end(png_ptr, info_ptr);

    if (cmflag)
        FREE(palette);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return 0;

}
Ejemplo n.º 10
0
int main(int argc,
         char **argv) {
    char buf[32];
    char *filein, *fileout, *fontdir, *textstr;
    l_int32 n, i, maxdepth, ntext, border, lossless, display, showtext;
    l_float32 scalefact;
    L_BMF *bmf;
    PIX *pix1, *pix2, *pix3, *pix4, *pixd;
    PIXA *pixa, *pixad;
    static char mainName[] = "displaypixa";

    if (argc != 3 && argc != 4 && argc != 7 && argc != 8) {
        fprintf(stderr, "Syntax error in displaypixa:\n"
                "   displaypixa filein fileout [showtext]\n"
                "   displaypixa filein scalefact border"
                " lossless disp fileout [showtext]\n");
        return 1;
    }

    filein = argv[1];
    if ((pixa = pixaRead(filein)) == NULL)
        return ERROR_INT("pixa not made", mainName, 1);
    pixaCountText(pixa, &ntext);

    if (argc == 3 || argc == 4)
        fileout = argv[2];
    if (argc == 4)
        showtext = atoi(argv[3]);

    /* Simple specification; no output text */
    if (argc == 3 ||
        (argc == 4 && (ntext == 0 || showtext == 0))) {  /* no text output */
        pixaVerifyDepth(pixa, &maxdepth);
        pixd = pixaDisplayTiledInRows(pixa, maxdepth, 1400, 1.0, 0, 10, 0);
        pixDisplay(pixd, 100, 100);
        if (pixGetDepth(pixd) == 1)
            pixWrite(fileout, pixd, IFF_PNG);
        else
            pixWrite(fileout, pixd, IFF_JFIF_JPEG);
        pixDestroy(&pixd);
        pixaDestroy(&pixa);
        return 0;
    }

    /* Simple specification with output text */
    if (argc == 4) {  /* showtext == 1 && ntext > 0 */
        n = pixaGetCount(pixa);
        bmf = bmfCreate(NULL, 6);
        pixad = pixaCreate(n);
        for (i = 0; i < n; i++) {
            pix1 = pixaGetPix(pixa, i, L_CLONE);
            pix2 = pixConvertTo32(pix1);
            pix3 = pixAddBorderGeneral(pix2, 10, 10, 5, 5, 0xffffff00);
            textstr = pixGetText(pix1);
            if (textstr && strlen(textstr) > 0) {
                snprintf(buf, sizeof(buf), "%s", textstr);
                pix4 = pixAddSingleTextblock(pix3, bmf, buf, 0xff000000,
                                             L_ADD_BELOW, NULL);
            } else {
                pix4 = pixClone(pix3);
            }
            pixaAddPix(pixad, pix4, L_INSERT);
            pixDestroy(&pix1);
            pixDestroy(&pix2);
            pixDestroy(&pix3);
        }
        bmfDestroy(&bmf);
        pixaVerifyDepth(pixad, &maxdepth);
        pixd = pixaDisplayTiledInRows(pixad, maxdepth, 1400, 1.0, 0, 10, 0);
        pixDisplay(pixd, 100, 100);
        if (pixGetDepth(pixd) == 1)
            pixWrite(fileout, pixd, IFF_PNG);
        else
            pixWrite(fileout, pixd, IFF_JFIF_JPEG);
        pixDestroy(&pixd);
        pixaDestroy(&pixa);
        pixaDestroy(&pixad);
        return 0;
    }

    /* Full specification */
    scalefact = atof(argv[2]);
    border = atoi(argv[3]);
    lossless = atoi(argv[4]);
    display = atoi(argv[5]);
    fileout = argv[6];
    showtext = (argc == 8) ? atoi(argv[7]) : 0;
    if (showtext && ntext == 0)
        L_INFO("No text found in any of the pix\n", mainName);
    bmf = (showtext && ntext > 0) ? bmfCreate(NULL, 6) : NULL;
    n = pixaGetCount(pixa);
    pixad = pixaCreate(n);
    for (i = 0; i < n; i++) {
        pix1 = pixaGetPix(pixa, i, L_CLONE);
        pix2 = pixConvertTo32(pix1);
        pix3 = pixAddBorderGeneral(pix2, 10, 10, 5, 5, 0xffffff00);
        textstr = pixGetText(pix1);
        if (bmf && textstr && strlen(textstr) > 0) {
            snprintf(buf, sizeof(buf), "%s", textstr);
            pix4 = pixAddSingleTextblock(pix3, bmf, buf, 0xff000000,
                                         L_ADD_BELOW, NULL);
        } else {
            pix4 = pixClone(pix3);
        }
        pixaAddPix(pixad, pix4, L_INSERT);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
    }
    bmfDestroy(&bmf);

    pixaVerifyDepth(pixad, &maxdepth);
    pixd = pixaDisplayTiledInRows(pixad, maxdepth, 1400, scalefact,
                                  0, 10, border);
    if (display) pixDisplay(pixd, 20, 20);
    if (pixGetDepth(pixd) == 1 || lossless)
        pixWrite(fileout, pixd, IFF_PNG);
    else
        pixWrite(fileout, pixd, IFF_JFIF_JPEG);

    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    pixaDestroy(&pixad);
    return 0;
}
Ejemplo n.º 11
0
/*!
 * \brief   pixWriteStreamJpeg()
 *
 * \param[in]    fp file stream
 * \param[in]    pixs  any depth; cmap is OK
 * \param[in]    quality  1 - 100; 75 is default value; 0 is also default
 * \param[in]    progressive 0 for baseline sequential; 1 for progressive
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) Progressive encoding gives better compression, at the
 *          expense of slower encoding and decoding.
 *      (2) Standard chroma subsampling is 2x2 on both the U and V
 *          channels.  For highest quality, use no subsampling; this
 *          option is set by pixSetChromaSampling(pix, 0).
 *      (3) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
 *          and 32 bpp.  However, it is possible, and in some cases desirable,
 *          to write out a jpeg file using an rgb pix that has 24 bpp.
 *          This can be created by appending the raster data for a 24 bpp
 *          image (with proper scanline padding) directly to a 24 bpp
 *          pix that was created without a data array.
 *      (4) There are two compression paths in this function:
 *          * Grayscale image, no colormap: compress as 8 bpp image.
 *          * rgb full color image: copy each line into the color
 *            line buffer, and compress as three 8 bpp images.
 *      (5) Under the covers, the jpeg library transforms rgb to a
 *          luminance-chromaticity triple, each component of which is
 *          also 8 bits, and compresses that.  It uses 2 Huffman tables,
 *          a higher resolution one (with more quantization levels)
 *          for luminosity and a lower resolution one for the chromas.
 * </pre>
 */
l_int32
pixWriteStreamJpeg(FILE    *fp,
                   PIX     *pixs,
                   l_int32  quality,
                   l_int32  progressive)
{
l_int32                      xres, yres;
l_int32                      i, j, k;
l_int32                      w, h, d, wpl, spp, colorflag, rowsamples;
l_uint32                    *ppixel, *line, *data;
JSAMPROW                     rowbuffer;
PIX                         *pix;
struct jpeg_compress_struct  cinfo;
struct jpeg_error_mgr        jerr;
const char                  *text;
jmp_buf                      jmpbuf;  /* must be local to the function */

    PROCNAME("pixWriteStreamJpeg");

    if (!fp)
        return ERROR_INT("stream not open", procName, 1);
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (quality <= 0)
        quality = 75;  /* default */

        /* If necessary, convert the pix so that it can be jpeg compressed.
         * The colormap is removed based on the source, so if the colormap
         * has only gray colors, the image will be compressed with spp = 1. */
    pixGetDimensions(pixs, &w, &h, &d);
    pix = NULL;
    if (pixGetColormap(pixs) != NULL) {
        L_INFO("removing colormap; may be better to compress losslessly\n",
               procName);
        pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
    } else if (d >= 8 && d != 16) {  /* normal case; no rewrite */
        pix = pixClone(pixs);
    } else if (d < 8 || d == 16) {
        L_INFO("converting from %d to 8 bpp\n", procName, d);
        pix = pixConvertTo8(pixs, 0);  /* 8 bpp, no cmap */
    } else {
        L_ERROR("unknown pix type with d = %d and no cmap\n", procName, d);
        return 1;
    }
    if (!pix)
        return ERROR_INT("pix not made", procName, 1);

    rewind(fp);
    rowbuffer = NULL;

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

        /* Initialize the jpeg structs for compression */
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, fp);
    cinfo.image_width  = w;
    cinfo.image_height = h;

        /* Set the color space and number of components */
    d = pixGetDepth(pix);
    if (d == 8) {
        colorflag = 0;    /* 8 bpp grayscale; no cmap */
        cinfo.input_components = 1;
        cinfo.in_color_space = JCS_GRAYSCALE;
    } else {  /* d == 32 || d == 24 */
        colorflag = 1;    /* rgb */
        cinfo.input_components = 3;
        cinfo.in_color_space = JCS_RGB;
    }

    jpeg_set_defaults(&cinfo);

        /* Setting optimize_coding to TRUE seems to improve compression
         * by approx 2-4 percent, and increases comp time by approx 20%. */
    cinfo.optimize_coding = FALSE;

        /* Set resolution in pixels/in (density_unit: 1 = in, 2 = cm) */
    xres = pixGetXRes(pix);
    yres = pixGetYRes(pix);
    if ((xres != 0) && (yres != 0)) {
        cinfo.density_unit = 1;  /* designates pixels per inch */
        cinfo.X_density = xres;
        cinfo.Y_density = yres;
    }

        /* Set the quality and progressive parameters */
    jpeg_set_quality(&cinfo, quality, TRUE);
    if (progressive)
        jpeg_simple_progression(&cinfo);

        /* Set the chroma subsampling parameters.  This is done in
         * YUV color space.  The Y (intensity) channel is never subsampled.
         * The standard subsampling is 2x2 on both the U and V channels.
         * Notation on this is confusing.  For a nice illustrations, see
         *   http://en.wikipedia.org/wiki/Chroma_subsampling
         * The standard subsampling is written as 4:2:0.
         * We allow high quality where there is no subsampling on the
         * chroma channels: denoted as 4:4:4.  */
    if (pixs->special == L_NO_CHROMA_SAMPLING_JPEG) {
        cinfo.comp_info[0].h_samp_factor = 1;
        cinfo.comp_info[0].v_samp_factor = 1;
        cinfo.comp_info[1].h_samp_factor = 1;
        cinfo.comp_info[1].v_samp_factor = 1;
        cinfo.comp_info[2].h_samp_factor = 1;
        cinfo.comp_info[2].v_samp_factor = 1;
    }

    jpeg_start_compress(&cinfo, TRUE);

    if ((text = pixGetText(pix)))
        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text));

        /* Allocate row buffer */
    spp = cinfo.input_components;
    rowsamples = spp * w;
    if ((rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), rowsamples))
        == NULL) {
        pixDestroy(&pix);
        return ERROR_INT("calloc fail for rowbuffer", procName, 1);
    }

    data = pixGetData(pix);
    wpl  = pixGetWpl(pix);
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (colorflag == 0) {        /* 8 bpp gray */
            for (j = 0; j < w; j++)
                rowbuffer[j] = GET_DATA_BYTE(line, j);
        } else {  /* colorflag == 1 */
            if (d == 24) {  /* See note 3 above; special case of 24 bpp rgb */
                jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1);
            } else {  /* standard 32 bpp rgb */
                ppixel = line;
                for (j = k = 0; j < w; j++) {
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                    ppixel++;
                }
            }
        }
        if (d != 24)
            jpeg_write_scanlines(&cinfo, &rowbuffer, 1);
    }
    jpeg_finish_compress(&cinfo);

    pixDestroy(&pix);
    LEPT_FREE(rowbuffer);
    jpeg_destroy_compress(&cinfo);
    return 0;
}
Ejemplo n.º 12
0
/* ----------------------------------------------------- */
void ProcessDigits(l_int32  index)
{
char       rootname[8] = "digit5";
char       buf[64];
l_int32    i, nc, ns, same;
NUMA      *na1;
PIX       *pix1, *pix2, *pix3, *pix4, *pix5, *pix6;
PIXA      *pixa1, *pixa2, *pixa3;

        /* Read the unfiltered, unscaled pixa of twenty-five 5s */
    snprintf(buf, sizeof(buf), "digits/%s.orig-25.pa", rootname);
    pixa1 = pixaRead(buf);

        /* Number and show the input images */
    snprintf(buf, sizeof(buf), "/tmp/lept/digit/%s.orig-num", rootname);
    PixaDisplayNumbered(pixa1, buf);

        /* Remove some of them */
    na1 = numaCreateFromString(removeset);
    pixaRemoveSelected(pixa1, na1);
    numaDestroy(&na1);
    snprintf(buf, sizeof(buf), "/tmp/lept/digit/%s.filt.pa", rootname);
    pixaWrite(buf, pixa1);

        /* Number and show the filtered images */
    snprintf(buf, sizeof(buf), "/tmp/lept/digit/%s.filt-num", rootname);
    PixaDisplayNumbered(pixa1, buf);

        /* Extract the largest c.c., clip to the foreground,
         * and scale the result to a fixed size. */
    nc = pixaGetCount(pixa1);
    pixa2 = pixaCreate(nc);
    for (i = 0; i < nc; i++) {
        pix1 = pixaGetPix(pixa1, i, L_CLONE);
            /* A threshold of 140 gives reasonable results */
        pix2 = pixThresholdToBinary(pix1, 140);
            /* Join nearly touching pieces */
        pix3 = pixCloseSafeBrick(NULL, pix2, 5, 5);
            /* Take the largest (by area) connected component */
        pix4 = pixFilterComponentBySize(pix3, 0, L_SELECT_BY_AREA, 8, NULL);
            /* Extract the original 1 bpp pixels that have been
             * covered by the closing operation */
        pixAnd(pix4, pix4, pix2);
            /* Grab the result as an image with no surrounding whitespace */
        pixClipToForeground(pix4, &pix5, NULL);
            /* Rescale the result to the canonical size */
        pix6 = pixScaleToSize(pix5, 20, 30);
        pixaAddPix(pixa2, pix6, L_INSERT);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
        pixDestroy(&pix3);
        pixDestroy(&pix4);
        pixDestroy(&pix5);
    }

        /* Add the index (a "5") in the text field of each pix; save pixa2 */
    snprintf(buf, sizeof(buf), "%d", index);
    for (i = 0; i < nc; i++) {
        pix1 = pixaGetPix(pixa2, i, L_CLONE);
        pixSetText(pix1, buf);
        pixDestroy(&pix1);
    }
    snprintf(buf, sizeof(buf), "/tmp/lept/digit/%s.comp.pa", rootname);
    pixaWrite(buf, pixa2);

        /* Number and show the resulting binary templates */
    snprintf(buf, sizeof(buf), "/tmp/lept/digit/%s.comp-num", rootname);
    PixaDisplayNumbered(pixa2, buf);

        /* Save the binary templates as a packed tiling (tiff g4).
         * This is the most efficient way to represent the templates. */
    pix1 = pixaDisplayOnLattice(pixa2, 20, 30, NULL, NULL);
    pixDisplay(pix1, 1000, 500);
    snprintf(buf, sizeof(buf), "/tmp/lept/digit/%s.comp.tif", rootname);
    pixWrite(buf, pix1, IFF_TIFF_G4);

        /* The number of templates is in the pix text string; check it. */
    pix2 = pixRead(buf);
    if (sscanf(pixGetText(pix2), "n = %d", &ns) != 1)
        fprintf(stderr, "Failed to read the number of templates!\n");
    if (ns != nc)
        fprintf(stderr, "(stored = %d) != (actual number = %d)\n", ns, nc);

        /* Reconstruct the pixa of templates from the tiled compressed
         * image, and verify that the resulting pixa is the same.  */
    pixa3 = pixaMakeFromTiledPix(pix1, 20, 30, 0, 0, NULL);
    pixaEqual(pixa2, pixa3, 0, NULL, &same);
    if (!same)
        fprintf(stderr, "Pixa are not the same!\n");

    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixaDestroy(&pixa1);
    pixaDestroy(&pixa2);
    pixaDestroy(&pixa3);
}
Ejemplo n.º 13
0
main(int    argc,
     char **argv)
{
char        *text;
l_int32      w, h, d, wpl, count, npages, color, format, bps, spp, iscmap;
FILE        *fp;
PIX         *pix;
PIXCMAP     *cmap;
char        *filein;
static char  mainName[] = "fileinfo";

    if (argc != 2)
	exit(ERROR_INT(" Syntax:  fileinfo filein", mainName, 1));
    filein = argv[1];

    l_pngSetStrip16To8(0);  /* to preserve 16 bpp if format is png */

        /* Read the full image */
    if ((pix = pixRead(filein)) == NULL)
	exit(ERROR_INT("image not returned from file", mainName, 1));

    format = pixGetInputFormat(pix);
    pixGetDimensions(pix, &w, &h, &d);
    wpl = pixGetWpl(pix);
    fprintf(stderr, "Reading the full image:\n");
    fprintf(stderr, "  Input image format type: %s\n",
            ImageFileFormatExtensions[format]);
    fprintf(stderr, "  w = %d, h = %d, d = %d, wpl = %d\n", w, h, d, wpl);
    fprintf(stderr, "  xres = %d, yres = %d\n",
            pixGetXRes(pix), pixGetYRes(pix));

    text = pixGetText(pix);
    if (text)  /*  not null */
        fprintf(stderr, "  Text: %s\n", text);

    cmap = pixGetColormap(pix);
    if (cmap) {
        pixcmapHasColor(cmap, &color);
        if (color)
            fprintf(stderr, "  Colormap exists and has color values:");
        else
            fprintf(stderr, "  Colormap exists and has only gray values:");
	pixcmapWriteStream(stderr, pixGetColormap(pix));
    }
    else
	fprintf(stderr, "  Colormap does not exist.\n");

    if (format == IFF_TIFF || format == IFF_TIFF_G4 ||
        format == IFF_TIFF_G3 || format == IFF_TIFF_PACKBITS) {
        fprintf(stderr, "  Tiff header information:\n");
        fp = lept_fopen(filein, "rb");
        tiffGetCount(fp, &npages);
        lept_fclose(fp);
        if (npages == 1)
            fprintf(stderr, "    One page in file\n");
        else
            fprintf(stderr, "    %d pages in file\n", npages);
        fprintTiffInfo(stderr, filein);
    }

    if (d == 1) {
        pixCountPixels(pix, &count, NULL);
	fprintf(stderr, "  1 bpp: pixel ratio ON/OFF = %6.3f\n",
          (l_float32)count / (l_float32)(pixGetWidth(pix) * pixGetHeight(pix)));
    }

    pixDestroy(&pix);

        /* Test pixReadHeader() */
    if (pixReadHeader(filein, &format, &w, &h, &bps, &spp, &iscmap)) {
        fprintf(stderr, "Failure to read header!\n");
        return 1;
    }
    fprintf(stderr, "Reading just the header:\n");
    fprintf(stderr, "  Input image format type: %s\n",
            ImageFileFormatExtensions[format]);
    fprintf(stderr,
            "  w = %d, h = %d, d = %d, bps = %d, spp = %d, iscmap = %d\n",
            w, h, d, bps, spp, iscmap);
    return 0;
}
Ejemplo n.º 14
0
/*!
 *  pixWriteStreamJpeg()
 *
 *      Input:  stream
 *              pix  (8 or 32 bpp)
 *              quality  (1 - 100; 75 is default value; 0 is also default)
 *              progressive (0 for baseline sequential; 1 for progressive)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) Under the covers, the library transforms rgb to a
 *          luminence-chromaticity triple, each component of which is
 *          also 8 bits, and compresses that.  It uses 2 Huffman tables,
 *          a higher resolution one (with more quantization levels)
 *          for luminosity and a lower resolution one for the chromas.
 *      (2) Progressive encoding gives better compression, at the
 *          expense of slower encoding and decoding.
 *      (3) Standard chroma subsampling is 2x2 on both the U and V
 *          channels.  For highest quality, use no subsampling.  This
 *          option is set by l_jpegSetNoChromaSampling(1).
 *      (4) There are three possibilities:
 *          * Grayscale image, no colormap: compress as 8 bpp image.
 *          * rgb full color image: copy each line into the color
 *            line buffer, and compress as three 8 bpp images.
 *          * 8 bpp colormapped image: convert each line to three
 *            8 bpp line images in the color line buffer, and
 *            compress as three 8 bpp images.
 *      (5) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
 *          and 32 bpp.  However, it is possible, and in some cases desirable,
 *          to write out a jpeg file using an rgb pix that has 24 bpp.
 *          This can be created by appending the raster data for a 24 bpp
 *          image (with proper scanline padding) directly to a 24 bpp
 *          pix that was created without a data array.  See note in
 *          pixWriteStreamPng() for an example.
 */
l_int32
pixWriteStreamJpeg(FILE    *fp,
                   PIX     *pix,
                   l_int32  quality,
                   l_int32  progressive)
{
l_uint8                      byteval;
l_int32                      xres, yres;
l_int32                      i, j, k;
l_int32                      w, h, d, wpl, spp, colorflg, rowsamples;
l_int32                     *rmap, *gmap, *bmap;
l_uint32                    *ppixel, *line, *data;
JSAMPROW                     rowbuffer;
PIXCMAP                     *cmap;
struct jpeg_compress_struct  cinfo;
struct jpeg_error_mgr        jerr;
const char                  *text;

    PROCNAME("pixWriteStreamJpeg");

    if (!fp)
        return ERROR_INT("stream not open", procName, 1);
    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);
    rewind(fp);

    if (setjmp(jpeg_jmpbuf)) {
        FREE(rowbuffer);
        if (colorflg == 1) {
            FREE(rmap);
            FREE(gmap);
            FREE(bmap);
        }
        return ERROR_INT("internal jpeg error", procName, 1);
    }

    rowbuffer = NULL;
    rmap = NULL;
    gmap = NULL;
    bmap = NULL;
    pixGetDimensions(pix, &w, &h, &d);
    if (d != 8 && d != 24 && d != 32)
        return ERROR_INT("bpp must be 8, 24 or 32", procName, 1);

    if (quality <= 0)
        quality = 75;  /* default */

    if (d == 32 || d == 24)
        colorflg = 2;    /* rgb; no colormap */
    else if ((cmap = pixGetColormap(pix)) == NULL)
        colorflg = 0;    /* 8 bpp grayscale; no colormap */
    else {
        colorflg = 1;    /* 8 bpp; colormap */
        pixcmapToArrays(cmap, &rmap, &gmap, &bmap);
    }

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

    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, fp);

    cinfo.image_width  = w;
    cinfo.image_height = h;

    if (colorflg == 0) {
        cinfo.input_components = 1;
        cinfo.in_color_space = JCS_GRAYSCALE;
    }
    else {  /* colorflg == 1 or 2 */
        cinfo.input_components = 3;
        cinfo.in_color_space = JCS_RGB;
    }

    jpeg_set_defaults(&cinfo);

        /* Setting optimize_coding to TRUE seems to improve compression
	 * by approx 2-4 percent, and increases comp time by approx 20%. */
    cinfo.optimize_coding = FALSE;

    xres = pixGetXRes(pix);
    yres = pixGetYRes(pix);
    if ((xres != 0) && (yres != 0)) {
        cinfo.density_unit = 1;  /* designates pixels per inch */
        cinfo.X_density = xres;
        cinfo.Y_density = yres;
    }

        /* Set the quality and progressive parameters */
    jpeg_set_quality(&cinfo, quality, TRUE);
    if (progressive) {
        jpeg_simple_progression(&cinfo);
    }

        /* Set the chroma subsampling parameters.  This is done in
         * YUV color space.  The Y (intensity) channel is never subsampled.
         * The standard subsampling is 2x2 on both the U and V channels.
         * Notation on this is confusing.  For a nice illustrations, see
         *   http://en.wikipedia.org/wiki/Chroma_subsampling
         * The standard subsampling is written as 4:2:0.
         * We allow high quality where there is no subsampling on the
         * chroma channels: denoted as 4:4:4.  */
    if (var_JPEG_NO_CHROMA_SAMPLING == 1) {
        cinfo.comp_info[0].h_samp_factor = 1;
        cinfo.comp_info[0].v_samp_factor = 1;
        cinfo.comp_info[1].h_samp_factor = 1;
        cinfo.comp_info[1].v_samp_factor = 1;
        cinfo.comp_info[2].h_samp_factor = 1;
        cinfo.comp_info[2].v_samp_factor = 1;
    }

    jpeg_start_compress(&cinfo, TRUE);

    if ((text = pixGetText(pix))) {
        jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text));
    }

        /* Allocate row buffer */
    spp = cinfo.input_components;
    rowsamples = spp * w;
    if ((rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), rowsamples)) == NULL)
        return ERROR_INT("calloc fail for rowbuffer", procName, 1);

    data = pixGetData(pix);
    wpl  = pixGetWpl(pix);
    for (i = 0; i < h; i++) {
        line = data + i * wpl;
        if (colorflg == 0) {        /* 8 bpp gray */
            for (j = 0; j < w; j++)
                rowbuffer[j] = GET_DATA_BYTE(line, j);
        }
        else if (colorflg == 1) {  /* 8 bpp colormapped */
            for (j = 0; j < w; j++) {
                byteval = GET_DATA_BYTE(line, j);
                rowbuffer[3 * j + COLOR_RED] = rmap[byteval];
                rowbuffer[3 * j + COLOR_GREEN] = gmap[byteval];
                rowbuffer[3 * j + COLOR_BLUE] = bmap[byteval];
            }
        }
        else {  /* colorflg == 2 */
            if (d == 24) {  /* See note 4 above; special case of 24 bpp rgb */
                jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1);
            }
            else {  /* standard 32 bpp rgb */
                ppixel = line;
                for (j = k = 0; j < w; j++) {
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                    ppixel++;
                }
            }
        }
        if (d != 24)
            jpeg_write_scanlines(&cinfo, &rowbuffer, 1);
    }

    jpeg_finish_compress(&cinfo);

    FREE(rowbuffer);
    if (colorflg == 1) {
        FREE(rmap);
        FREE(gmap);
        FREE(bmap);
    }

    jpeg_destroy_compress(&cinfo);
    return 0;
}
Ejemplo n.º 15
0
main(int    argc,
     char **argv)
{
l_int32      w, h, d, wpl, count, i, format, xres, yres;
FILE        *fp;
PIX         *pix, *pixt1, *pixt2;
PIXCMAP     *cmap;
char        *filein;
char        *fileout = NULL;
static char  mainName[] = "iotest";

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

    filein = argv[1];
    if (argc == 3)
        fileout = argv[2];

#if 1
    if ((pix = pixRead(filein)) == NULL)
	exit(ERROR_INT("pix not made", mainName, 1));
#else
    if ((pix = pixReadJpeg(filein, 0, 4, NULL)) == NULL)
	exit(ERROR_INT("pix not made", mainName, 1));
#endif

    pixGetDimensions(pix, &w, &h, &d);
    wpl = pixGetWpl(pix);
    fprintf(stderr, "w = %d, h = %d, d = %d, wpl = %d\n", w, h, d, wpl);
    xres = pixGetXRes(pix);
    yres = pixGetXRes(pix);
    if (xres != 0 && yres != 0)
        fprintf(stderr, "xres = %d, yres = %d\n", xres, yres);
    if (pixGetColormap(pix)) {
	    /* Write and read back the colormap */
        pixcmapWriteStream(stderr, pixGetColormap(pix));
        fp = lept_fopen("/tmp/junkcmap1", "wb");
        pixcmapWriteStream(fp, pixGetColormap(pix));
        lept_fclose(fp);
        fp = lept_fopen("/tmp/junkcmap1", "rb");
        cmap = pixcmapReadStream(fp);
        lept_fclose(fp);
        fp = lept_fopen("/tmp/junkcmap2", "wb");
        pixcmapWriteStream(fp, cmap);
        lept_fclose(fp);
        pixcmapDestroy(&cmap);

            /* Remove and regenerate colormap */
        pixt1 = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
	if (pixGetDepth(pixt1) == 8) {
            fprintf(stderr, "Colormap: represents grayscale image\n");
            pixt2 = pixConvertGrayToColormap(pixt1);
	}
	else {  /* 32 bpp */
            fprintf(stderr, "Colormap: represents RGB image\n");
            pixt2 = pixConvertRGBToColormap(pixt1, 1);
	}
        pixWrite("/tmp/junkpixt2.png", pixt2, IFF_PNG);
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }
    else {
        fprintf(stderr, "no colormap\n");
    }
    format = pixGetInputFormat(pix);
    fprintf(stderr, "Input format extension: %s\n",
            ImageFileFormatExtensions[format]);
    if (format == IFF_JFIF_JPEG)
        fprintf(stderr, "Jpeg comment: %s\n", pixGetText(pix));

    if (d == 1) {
        pixCountPixels(pix, &count, NULL);
        fprintf(stderr, "pixel ratio ON/OFF = %6.3f\n",
          (l_float32)count / (l_float32)(pixGetWidth(pix) * pixGetHeight(pix)));
    }

    if (argc == 3) {
#if 1
        d = pixGetDepth(pix);
        if (d == 16 || d < 8 || pixGetColormap(pix))
            pixWrite(fileout, pix, IFF_PNG);
        else
            pixWriteJpeg(fileout, pix, 75, 0);
#elif 0
        pixWrite(fileout, pix, IFF_BMP);
#elif 0
        pixWrite(fileout, pix, IFF_PNG);
#elif 0
        pixWrite(fileout, pix, IFF_TIFF);
        fprintTiffInfo(stderr, fileout);
#elif 0
        pixWrite(fileout, pix, IFF_TIFF_PACKBITS);
        fprintTiffInfo(stderr, fileout);
#elif 0
        pixWrite(fileout, pix, IFF_TIFF_G3);
        fprintTiffInfo(stderr, fileout);
#elif 0
        pixWrite(fileout, pix, IFF_TIFF_G4);
        fprintTiffInfo(stderr, fileout);
#elif 0
        pixWrite(fileout, pix, IFF_JFIF_JPEG);
#elif 0
        pixWriteJpeg(fileout, pix, 75, 0);
#elif 0
        pixWrite(fileout, pix, IFF_PNM);
#elif 0
        pixWrite(fileout, pix, IFF_PS);
#endif 
    }

    pixDestroy(&pix);

#if 0   /* test tiff header reader */
{ l_int32 w, h, bps, spp, res, cmap;
    if (readHeaderTiff(filein, 0, &w, &h, &bps, &spp, &res, &cmap) == 0)
        fprintf(stderr,
        "w = %d, h = %d, bps = %d, spp = %d, res = %d, cmap = %d\n",
        w, h, bps, spp, res, cmap);
}
#endif

    return 0;
}
Ejemplo n.º 16
0
l_int32 main(int    argc,
             char **argv)
{
char         *dir, *path;
char         *str1 = NULL;
char         *chara, *chara2;
char          buf[256];
l_uint8      *data1, *data2, *data3, *data4;
l_int32       w, h, i, n, bx, by, bw, bh, nchar, nbytes, ret;
l_int32      *rtable64;
l_uint32      pixval;
size_t        nbytes1, nbytes2, nout, nout2, nout3;
L_BMF        *bmf;
BOX          *box1, *box2;
BOXA         *boxa;
PIX          *pix, *pixs, *pixm, *pixg, *pixd;
PIX          *pix0, *pix1, *pix2, *pix3, *pix4, *pix5, *pix6;
PIXA         *pixas, *pixa1, *pixa2, *pixa3;
L_RECOG      *recog;
L_STRCODE    *strc;

    if (argc != 1) {
        fprintf(stderr, " Syntax: recog_bootnum\n");
        return 1;
    }

    lept_mkdir("lept/recog/digits");

    /* ----------------------- Bootnum 1 --------------------- */
        /* Make the bootnum pixa from the images */
    pixa1 = MakeBootnum1();
    pixaWrite("/tmp/lept/recog/digits/bootnum1.pa", pixa1);
    pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 0);
    pixDestroy(&pix1);
    pixaDestroy(&pixa1);

        /* Generate the code to make the bootnum1 pixa.
         * Note: the actual code we use is in bootnumgen1.c, and
         * has already been compiled into the library. */
    strc = strcodeCreate(101);  /* arbitrary integer */
    strcodeGenerate(strc, "/tmp/lept/recog/digits/bootnum1.pa", "PIXA");
    strcodeFinalize(&strc, "/tmp/lept/auto");
    lept_free(strc);

        /* Generate the bootnum1 pixa from the generated code */
    pixa1 = (PIXA *)l_bootnum_gen1();
    pix1 = pixaDisplayTiledWithText(pixa1, 1500, 1.0, 10, 2, 6, 0xff000000);
/*    pix1 = pixaDisplayTiled(pixa1, 1500, 0, 30); */
    pixDisplay(pix1, 100, 0);
    pixDestroy(&pix1);

        /* Extend the bootnum1 pixa by erosion */
    pixa3 = pixaExtendIterative(pixa1, L_MORPH_ERODE, 2, NULL, 1);
    pix1 = pixaDisplayTiledWithText(pixa3, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 0);
    pixDestroy(&pix1);
    pixaDestroy(&pixa1);
    pixaDestroy(&pixa3);

    /* ----------------------- Bootnum 2 --------------------- */
        /* Make the bootnum pixa from the images */
    L_INFO("the 4 errors below are due to bad input\n", "recog_bootnum");
    pixa2 = MakeBootnum2();
    pix1 = pixaDisplayTiledWithText(pixa2, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 700);
    pixDestroy(&pix1);
    pixaDestroy(&pixa2);

        /* Generate the code to make the bootnum2 pixa.
         * Note: the actual code we use is in bootnumgen2.c. */
    strc = strcodeCreate(102);  /* another arbitrary integer */
    strcodeGenerate(strc, "/tmp/lept/recog/digits/bootnum2.pa", "PIXA");
    strcodeFinalize(&strc, "/tmp/lept/auto");
    lept_free(strc);

        /* Generate the bootnum2 pixa from the generated code */
    pixa2 = (PIXA *)l_bootnum_gen2();
/*    pix1 = pixaDisplayTiled(pixa2, 1500, 0, 30);  */
    pix1 = pixaDisplayTiledWithText(pixa2, 1500, 1.0, 10, 2, 6, 0xff000000);
    pixDisplay(pix1, 100, 700);
    pixDestroy(&pix1);
    pixaDestroy(&pixa2);


#if 0
    pixas = (PIXA *)l_bootnum_gen1();
/*    pixas = pixaRead("recog/digits/bootnum1.pa"); */
    pixaWrite("/tmp/junk.pa", pixas);
    pixa1 = pixaRead("/tmp/junk.pa");
    pixaWrite("/tmp/junk1.pa", pixa1);
    pixa = pixaRead("/tmp/junk1.pa");
    n = pixaGetCount(pixa);
    for (i = 0; i < n; i++) {
        pix = pixaGetPix(pixa, i, L_CLONE);
        fprintf(stderr, "i = %d, text = %s\n", i, pixGetText(pix));
        pixDestroy(&pix);
    }
#endif

    return 0;
}