/*! * 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; }
/*! * \brief recogAddCharstrLabels() * * \param[in] recog * \return 0 if OK, 1 on error */ static l_int32 recogAddCharstrLabels(L_RECOG *recog) { char *text; l_int32 i, j, n1, n2; PIX *pix; PIXA *pixa; PIXAA *paa; PROCNAME("recogAddCharstrLabels"); if (!recog) return ERROR_INT("recog not defined", procName, 1); /* Add the labels to each unscaled pix */ paa = recog->pixaa_u; n1 = pixaaGetCount(paa, NULL); for (i = 0; i < n1; i++) { pixa = pixaaGetPixa(paa, i, L_CLONE); text = sarrayGetString(recog->sa_text, i, L_NOCOPY); n2 = pixaGetCount(pixa); for (j = 0; j < n2; j++) { pix = pixaGetPix(pixa, j, L_CLONE); pixSetText(pix, text); pixDestroy(&pix); } pixaDestroy(&pixa); } return 0; }
/*! * \brief pixReadMemJpeg() * * \param[in] data const; jpeg-encoded * \param[in] size of data * \param[in] cmflag colormap flag 0 means return RGB image if color; * 1 means create a colormap and return * an 8 bpp colormapped image if color * \param[in] reduction scaling factor: 1, 2, 4 or 8 * \param[out] pnwarn [optional] number of warnings * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default * \return pix, or NULL on error * * <pre> * Notes: * (1) The %size byte of %data must be a null character. * (2) The only hint flag so far is L_JPEG_READ_LUMINANCE, * given in the enum in imageio.h. * (3) See pixReadJpeg() for usage. * </pre> */ PIX * pixReadMemJpeg(const l_uint8 *data, size_t size, l_int32 cmflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint) { l_int32 ret; l_uint8 *comment; FILE *fp; PIX *pix; PROCNAME("pixReadMemJpeg"); if (pnwarn) *pnwarn = 0; if (!data) return (PIX *)ERROR_PTR("data not defined", procName, NULL); if ((fp = fopenReadFromMemory(data, size)) == NULL) return (PIX *)ERROR_PTR("stream not opened", procName, NULL); pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint); if (pix) { ret = fgetJpegComment(fp, &comment); if (!ret && comment) { pixSetText(pix, (char *)comment); LEPT_FREE(comment); } } fclose(fp); if (!pix) L_ERROR("pix not read\n", procName); return pix; }
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; }
// Returns a pix representing the sample. (Int features only.) Pix* TrainingSample::RenderToPix(const UNICHARSET* unicharset) const { Pix* pix = pixCreate(kIntFeatureExtent, kIntFeatureExtent, 1); for (uint32_t f = 0; f < num_features_; ++f) { int start_x = features_[f].X; int start_y = kIntFeatureExtent - features_[f].Y; double dx = cos((features_[f].Theta / 256.0) * 2.0 * M_PI - M_PI); double dy = -sin((features_[f].Theta / 256.0) * 2.0 * M_PI - M_PI); for (int i = 0; i <= 5; ++i) { int x = static_cast<int>(start_x + dx * i); int y = static_cast<int>(start_y + dy * i); if (x >= 0 && x < 256 && y >= 0 && y < 256) pixSetPixel(pix, x, y, 1); } } if (unicharset != nullptr) pixSetText(pix, unicharset->id_to_unichar(class_id_)); return pix; }
/*! * pixReadMemJpeg() * * Input: data (const; jpeg-encoded) * size (of data) * colormap flag (0 means return RGB image if color; * 1 means create a colormap and return * an 8 bpp colormapped image if color) * reduction (scaling factor: 1, 2, 4 or 8) * &nwarn (<optional return> number of warnings) * hint (a bitwise OR of L_JPEG_* values; 0 for default) * Return: pix, or null on error * * Notes: * (1) The @size byte of @data must be a null character. * (2) The only hint flag so far is L_JPEG_READ_LUMINANCE, * given in the enum in imageio.h. * (3) See pixReadJpeg() for usage. */ PIX * pixReadMemJpeg(const l_uint8 *data, size_t size, l_int32 cmflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint) { l_int32 ret; l_uint8 *comment; FILE *fp; PIX *pix; PROCNAME("pixReadMemJpeg"); if (pnwarn) *pnwarn = 0; if (!data) return (PIX *)ERROR_PTR("data not defined", procName, NULL); #if HAVE_FMEMOPEN if ((fp = fmemopen((l_uint8 *)data, size, "r")) == NULL) return (PIX *)ERROR_PTR("stream not opened", procName, NULL); #else L_WARNING("work-around: writing to a temp file\n", procName); if ((fp = tmpfile()) == NULL) return (PIX *)ERROR_PTR("tmpfile stream not opened", procName, NULL); fwrite(data, 1, size, fp); rewind(fp); #endif /* HAVE_FMEMOPEN */ pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint); if (pix) { ret = fgetJpegComment(fp, &comment); if (!ret && comment) { pixSetText(pix, (char *)comment); FREE(comment); } } fclose(fp); if (!pix) L_ERROR("pix not read\n", procName); return pix; }
/*! * \brief pixReadJpeg() * * \param[in] filename * \param[in] cmapflag 0 for no colormap in returned pix; * 1 to return an 8 bpp cmapped pix if spp = 3 or 4 * \param[in] reduction scaling factor: 1, 2, 4 or 8 * \param[out] pnwarn [optional] number of warnings about * corrupted data * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default * \return pix, or NULL on error * * <pre> * Notes: * (1) This is a special function for reading jpeg files. * (2) Use this if you want the jpeg library to create * an 8 bpp colormapped image. * (3) Images reduced by factors of 2, 4 or 8 can be returned * significantly faster than full resolution images. * (4) If the jpeg data is bad, the jpeg library will continue * silently, or return warnings, or attempt to exit. Depending * on the severity of the data corruption, there are two possible * outcomes: * (a) a possibly damaged pix can be generated, along with zero * or more warnings, or * (b) the library will attempt to exit (caught by our error * handler) and no pix will be returned. * If a pix is generated with at least one warning of data * corruption, and if L_JPEG_FAIL_ON_BAD_DATA is included in %hint, * no pix will be returned. * (5) The possible hint values are given in the enum in imageio.h: * * L_JPEG_READ_LUMINANCE * * L_JPEG_FAIL_ON_BAD_DATA * Default (0) is to do neither. * </pre> */ PIX * pixReadJpeg(const char *filename, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint) { l_int32 ret; l_uint8 *comment; FILE *fp; PIX *pix; PROCNAME("pixReadJpeg"); if (pnwarn) *pnwarn = 0; if (!filename) return (PIX *)ERROR_PTR("filename not defined", procName, NULL); if (cmapflag != 0 && cmapflag != 1) cmapflag = 0; /* default */ if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8) return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", procName, NULL); if ((fp = fopenReadStream(filename)) == NULL) return (PIX *)ERROR_PTR("image file not found", procName, NULL); pix = pixReadStreamJpeg(fp, cmapflag, reduction, pnwarn, hint); if (pix) { ret = fgetJpegComment(fp, &comment); if (!ret && comment) pixSetText(pix, (char *)comment); LEPT_FREE(comment); } fclose(fp); if (!pix) return (PIX *)ERROR_PTR("image not returned", procName, NULL); return pix; }
/*! * pixReadStreamPng() * * Input: stream * Return: pix, or null on error * * Notes: * (1) If called from pixReadStream(), the stream is positioned * at the beginning of the file. * (2) To do sequential reads of png format images from a stream, * use pixReadStreamPng() */ PIX * pixReadStreamPng(FILE *fp) { l_uint8 rval, gval, bval; l_int32 i, j, k; l_int32 wpl, d, spp, cindex; l_uint32 png_transforms; l_uint32 *data, *line, *ppixel; int num_palette, num_text; png_byte bit_depth, color_type, channels; png_uint_32 w, h, rowbytes; png_uint_32 xres, yres; png_bytep rowptr; png_bytep *row_pointers; png_structp png_ptr; png_infop info_ptr, end_info; png_colorp palette; png_textp text_ptr; /* ptr to text_chunk */ PIX *pix; PIXCMAP *cmap; PROCNAME("pixReadStreamPng"); if (!fp) return (PIX *)ERROR_PTR("fp not defined", procName, NULL); pix = NULL; /* Allocate the 3 data structures */ if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL)) == NULL) return (PIX *)ERROR_PTR("png_ptr not made", procName, NULL); if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (PIX *)ERROR_PTR("info_ptr not made", procName, NULL); } if ((end_info = png_create_info_struct(png_ptr)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return (PIX *)ERROR_PTR("end_info not made", procName, NULL); } /* Set up png setjmp error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("internal png error", procName, NULL); } png_init_io(png_ptr, fp); /* ---------------------------------------------------------- * * Set the transforms flags. Whatever happens here, * NEVER invert 1 bpp using PNG_TRANSFORM_INVERT_MONO. * ---------------------------------------------------------- */ /* To strip 16 --> 8 bit depth, use PNG_TRANSFORM_STRIP_16 */ if (var_PNG_STRIP_16_TO_8 == 1) /* our default */ png_transforms = PNG_TRANSFORM_STRIP_16; else png_transforms = PNG_TRANSFORM_IDENTITY; /* To remove alpha channel, use PNG_TRANSFORM_STRIP_ALPHA */ if (var_PNG_STRIP_ALPHA == 1) /* our default */ png_transforms |= PNG_TRANSFORM_STRIP_ALPHA; /* Read it */ png_read_png(png_ptr, info_ptr, png_transforms, NULL); row_pointers = png_get_rows(png_ptr, info_ptr); w = png_get_image_width(png_ptr, info_ptr); h = png_get_image_height(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); spp = channels; if (spp == 1) d = bit_depth; else if (spp == 2) { d = 2 * bit_depth; L_WARNING("there shouldn't be 2 spp!", procName); } else /* spp == 3 (rgb), spp == 4 (rgba) */ d = 4 * bit_depth; /* Remove if/when this is implemented for all bit_depths */ if (spp == 3 && bit_depth != 8) { fprintf(stderr, "Help: spp = 3 and depth = %d != 8\n!!", bit_depth); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("not implemented for this depth", procName, NULL); } if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_MASK_PALETTE) { /* generate a colormap */ png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); cmap = pixcmapCreate(d); /* spp == 1 */ for (cindex = 0; cindex < num_palette; cindex++) { rval = palette[cindex].red; gval = palette[cindex].green; bval = palette[cindex].blue; pixcmapAddColor(cmap, rval, gval, bval); } } else cmap = NULL; if ((pix = pixCreate(w, h, d)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("pix not made", procName, NULL); } wpl = pixGetWpl(pix); data = pixGetData(pix); pixSetColormap(pix, cmap); if (spp == 1) { /* copy straight from buffer to pix */ for (i = 0; i < h; i++) { line = data + i * wpl; rowptr = row_pointers[i]; for (j = 0; j < rowbytes; j++) { SET_DATA_BYTE(line, j, rowptr[j]); } } } else { /* spp == 3 or spp == 4 */ for (i = 0; i < h; i++) { ppixel = data + i * wpl; rowptr = row_pointers[i]; for (j = k = 0; j < w; j++) { SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k++]); SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k++]); SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]); if (spp == 4) SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]); ppixel++; } } } #if DEBUG if (cmap) { for (i = 0; i < 16; i++) { fprintf(stderr, "[%d] = %d\n", i, ((l_uint8 *)(cmap->array))[i]); } } #endif /* DEBUG */ /* If there is no colormap, PNG defines black = 0 and * white = 1 by default for binary monochrome. Therefore, * since we use the opposite definition, we must invert * the image colors in either of these cases: * (i) there is no colormap (default) * (ii) there is a colormap which defines black to * be 0 and white to be 1. * We cannot use the PNG_TRANSFORM_INVERT_MONO flag * because that flag (since version 1.0.9) inverts 8 bpp * grayscale as well, which we don't want to do. * (It also doesn't work if there is a colormap.) * If there is a colormap that defines black = 1 and * white = 0, we don't need to do anything. * * How do we check the polarity of the colormap? * The colormap determines the values of black and * white pixels in the following way: * if black = 1 (255), white = 0 * 255, 255, 255, 0, 0, 0, 0, 0, 0 * if black = 0, white = 1 (255) * 0, 0, 0, 0, 255, 255, 255, 0 * So we test the first byte to see if it is 0; * if so, invert the colors. * * If there is a colormap, after inverting the pixels it is * necessary to destroy the colormap. Otherwise, if someone were * to call pixRemoveColormap(), this would cause the pixel * values to be inverted again! */ if (d == 1 && (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) { /* fprintf(stderr, "Inverting binary data on png read\n"); */ pixInvert(pix, pix); pixDestroyColormap(pix); } xres = png_get_x_pixels_per_meter(png_ptr, info_ptr); yres = png_get_y_pixels_per_meter(png_ptr, info_ptr); pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */ pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */ /* Get the text if there is any */ png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); if (num_text && text_ptr) pixSetText(pix, text_ptr->text); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return pix; }
/* ----------------------------------------------------- */ 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); }
int main(int argc, char **argv) { char buf[8]; l_int32 i, n, h; l_float32 scalefact; BOXA *boxa; PIX *pixs, *pix, *pixt1, *pixt2; PIXA *pixa, *pixas, *pixad; PIXAA *pixaa; static char mainName[] = "digitprep1"; if (argc != 1) { ERROR_INT(" Syntax: digitprep1", mainName, 1); return 1; } if ((pixs = pixRead("barcode-digits.png")) == NULL) return ERROR_INT("pixs not read", mainName, 1); /* Extract the digits and scale to HEIGHT */ boxa = pixConnComp(pixs, &pixa, 8); pixas = pixaSort(pixa, L_SORT_BY_X, L_SORT_INCREASING, NULL, L_CLONE); n = pixaGetCount(pixas); /* Move the last ("0") to the first position */ pixt1 = pixaGetPix(pixas, n - 1, L_CLONE); pixaInsertPix(pixas, 0, pixt1, NULL); pixaRemovePix(pixas, n); /* Make the output scaled pixa */ pixad = pixaCreate(n); for (i = 0; i < n; i++) { pixt1 = pixaGetPix(pixas, i, L_CLONE); pixGetDimensions(pixt1, NULL, &h, NULL); scalefact = HEIGHT / (l_float32)h; pixt2 = pixScale(pixt1, scalefact, scalefact); if (pixGetHeight(pixt2) != 32) return ERROR_INT("height not 32!", mainName, 1); sprintf(buf, "%d", i); pixSetText(pixt2, buf); pixaAddPix(pixad, pixt2, L_INSERT); pixDestroy(&pixt1); } /* Save in a pixaa, with 1 pix in each pixa */ pixaa = pixaaCreateFromPixa(pixad, 1, L_CHOOSE_CONSECUTIVE, L_CLONE); pixaaWrite("junkdigits.pixaa", pixaa); /* Show result */ pixt1 = pixaaDisplayByPixa(pixaa, 20, 20, 1000); pixDisplay(pixt1, 100, 100); pixDestroy(&pixt1); boxaDestroy(&boxa); pixaDestroy(&pixa); pixaDestroy(&pixas); pixaDestroy(&pixad); pixaaDestroy(&pixaa); return 0; }
/*! * pixReadStream() * * Input: fp (file stream) * hint (bitwise OR of L_HINT_* values for jpeg; use 0 for no hint) * Return: pix if OK; null on error * * Notes: * (1) The hint only applies to jpeg. */ PIX * pixReadStream(FILE *fp, l_int32 hint) { l_int32 format, ret; l_uint8 *comment; PIX *pix; PROCNAME("pixReadStream"); if (!fp) return (PIX *)ERROR_PTR("stream not defined", procName, NULL); pix = NULL; findFileFormatStream(fp, &format); switch (format) { case IFF_BMP: if ((pix = pixReadStreamBmp(fp)) == NULL ) return (PIX *)ERROR_PTR( "bmp: no pix returned", procName, NULL); break; case IFF_JFIF_JPEG: if ((pix = pixReadStreamJpeg(fp, 0, 1, NULL, hint)) == NULL) return (PIX *)ERROR_PTR( "jpeg: no pix returned", procName, NULL); ret = fgetJpegComment(fp, &comment); if (!ret && comment) pixSetText(pix, (char *)comment); FREE(comment); break; case IFF_PNG: if ((pix = pixReadStreamPng(fp)) == NULL) return (PIX *)ERROR_PTR("png: no pix returned", procName, NULL); break; case IFF_TIFF: case IFF_TIFF_PACKBITS: case IFF_TIFF_RLE: case IFF_TIFF_G3: case IFF_TIFF_G4: case IFF_TIFF_LZW: case IFF_TIFF_ZIP: if ((pix = pixReadStreamTiff(fp, 0)) == NULL) /* page 0 by default */ return (PIX *)ERROR_PTR("tiff: no pix returned", procName, NULL); break; case IFF_PNM: if ((pix = pixReadStreamPnm(fp)) == NULL) return (PIX *)ERROR_PTR("pnm: no pix returned", procName, NULL); break; case IFF_GIF: if ((pix = pixReadStreamGif(fp)) == NULL) return (PIX *)ERROR_PTR("gif: no pix returned", procName, NULL); break; case IFF_JP2: if ((pix = pixReadStreamJp2k(fp, 1, NULL, 0, 0)) == NULL) return (PIX *)ERROR_PTR("jp2: no pix returned", procName, NULL); break; case IFF_WEBP: if ((pix = pixReadStreamWebP(fp)) == NULL) return (PIX *)ERROR_PTR("webp: no pix returned", procName, NULL); break; case IFF_SPIX: if ((pix = pixReadStreamSpix(fp)) == NULL) return (PIX *)ERROR_PTR("spix: no pix returned", procName, NULL); break; case IFF_UNKNOWN: return (PIX *)ERROR_PTR( "Unknown format: no pix returned", procName, NULL); break; } if (pix) pixSetInputFormat(pix, format); return pix; }
/*! * pixReadStreamJpeg() * * Input: stream * colormap flag (0 means return RGB image if color; * 1 means create colormap and return 8 bpp * palette image if color) * reduction (scaling factor: 1, 2, 4 or 8) * &pnwarn (<optional return> number of warnings) * hint: (a bitwise OR of L_HINT_* values); use 0 for no hints * Return: pix, or null on error * * Usage: see pixReadJpeg() */ PIX * pixReadStreamJpeg(FILE *fp, l_int32 cmflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint) { l_uint8 cyan, yellow, magenta, black, white; l_int32 rval, gval, bval; l_int32 i, j, k; l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk; l_uint32 *data; l_uint32 *line, *ppixel; JSAMPROW rowbuffer; PIX *pix; PIXCMAP *cmap; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; l_uint8 *comment = NULL; PROCNAME("pixReadStreamJpeg"); if (!fp) return (PIX *)ERROR_PTR("fp not defined", procName, NULL); if (pnwarn) *pnwarn = 0; /* init */ if (cmflag != 0 && cmflag != 1) cmflag = 0; /* default */ if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8) return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", procName, NULL); if (BITS_IN_JSAMPLE != 8) /* set in jmorecfg.h */ return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", procName, NULL); rewind(fp); pix = NULL; /* init */ if (setjmp(jpeg_jmpbuf)) { pixDestroy(&pix); FREE(rowbuffer); return (PIX *)ERROR_PTR("internal jpeg error", procName, NULL); } rowbuffer = NULL; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = jpeg_error_do_not_exit; /* catch error; do not exit! */ jpeg_create_decompress(&cinfo); cinfo.client_data = &comment; jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback); jpeg_stdio_src(&cinfo, fp); jpeg_read_header(&cinfo, TRUE); cinfo.scale_denom = reduction; cinfo.scale_num = 1; if (hint & L_HINT_GRAY) cinfo.out_color_space = JCS_GRAYSCALE; jpeg_calc_output_dimensions(&cinfo); /* Allocate the image and a row buffer */ spp = cinfo.out_color_components; w = cinfo.output_width; h = cinfo.output_height; ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmflag == 0); cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmflag == 0); if (spp != 1 && spp != 3 && !ycck && !cmyk) { if (comment) FREE(comment); return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK", procName, NULL); } if ((spp == 3 && cmflag == 0) || ycck || cmyk) { /* rgb or 4 bpp color */ rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), spp * w); pix = pixCreate(w, h, 32); } else { /* 8 bpp gray or colormapped */ rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), w); pix = pixCreate(w, h, 8); } if (!rowbuffer || !pix) { if (comment) FREE(comment); if (rowbuffer) FREE(rowbuffer); pixDestroy(&pix); return (PIX *)ERROR_PTR("rowbuffer or pix not made", procName, NULL); } if (comment) { pixSetText(pix, (char *)comment); FREE(comment); } if (spp == 1) /* Grayscale or colormapped */ jpeg_start_decompress(&cinfo); else { /* Color; spp == 3 or YCCK or CMYK */ if (cmflag == 0) { /* -- 24 bit color in 32 bit pix or YCCK/CMYK -- */ cinfo.quantize_colors = FALSE; jpeg_start_decompress(&cinfo); } else { /* Color quantize to 8 bits */ cinfo.quantize_colors = TRUE; cinfo.desired_number_of_colors = 256; jpeg_start_decompress(&cinfo); /* Construct a pix cmap */ cmap = pixcmapCreate(8); ncolors = cinfo.actual_number_of_colors; for (cindex = 0; cindex < ncolors; cindex++) { rval = cinfo.colormap[0][cindex]; gval = cinfo.colormap[1][cindex]; bval = cinfo.colormap[2][cindex]; pixcmapAddColor(cmap, rval, gval, bval); } pixSetColormap(pix, cmap); } } wpl = pixGetWpl(pix); data = pixGetData(pix); /* Decompress */ if ((spp == 3 && cmflag == 0) || ycck || cmyk) { /* -- 24 bit color -- */ for (i = 0; i < h; i++) { if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1) return (PIX *)ERROR_PTR("bad read scanline", procName, NULL); ppixel = data + i * wpl; if (spp == 3) { for (j = k = 0; j < w; j++) { SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]); SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]); SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]); ppixel++; } } else { /* This is a conversion from CMYK -> RGB that ignores color profiles, and is invoked when the image header claims to be in CMYK or YCCK colorspace. If in YCCK, libjpeg may be doing YCCK -> CMYK under the hood. To understand why the colors are inverted on read-in, see the "Special color spaces" section of "Using the IJG JPEG Library" by Thomas G. Lane. */ for (j = k = 0; j < w; j++) { cyan = 255 - rowbuffer[k++]; magenta = 255 - rowbuffer[k++]; yellow = 255 - rowbuffer[k++]; white = rowbuffer[k++]; black = 255 - white; rval = 255 - (cyan * white) / 255 - black; gval = 255 - (magenta * white) / 255 - black; bval = 255 - (yellow * white) / 255 - black; rval = L_MIN(L_MAX(rval, 0), 255); gval = L_MIN(L_MAX(gval, 0), 255); bval = L_MIN(L_MAX(bval, 0), 255); composeRGBPixel(rval, gval, bval, ppixel); ppixel++; } } } } else { /* 8 bpp grayscale or colormapped pix */ for (i = 0; i < h; i++) { if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1) return (PIX *)ERROR_PTR("bad read scanline", procName, NULL); line = data + i * wpl; for (j = 0; j < w; j++) SET_DATA_BYTE(line, j, rowbuffer[j]); } } if (pnwarn) *pnwarn = cinfo.err->num_warnings; switch (cinfo.density_unit) { case 1: /* pixels per inch */ pixSetXRes(pix, cinfo.X_density); pixSetYRes(pix, cinfo.Y_density); break; case 2: /* pixels per centimeter */ pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5)); pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5)); break; default: /* the pixel density may not be defined; ignore */ break; } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); FREE(rowbuffer); return pix; }