/*! * findFileFormatStream() * * Input: fp (file stream) * &format (<return>) * Return: 0 if OK, 1 on error or if format is not recognized * * Notes: * (1) Important: Side effect -- this resets fp to BOF. */ l_int32 findFileFormatStream(FILE *fp, l_int32 *pformat) { l_uint8 firstbytes[12]; l_int32 format; PROCNAME("findFileFormatStream"); if (!pformat) return ERROR_INT("&format not defined", procName, 1); *pformat = IFF_UNKNOWN; if (!fp) return ERROR_INT("stream not defined", procName, 1); rewind(fp); if (fnbytesInFile(fp) < 12) return ERROR_INT("truncated file", procName, 1); if (fread((char *)&firstbytes, 1, 12, fp) != 12) return ERROR_INT("failed to read first 12 bytes of file", procName, 1); rewind(fp); findFileFormatBuffer(firstbytes, &format); if (format == IFF_TIFF) { findTiffCompression(fp, &format); rewind(fp); } *pformat = format; if (format == IFF_UNKNOWN) return 1; else return 0; }
/*! * sreadHeaderJp2k() * * Input: data * size * &w (<optional return>) * &h (<optional return>) * &spp (<optional return>, samples/pixel) * Return: 0 if OK, 1 on error * * Notes: * (1) The metadata is stored as follows: * h: 4 bytes @ 48 * w: 4 bytes @ 52 * spp: 2 bytes @ 56 */ l_int32 sreadHeaderJp2k(const l_uint8 *data, size_t size, l_int32 *pw, l_int32 *ph, l_int32 *pspp) { l_int32 format, val, w, h, spp; PROCNAME("sreadHeaderJp2k"); if (pw) *pw = 0; if (ph) *ph = 0; if (pspp) *pspp = 0; if (!data) return ERROR_INT("data not defined", procName, 1); if (size < 60) return ERROR_INT("size < 60", procName, 1); findFileFormatBuffer(data, &format); if (format != IFF_JP2) return ERROR_INT("not jp2 file", procName, 1); val = *((l_uint32 *)data + 12); h = convertOnLittleEnd32(val); val = *((l_uint32 *)data + 13); w = convertOnLittleEnd32(val); val = *((l_uint16 *)data + 28); spp = convertOnLittleEnd16(val); if (w > MAX_JP2K_WIDTH || h > MAX_JP2K_HEIGHT) return ERROR_INT("unrealistically large sizes", procName, 1); if (pw) *pw = w; if (ph) *ph = h; if (pspp) *pspp = spp; return 0; }
/*! * readHeaderMemJp2k() * * Input: data * size (at least 80) * &w (<optional return>) * &h (<optional return>) * &bps (<optional return>, bits/sample) * &spp (<optional return>, samples/pixel) * Return: 0 if OK, 1 on error * * Notes: * (1) The ISO/IEC reference for jpeg2000 is * http://www.jpeg.org/public/15444-1annexi.pdf * and the file format syntax begins at page 127. * (2) The Image Header Box begins with 'ihdr' = 0x69686472 in * big-endian order. This typically, but not always, starts * byte 44, with the big-endian data fields beginning at byte 48: * h: 4 bytes * w: 4 bytes * spp: 2 bytes * bps: 1 byte (contains bps - 1) */ l_int32 readHeaderMemJp2k(const l_uint8 *data, size_t size, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp) { l_int32 format, val, w, h, bps, spp, loc, found, windex; l_uint8 ihdr[4] = {0x69, 0x68, 0x64, 0x72}; /* 'ihdr' */ PROCNAME("readHeaderMemJp2k"); if (pw) *pw = 0; if (ph) *ph = 0; if (pbps) *pbps = 0; if (pspp) *pspp = 0; if (!data) return ERROR_INT("data not defined", procName, 1); if (size < 80) return ERROR_INT("size < 80", procName, 1); findFileFormatBuffer(data, &format); if (format != IFF_JP2) return ERROR_INT("not jp2 file", procName, 1); /* Search for beginning of the Image Header Box: 'ihdr' */ arrayFindSequence(data, size, ihdr, 4, &loc, &found); if (!found) return ERROR_INT("image parameters not found", procName, 1); if (loc != 44) L_INFO("Beginning of ihdr is at byte %d\n", procName, loc); windex = loc / 4 + 1; val = *((l_uint32 *)data + windex); h = convertOnLittleEnd32(val); val = *((l_uint32 *)data + windex + 1); w = convertOnLittleEnd32(val); val = *((l_uint16 *)data + 2 * (windex + 2)); spp = convertOnLittleEnd16(val); bps = *(data + 4 * (windex + 2) + 2) + 1; if (w > MAX_JP2K_WIDTH || h > MAX_JP2K_HEIGHT) return ERROR_INT("unrealistically large sizes", procName, 1); if (pw) *pw = w; if (ph) *ph = h; if (pbps) *pbps = bps; if (pspp) *pspp = spp; return 0; }
/*! * pixReadHeaderMem() * * Input: data (const; encoded) * datasize (size of data) * &format (<optional returns> image format) * &w, &h (<optional returns> width and height) * &bps <optional return> bits/sample * &spp <optional return> samples/pixel (1, 3 or 4) * &iscmap (<optional return> 1 if cmap exists; 0 otherwise) * Return: 0 if OK, 1 on error * * Notes: * (1) This reads the actual headers for jpeg, png, tiff, jp2k and pnm. * For bmp and gif, we cheat and read all the data into a pix, * from which we extract the "header" information. * (2) The amount of data required depends on the format. For * png, it requires less than 30 bytes, but for jpeg it can * require most of the compressed file. In practice, the data * is typically the entire compressed file in memory. * (3) findFileFormatBuffer() requires up to 8 bytes to decide on * the format, which we require. */ l_int32 pixReadHeaderMem(const l_uint8 *data, size_t size, l_int32 *pformat, l_int32 *pw, l_int32 *ph, l_int32 *pbps, l_int32 *pspp, l_int32 *piscmap) { l_int32 format, ret, w, h, d, bps, spp, iscmap; l_int32 type; /* not used */ PIX *pix; PROCNAME("pixReadHeaderMem"); if (pw) *pw = 0; if (ph) *ph = 0; if (pbps) *pbps = 0; if (pspp) *pspp = 0; if (piscmap) *piscmap = 0; if (pformat) *pformat = 0; iscmap = 0; /* init to false */ if (!data) return ERROR_INT("data not defined", procName, 1); if (size < 8) return ERROR_INT("size < 8", procName, 1); findFileFormatBuffer(data, &format); switch (format) { case IFF_BMP: /* cheating: read the pix */ if ((pix = pixReadMemBmp(data, size)) == NULL) return ERROR_INT( "bmp: pix not read", procName, 1); pixGetDimensions(pix, &w, &h, &d); pixDestroy(&pix); bps = (d == 32) ? 8 : d; spp = (d == 32) ? 3 : 1; break; case IFF_JFIF_JPEG: ret = readHeaderMemJpeg(data, size, &w, &h, &spp, NULL, NULL); bps = 8; if (ret) return ERROR_INT( "jpeg: no header info returned", procName, 1); break; case IFF_PNG: ret = readHeaderMemPng(data, size, &w, &h, &bps, &spp, &iscmap); if (ret) return ERROR_INT( "png: no header info returned", procName, 1); 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: /* Reading page 0 by default; possibly redefine format */ ret = readHeaderMemTiff(data, size, 0, &w, &h, &bps, &spp, NULL, &iscmap, &format); if (ret) return ERROR_INT( "tiff: no header info returned", procName, 1); break; case IFF_PNM: ret = readHeaderMemPnm(data, size, &w, &h, &d, &type, &bps, &spp); if (ret) return ERROR_INT( "pnm: no header info returned", procName, 1); break; case IFF_GIF: /* cheating: read the pix */ if ((pix = pixReadMemGif(data, size)) == NULL) return ERROR_INT( "gif: pix not read", procName, 1); pixGetDimensions(pix, &w, &h, &d); pixDestroy(&pix); iscmap = 1; /* always colormapped; max 256 colors */ spp = 1; bps = d; break; case IFF_JP2: ret = readHeaderMemJp2k(data, size, &w, &h, &bps, &spp); break; case IFF_WEBP: bps = 8; ret = readHeaderMemWebP(data, size, &w, &h, &spp); break; case IFF_SPIX: ret = sreadHeaderSpix((l_uint32 *)data, &w, &h, &bps, &spp, &iscmap); if (ret) return ERROR_INT( "pnm: no header info returned", procName, 1); break; case IFF_UNKNOWN: return ERROR_INT("unknown format; no data returned", procName, 1); break; } if (pw) *pw = w; if (ph) *ph = h; if (pbps) *pbps = bps; if (pspp) *pspp = spp; if (piscmap) *piscmap = iscmap; if (pformat) *pformat = format; return 0; }
/*! * pixReadMem() * * Input: data (const; encoded) * datasize (size of data) * Return: pix, or null on error * * Notes: * (1) This is a variation of pixReadStream(), where the data is read * from a memory buffer rather than a file. * (2) On windows, this only reads tiff formatted files directly from * memory. For other formats, it write to a temp file and * decompress from file. * (3) findFileFormatBuffer() requires up to 8 bytes to decide on * the format. That determines the constraint here. But in * fact the data must contain the entire compressed string for * the image. */ PIX * pixReadMem(const l_uint8 *data, size_t size) { l_int32 format; PIX *pix; PROCNAME("pixReadMem"); if (!data) return (PIX *)ERROR_PTR("data not defined", procName, NULL); if (size < 8) return (PIX *)ERROR_PTR("size < 8", procName, NULL); pix = NULL; findFileFormatBuffer(data, &format); switch (format) { case IFF_BMP: if ((pix = pixReadMemBmp(data, size)) == NULL ) return (PIX *)ERROR_PTR( "bmp: no pix returned", procName, NULL); break; case IFF_JFIF_JPEG: if ((pix = pixReadMemJpeg(data, size, READ_24_BIT_COLOR, 1, NULL, 0)) == NULL) return (PIX *)ERROR_PTR( "jpeg: no pix returned", procName, NULL); break; case IFF_PNG: if ((pix = pixReadMemPng(data, size)) == 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: /* Reading page 0 by default */ if ((pix = pixReadMemTiff(data, size, 0)) == NULL) return (PIX *)ERROR_PTR("tiff: no pix returned", procName, NULL); break; case IFF_PNM: if ((pix = pixReadMemPnm(data, size)) == NULL) return (PIX *)ERROR_PTR("pnm: no pix returned", procName, NULL); break; case IFF_GIF: if ((pix = pixReadMemGif(data, size)) == NULL) return (PIX *)ERROR_PTR("gif: no pix returned", procName, NULL); break; case IFF_JP2: if ((pix = pixReadMemJp2k(data, size, 1, NULL, 0)) == NULL) return (PIX *)ERROR_PTR("jp2k: no pix returned", procName, NULL); break; case IFF_WEBP: if ((pix = pixReadMemWebP(data, size)) == NULL) return (PIX *)ERROR_PTR("webp: no pix returned", procName, NULL); break; case IFF_SPIX: if ((pix = pixReadMemSpix(data, size)) == 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; } /* Set the input format. For tiff reading from memory we lose * the actual input format; for 1 bpp, default to G4. */ if (pix) { if (format == IFF_TIFF && pixGetDepth(pix) == 1) format = IFF_TIFF_G4; pixSetInputFormat(pix, format); } return pix; }