/*! * \brief pixWriteMemBmp() * * \param[out] pfdata data of bmp formatted image * \param[out] pfsize size of returned data * \param[in] pixs 1, 2, 4, 8, 16, 32 bpp * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) 2 bpp bmp files are not valid in the spec, and are * written as 8 bpp. * (2) pix with depth <= 8 bpp are written with a colormap. * 16 bpp gray and 32 bpp rgb pix are written without a colormap. * (3) The transparency component in an rgb pix is ignored. * All 32 bpp pix have the bmp alpha component set to 255 (opaque). * (4) The bmp colormap entries, RGBA_QUAD, are the same as * the ones used for colormaps in leptonica. This allows * a simple memcpy for bmp output. * </pre> */ l_int32 pixWriteMemBmp(l_uint8 **pfdata, size_t *pfsize, PIX *pixs) { l_uint8 pel[4]; l_uint8 *cta = NULL; /* address of the bmp color table array */ l_uint8 *fdata, *data, *fmdata; l_int32 cmaplen; /* number of bytes in the bmp colormap */ l_int32 ncolors, val, stepsize; l_int32 w, h, d, fdepth, xres, yres; l_int32 pixWpl, pixBpl, extrabytes, fBpl, fWpl, i, j, k; l_int32 heapcm; /* extra copy of cta on the heap ? 1 : 0 */ l_uint32 offbytes, fimagebytes; l_uint32 *line, *pword; size_t fsize; BMP_FH *bmpfh; BMP_IH *bmpih; PIX *pix; PIXCMAP *cmap; RGBA_QUAD *pquad; PROCNAME("pixWriteMemBmp"); if (pfdata) *pfdata = NULL; if (pfsize) *pfsize = 0; if (!pfdata) return ERROR_INT("&fdata not defined", procName, 1 ); if (!pfsize) return ERROR_INT("&fsize not defined", procName, 1 ); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); pixGetDimensions(pixs, &w, &h, &d); if (d == 2) { L_WARNING("2 bpp files can't be read; converting to 8 bpp\n", procName); pix = pixConvert2To8(pixs, 0, 85, 170, 255, 1); d = 8; } else { pix = pixCopy(NULL, pixs); } fdepth = (d == 32) ? 24 : d; /* Resolution is given in pixels/meter */ xres = (l_int32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5); yres = (l_int32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5); pixWpl = pixGetWpl(pix); pixBpl = 4 * pixWpl; fWpl = (w * fdepth + 31) / 32; fBpl = 4 * fWpl; fimagebytes = h * fBpl; if (fimagebytes > 4LL * L_MAX_ALLOWED_PIXELS) { pixDestroy(&pix); return ERROR_INT("image data is too large", procName, 1); } /* If not rgb or 16 bpp, the bmp data is required to have a colormap */ heapcm = 0; if (d == 32 || d == 16) { /* 24 bpp rgb or 16 bpp: no colormap */ ncolors = 0; cmaplen = 0; } else if ((cmap = pixGetColormap(pix))) { /* existing colormap */ ncolors = pixcmapGetCount(cmap); cmaplen = ncolors * sizeof(RGBA_QUAD); cta = (l_uint8 *)cmap->array; } else { /* no existing colormap; d <= 8; make a binary or gray one */ if (d == 1) { cmaplen = sizeof(bwmap); ncolors = 2; cta = (l_uint8 *)bwmap; } else { /* d = 2,4,8; use a grayscale output colormap */ ncolors = 1 << fdepth; cmaplen = ncolors * sizeof(RGBA_QUAD); heapcm = 1; cta = (l_uint8 *)LEPT_CALLOC(cmaplen, 1); stepsize = 255 / (ncolors - 1); for (i = 0, val = 0, pquad = (RGBA_QUAD *)cta; i < ncolors; i++, val += stepsize, pquad++) { pquad->blue = pquad->green = pquad->red = val; pquad->alpha = 255; /* opaque */ } } } #if DEBUG {l_uint8 *pcmptr; pcmptr = (l_uint8 *)pixGetColormap(pix)->array; fprintf(stderr, "Pix colormap[0] = %c%c%c%d\n", pcmptr[0], pcmptr[1], pcmptr[2], pcmptr[3]); fprintf(stderr, "Pix colormap[1] = %c%c%c%d\n", pcmptr[4], pcmptr[5], pcmptr[6], pcmptr[7]); } #endif /* DEBUG */ offbytes = BMP_FHBYTES + BMP_IHBYTES + cmaplen; fsize = offbytes + fimagebytes; fdata = (l_uint8 *)LEPT_CALLOC(fsize, 1); *pfdata = fdata; *pfsize = fsize; /* Convert to little-endian and write the file header data */ bmpfh = (BMP_FH *)fdata; bmpfh->bfType = convertOnBigEnd16(BMP_ID); bmpfh->bfSize = convertOnBigEnd16(fsize & 0x0000ffff); bmpfh->bfFill1 = convertOnBigEnd16((fsize >> 16) & 0x0000ffff); bmpfh->bfOffBits = convertOnBigEnd16(offbytes & 0x0000ffff); bmpfh->bfFill2 = convertOnBigEnd16((offbytes >> 16) & 0x0000ffff); /* Convert to little-endian and write the info header data */ bmpih = (BMP_IH *)(fdata + BMP_FHBYTES); bmpih->biSize = convertOnBigEnd32(BMP_IHBYTES); bmpih->biWidth = convertOnBigEnd32(w); bmpih->biHeight = convertOnBigEnd32(h); bmpih->biPlanes = convertOnBigEnd16(1); bmpih->biBitCount = convertOnBigEnd16(fdepth); bmpih->biSizeImage = convertOnBigEnd32(fimagebytes); bmpih->biXPelsPerMeter = convertOnBigEnd32(xres); bmpih->biYPelsPerMeter = convertOnBigEnd32(yres); bmpih->biClrUsed = convertOnBigEnd32(ncolors); bmpih->biClrImportant = convertOnBigEnd32(ncolors); /* Copy the colormap data and free the cta if necessary */ if (ncolors > 0) { memcpy(fdata + BMP_FHBYTES + BMP_IHBYTES, cta, cmaplen); if (heapcm) LEPT_FREE(cta); } /* When you write a binary image with a colormap * that sets BLACK to 0, you must invert the data */ if (fdepth == 1 && cmap && ((l_uint8 *)(cmap->array))[0] == 0x0) { pixInvert(pix, pix); } /* An endian byte swap is also required */ pixEndianByteSwap(pix); /* Transfer the image data. Image origin for bmp is at lower right. */ fmdata = fdata + offbytes; if (fdepth != 24) { /* typ 1 or 8 bpp */ data = (l_uint8 *)pixGetData(pix) + pixBpl * (h - 1); for (i = 0; i < h; i++) { memcpy(fmdata, data, fBpl); data -= pixBpl; fmdata += fBpl; } } else { /* 32 bpp pix; 24 bpp file * See the comments in pixReadStreamBmp() to * understand the logic behind the pixel ordering below. * Note that we have again done an endian swap on * little endian machines before arriving here, so that * the bytes are ordered on both platforms as: Red Green Blue -- |-----------|------------|-----------|-----------| */ extrabytes = fBpl - 3 * w; line = pixGetData(pix) + pixWpl * (h - 1); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pword = line + j; pel[2] = *((l_uint8 *)pword + COLOR_RED); pel[1] = *((l_uint8 *)pword + COLOR_GREEN); pel[0] = *((l_uint8 *)pword + COLOR_BLUE); memcpy(fmdata, &pel, 3); fmdata += 3; } if (extrabytes) { for (k = 0; k < extrabytes; k++) { memcpy(fmdata, &pel, 1); fmdata++; } } line -= pixWpl; } } pixDestroy(&pix); return 0; }
main(int argc, char **argv) { char *filein, *fileout; l_int32 d, same; PIX *pixs, *pixd, *pixt0, *pixt1, *pixt2, *pixt3, *pixt4, *pixt5; static char mainName[] = "converttogray"; if (argc != 2 && argc != 3) exit(ERROR_INT(" Syntax: converttogray filein [fileout]", mainName, 1)); filein = argv[1]; fileout = argv[2]; if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); #if 0 pixd = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33); pixWrite(fileout, pixd, IFF_PNG); pixDestroy(&pixd); #endif #if 1 d = pixGetDepth(pixs); if (d == 2) { pixt1 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE); pixt2 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE); pixEqual(pixt1, pixt2, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/junkpixt1", pixt1, IFF_PNG); pixWrite("/tmp/junkpixt2", pixt2, IFF_PNG); pixDestroy(&pixt1); pixDestroy(&pixt2); pixSetColormap(pixs, NULL); pixt3 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE); pixt4 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE); pixEqual(pixt3, pixt4, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/junkpixt3", pixt3, IFF_PNG); pixWrite("/tmp/junkpixt4", pixt4, IFF_PNG); pixDestroy(&pixt3); pixDestroy(&pixt4); } else if (d == 4) { pixt1 = pixConvert4To8(pixs, TRUE); pixt2 = pixConvert4To8(pixs, FALSE); pixEqual(pixt1, pixt2, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/junkpixt1", pixt1, IFF_PNG); pixWrite("/tmp/junkpixt2", pixt2, IFF_PNG); pixDestroy(&pixt1); pixDestroy(&pixt2); pixSetColormap(pixs, NULL); pixt3 = pixConvert4To8(pixs, TRUE); pixt4 = pixConvert4To8(pixs, FALSE); pixEqual(pixt3, pixt4, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/junkpixt3", pixt3, IFF_PNG); pixWrite("/tmp/junkpixt4", pixt4, IFF_PNG); pixDestroy(&pixt3); pixDestroy(&pixt4); } #endif pixDestroy(&pixs); return 0; }
int main(int argc, char **argv) { char *filein; char *fileout = NULL; l_int32 d, same; PIX *pixs, *pixd, *pix1, *pix2, *pix3, *pix4; static char mainName[] = "converttogray"; if (argc != 2 && argc != 3) return ERROR_INT(" Syntax: converttogray filein [fileout]", mainName, 1); filein = argv[1]; if (argc == 3) fileout = argv[2]; if ((pixs = pixRead(filein)) == NULL) return ERROR_INT("pixs not made", mainName, 1); if (fileout) { pixd = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33); pixWrite(fileout, pixd, IFF_PNG); pixDestroy(&pixs); pixDestroy(&pixd); return 0; } d = pixGetDepth(pixs); if (d == 2) { pix1 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE); pix2 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE); pixEqual(pix1, pix2, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/pix1.png", pix1, IFF_PNG); pixWrite("/tmp/pix2.png", pix2, IFF_PNG); pixDestroy(&pix1); pixDestroy(&pix2); pixSetColormap(pixs, NULL); pix3 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, TRUE); pix4 = pixConvert2To8(pixs, 0x00, 0x55, 0xaa, 0xff, FALSE); pixEqual(pix3, pix4, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/pix3.png", pix3, IFF_PNG); pixWrite("/tmp/pix4.png", pix4, IFF_PNG); pixDestroy(&pix3); pixDestroy(&pix4); } else if (d == 4) { pix1 = pixConvert4To8(pixs, TRUE); pix2 = pixConvert4To8(pixs, FALSE); pixEqual(pix1, pix2, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/pix1.png", pix1, IFF_PNG); pixWrite("/tmp/pix2.png", pix2, IFF_PNG); pixDestroy(&pix1); pixDestroy(&pix2); pixSetColormap(pixs, NULL); pix3 = pixConvert4To8(pixs, TRUE); pix4 = pixConvert4To8(pixs, FALSE); pixEqual(pix3, pix4, &same); if (same) fprintf(stderr, "images are the same\n"); else fprintf(stderr, "images are different!\n"); pixWrite("/tmp/pix3.png", pix3, IFF_PNG); pixWrite("/tmp/pix4.png", pix4, IFF_PNG); pixDestroy(&pix3); pixDestroy(&pix4); } else { L_INFO("only converts 2 and 4 bpp; d = %d\n", mainName, d); } pixDestroy(&pixs); return 0; }
/*! * pixGetWindowsHBITMAP() * * Input: pix * Return: Windows hBitmap, or null on error * * Notes: * (1) It's the responsibility of the caller to destroy the * returned hBitmap with a call to DeleteObject (or with * something that eventually calls DeleteObject). */ HBITMAP pixGetWindowsHBITMAP(PIX *pix) { l_int32 width, height, depth; l_uint32 *data; HBITMAP hBitmap = NULL; BITMAP bm; DWORD imageBitsSize; PIX *pixt = NULL; PIXCMAP *cmap; PROCNAME("pixGetWindowsHBITMAP"); if (!pix) return (HBITMAP)ERROR_PTR("pix not defined", procName, NULL); pixGetDimensions(pix, &width, &height, &depth); cmap = pixGetColormap(pix); if (depth == 24) depth = 32; if (depth == 2) { pixt = pixConvert2To8(pix, 0, 85, 170, 255, TRUE); if (!pixt) return (HBITMAP)ERROR_PTR("unable to convert pix from 2bpp to 8bpp", procName, NULL); depth = pixGetDepth(pixt); cmap = pixGetColormap(pixt); } if (depth < 16) { if (!cmap) cmap = pixcmapCreateLinear(depth, 1<<depth); } hBitmap = DSCreateDIBSection(width, height, depth, cmap); if (!hBitmap) return (HBITMAP)ERROR_PTR("Unable to create HBITMAP", procName, NULL); /* By default, Windows assumes bottom up images */ if (pixt) pixt = pixFlipTB(pixt, pixt); else pixt = pixFlipTB(NULL, pix); /* "standard" color table assumes bit off=black */ if (depth == 1) { pixInvert(pixt, pixt); } /* Don't byte swap until done manipulating pix! */ if (depth <= 16) pixEndianByteSwap(pixt); GetObject (hBitmap, sizeof(BITMAP), &bm); imageBitsSize = ImageBitsSize(hBitmap); data = pixGetData(pixt); if (data) { memcpy (bm.bmBits, data, imageBitsSize); } else { DeleteObject (hBitmap); hBitmap = NULL; } pixDestroy(&pixt); return hBitmap; }