/*! * 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; }
/*! * 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; }
/*! * 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; }
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; }
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); }
/*! * 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; }
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; }
/*! * \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; }
/*! * 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; }
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; }
/*! * \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; }
/* ----------------------------------------------------- */ 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); }
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; }
/*! * 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; }
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; }
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; }