/* * The copyright in this software is being made available under the 2-clauses * BSD License, included below. This software may be subject to other third * party and contributor rights, including patent rights, and no such rights * are granted under this license. * * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium * Copyright (c) 2002-2014, Professor Benoit Macq * Copyright (c) 2001-2003, David Janssens * Copyright (c) 2002-2003, Yannick Verschueren * Copyright (c) 2003-2007, Francois-Olivier Devaux * Copyright (c) 2003-2014, Antonin Descampe * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2006-2007, Parvatha Elangovan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "opj_apps_config.h" #include #include #include #include #include "openjpeg.h" #include "convert.h" typedef struct { OPJ_UINT16 bfType; /* 'BM' for Bitmap (19776) */ OPJ_UINT32 bfSize; /* Size of the file */ OPJ_UINT16 bfReserved1; /* Reserved : 0 */ OPJ_UINT16 bfReserved2; /* Reserved : 0 */ OPJ_UINT32 bfOffBits; /* Offset */ } OPJ_BITMAPFILEHEADER; typedef struct { OPJ_UINT32 biSize; /* Size of the structure in bytes */ OPJ_UINT32 biWidth; /* Width of the image in pixels */ OPJ_UINT32 biHeight; /* Height of the image in pixels */ OPJ_UINT16 biPlanes; /* 1 */ OPJ_UINT16 biBitCount; /* Number of color bits by pixels */ OPJ_UINT32 biCompression; /* Type of encoding 0: none 1: RLE8 2: RLE4 */ OPJ_UINT32 biSizeImage; /* Size of the image in bytes */ OPJ_UINT32 biXpelsPerMeter; /* Horizontal (X) resolution in pixels/meter */ OPJ_UINT32 biYpelsPerMeter; /* Vertical (Y) resolution in pixels/meter */ OPJ_UINT32 biClrUsed; /* Number of color used in the image (0: ALL) */ OPJ_UINT32 biClrImportant; /* Number of important color (0: ALL) */ OPJ_UINT32 biRedMask; /* Red channel bit mask */ OPJ_UINT32 biGreenMask; /* Green channel bit mask */ OPJ_UINT32 biBlueMask; /* Blue channel bit mask */ OPJ_UINT32 biAlphaMask; /* Alpha channel bit mask */ OPJ_UINT32 biColorSpaceType; /* Color space type */ OPJ_UINT8 biColorSpaceEP[36]; /* Color space end points */ OPJ_UINT32 biRedGamma; /* Red channel gamma */ OPJ_UINT32 biGreenGamma; /* Green channel gamma */ OPJ_UINT32 biBlueGamma; /* Blue channel gamma */ OPJ_UINT32 biIntent; /* Intent */ OPJ_UINT32 biIccProfileData; /* ICC profile data */ OPJ_UINT32 biIccProfileSize; /* ICC profile size */ OPJ_UINT32 biReserved; /* Reserved */ } OPJ_BITMAPINFOHEADER; static void opj_applyLUT8u_8u32s_C1R( OPJ_UINT8 const* pSrc, OPJ_INT32 srcStride, OPJ_INT32* pDst, OPJ_INT32 dstStride, OPJ_UINT8 const* pLUT, OPJ_UINT32 width, OPJ_UINT32 height) { OPJ_UINT32 y; for (y = height; y != 0U; --y) { OPJ_UINT32 x; for (x = 0; x < width; x++) { pDst[x] = (OPJ_INT32)pLUT[pSrc[x]]; } pSrc += srcStride; pDst += dstStride; } } static void opj_applyLUT8u_8u32s_C1P3R( OPJ_UINT8 const* pSrc, OPJ_INT32 srcStride, OPJ_INT32* const* pDst, OPJ_INT32 const* pDstStride, OPJ_UINT8 const* const* pLUT, OPJ_UINT32 width, OPJ_UINT32 height) { OPJ_UINT32 y; OPJ_INT32* pR = pDst[0]; OPJ_INT32* pG = pDst[1]; OPJ_INT32* pB = pDst[2]; OPJ_UINT8 const* pLUT_R = pLUT[0]; OPJ_UINT8 const* pLUT_G = pLUT[1]; OPJ_UINT8 const* pLUT_B = pLUT[2]; for (y = height; y != 0U; --y) { OPJ_UINT32 x; for (x = 0; x < width; x++) { OPJ_UINT8 idx = pSrc[x]; pR[x] = (OPJ_INT32)pLUT_R[idx]; pG[x] = (OPJ_INT32)pLUT_G[idx]; pB[x] = (OPJ_INT32)pLUT_B[idx]; } pSrc += srcStride; pR += pDstStride[0]; pG += pDstStride[1]; pB += pDstStride[2]; } } static void bmp24toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image) { int index; OPJ_UINT32 width, height; OPJ_UINT32 x, y; const OPJ_UINT8 *pSrc = NULL; width = image->comps[0].w; height = image->comps[0].h; index = 0; pSrc = pData + (height - 1U) * stride; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { image->comps[0].data[index] = (OPJ_INT32)pSrc[3 * x + 2]; /* R */ image->comps[1].data[index] = (OPJ_INT32)pSrc[3 * x + 1]; /* G */ image->comps[2].data[index] = (OPJ_INT32)pSrc[3 * x + 0]; /* B */ index++; } pSrc -= stride; } } static void bmp_mask_get_shift_and_prec(OPJ_UINT32 mask, OPJ_UINT32* shift, OPJ_UINT32* prec) { OPJ_UINT32 l_shift, l_prec; l_shift = l_prec = 0U; if (mask != 0U) { while ((mask & 1U) == 0U) { mask >>= 1; l_shift++; } while (mask & 1U) { mask >>= 1; l_prec++; } } *shift = l_shift; *prec = l_prec; } static void bmpmask32toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image, OPJ_UINT32 redMask, OPJ_UINT32 greenMask, OPJ_UINT32 blueMask, OPJ_UINT32 alphaMask) { int index; OPJ_UINT32 width, height; OPJ_UINT32 x, y; const OPJ_UINT8 *pSrc = NULL; OPJ_BOOL hasAlpha; OPJ_UINT32 redShift, redPrec; OPJ_UINT32 greenShift, greenPrec; OPJ_UINT32 blueShift, bluePrec; OPJ_UINT32 alphaShift, alphaPrec; width = image->comps[0].w; height = image->comps[0].h; hasAlpha = image->numcomps > 3U; bmp_mask_get_shift_and_prec(redMask, &redShift, &redPrec); bmp_mask_get_shift_and_prec(greenMask, &greenShift, &greenPrec); bmp_mask_get_shift_and_prec(blueMask, &blueShift, &bluePrec); bmp_mask_get_shift_and_prec(alphaMask, &alphaShift, &alphaPrec); image->comps[0].bpp = redPrec; image->comps[0].prec = redPrec; image->comps[1].bpp = greenPrec; image->comps[1].prec = greenPrec; image->comps[2].bpp = bluePrec; image->comps[2].prec = bluePrec; if (hasAlpha) { image->comps[3].bpp = alphaPrec; image->comps[3].prec = alphaPrec; } index = 0; pSrc = pData + (height - 1U) * stride; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { OPJ_UINT32 value = 0U; value |= ((OPJ_UINT32)pSrc[4 * x + 0]) << 0; value |= ((OPJ_UINT32)pSrc[4 * x + 1]) << 8; value |= ((OPJ_UINT32)pSrc[4 * x + 2]) << 16; value |= ((OPJ_UINT32)pSrc[4 * x + 3]) << 24; image->comps[0].data[index] = (OPJ_INT32)((value & redMask) >> redShift); /* R */ image->comps[1].data[index] = (OPJ_INT32)((value & greenMask) >> greenShift); /* G */ image->comps[2].data[index] = (OPJ_INT32)((value & blueMask) >> blueShift); /* B */ if (hasAlpha) { image->comps[3].data[index] = (OPJ_INT32)((value & alphaMask) >> alphaShift); /* A */ } index++; } pSrc -= stride; } } static void bmpmask16toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image, OPJ_UINT32 redMask, OPJ_UINT32 greenMask, OPJ_UINT32 blueMask, OPJ_UINT32 alphaMask) { int index; OPJ_UINT32 width, height; OPJ_UINT32 x, y; const OPJ_UINT8 *pSrc = NULL; OPJ_BOOL hasAlpha; OPJ_UINT32 redShift, redPrec; OPJ_UINT32 greenShift, greenPrec; OPJ_UINT32 blueShift, bluePrec; OPJ_UINT32 alphaShift, alphaPrec; width = image->comps[0].w; height = image->comps[0].h; hasAlpha = image->numcomps > 3U; bmp_mask_get_shift_and_prec(redMask, &redShift, &redPrec); bmp_mask_get_shift_and_prec(greenMask, &greenShift, &greenPrec); bmp_mask_get_shift_and_prec(blueMask, &blueShift, &bluePrec); bmp_mask_get_shift_and_prec(alphaMask, &alphaShift, &alphaPrec); image->comps[0].bpp = redPrec; image->comps[0].prec = redPrec; image->comps[1].bpp = greenPrec; image->comps[1].prec = greenPrec; image->comps[2].bpp = bluePrec; image->comps[2].prec = bluePrec; if (hasAlpha) { image->comps[3].bpp = alphaPrec; image->comps[3].prec = alphaPrec; } index = 0; pSrc = pData + (height - 1U) * stride; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { OPJ_UINT32 value = 0U; value |= ((OPJ_UINT32)pSrc[2 * x + 0]) << 0; value |= ((OPJ_UINT32)pSrc[2 * x + 1]) << 8; image->comps[0].data[index] = (OPJ_INT32)((value & redMask) >> redShift); /* R */ image->comps[1].data[index] = (OPJ_INT32)((value & greenMask) >> greenShift); /* G */ image->comps[2].data[index] = (OPJ_INT32)((value & blueMask) >> blueShift); /* B */ if (hasAlpha) { image->comps[3].data[index] = (OPJ_INT32)((value & alphaMask) >> alphaShift); /* A */ } index++; } pSrc -= stride; } } static opj_image_t* bmp8toimage(const OPJ_UINT8* pData, OPJ_UINT32 stride, opj_image_t* image, OPJ_UINT8 const* const* pLUT) { OPJ_UINT32 width, height; const OPJ_UINT8 *pSrc = NULL; width = image->comps[0].w; height = image->comps[0].h; pSrc = pData + (height - 1U) * stride; if (image->numcomps == 1U) { opj_applyLUT8u_8u32s_C1R(pSrc, -(OPJ_INT32)stride, image->comps[0].data, (OPJ_INT32)width, pLUT[0], width, height); } else { OPJ_INT32* pDst[3]; OPJ_INT32 pDstStride[3]; pDst[0] = image->comps[0].data; pDst[1] = image->comps[1].data; pDst[2] = image->comps[2].data; pDstStride[0] = (OPJ_INT32)width; pDstStride[1] = (OPJ_INT32)width; pDstStride[2] = (OPJ_INT32)width; opj_applyLUT8u_8u32s_C1P3R(pSrc, -(OPJ_INT32)stride, pDst, pDstStride, pLUT, width, height); } return image; } static OPJ_BOOL bmp_read_file_header(FILE* IN, OPJ_BITMAPFILEHEADER* header) { header->bfType = (OPJ_UINT16)getc(IN); header->bfType |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); if (header->bfType != 19778) { fprintf(stderr, "Error, not a BMP file!\n"); return OPJ_FALSE; } /* FILE HEADER */ /* ------------- */ header->bfSize = (OPJ_UINT32)getc(IN); header->bfSize |= (OPJ_UINT32)getc(IN) << 8; header->bfSize |= (OPJ_UINT32)getc(IN) << 16; header->bfSize |= (OPJ_UINT32)getc(IN) << 24; header->bfReserved1 = (OPJ_UINT16)getc(IN); header->bfReserved1 |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); header->bfReserved2 = (OPJ_UINT16)getc(IN); header->bfReserved2 |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); header->bfOffBits = (OPJ_UINT32)getc(IN); header->bfOffBits |= (OPJ_UINT32)getc(IN) << 8; header->bfOffBits |= (OPJ_UINT32)getc(IN) << 16; header->bfOffBits |= (OPJ_UINT32)getc(IN) << 24; return OPJ_TRUE; } static OPJ_BOOL bmp_read_info_header(FILE* IN, OPJ_BITMAPINFOHEADER* header) { memset(header, 0, sizeof(*header)); /* INFO HEADER */ /* ------------- */ header->biSize = (OPJ_UINT32)getc(IN); header->biSize |= (OPJ_UINT32)getc(IN) << 8; header->biSize |= (OPJ_UINT32)getc(IN) << 16; header->biSize |= (OPJ_UINT32)getc(IN) << 24; switch (header->biSize) { case 12U: /* BITMAPCOREHEADER */ case 40U: /* BITMAPINFOHEADER */ case 52U: /* BITMAPV2INFOHEADER */ case 56U: /* BITMAPV3INFOHEADER */ case 108U: /* BITMAPV4HEADER */ case 124U: /* BITMAPV5HEADER */ break; default: fprintf(stderr, "Error, unknown BMP header size %d\n", header->biSize); return OPJ_FALSE; } header->biWidth = (OPJ_UINT32)getc(IN); header->biWidth |= (OPJ_UINT32)getc(IN) << 8; header->biWidth |= (OPJ_UINT32)getc(IN) << 16; header->biWidth |= (OPJ_UINT32)getc(IN) << 24; header->biHeight = (OPJ_UINT32)getc(IN); header->biHeight |= (OPJ_UINT32)getc(IN) << 8; header->biHeight |= (OPJ_UINT32)getc(IN) << 16; header->biHeight |= (OPJ_UINT32)getc(IN) << 24; header->biPlanes = (OPJ_UINT16)getc(IN); header->biPlanes |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); header->biBitCount = (OPJ_UINT16)getc(IN); header->biBitCount |= (OPJ_UINT16)((OPJ_UINT32)getc(IN) << 8); if (header->biSize >= 40U) { header->biCompression = (OPJ_UINT32)getc(IN); header->biCompression |= (OPJ_UINT32)getc(IN) << 8; header->biCompression |= (OPJ_UINT32)getc(IN) << 16; header->biCompression |= (OPJ_UINT32)getc(IN) << 24; header->biSizeImage = (OPJ_UINT32)getc(IN); header->biSizeImage |= (OPJ_UINT32)getc(IN) << 8; header->biSizeImage |= (OPJ_UINT32)getc(IN) << 16; header->biSizeImage |= (OPJ_UINT32)getc(IN) << 24; header->biXpelsPerMeter = (OPJ_UINT32)getc(IN); header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 8; header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 16; header->biXpelsPerMeter |= (OPJ_UINT32)getc(IN) << 24; header->biYpelsPerMeter = (OPJ_UINT32)getc(IN); header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 8; header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 16; header->biYpelsPerMeter |= (OPJ_UINT32)getc(IN) << 24; header->biClrUsed = (OPJ_UINT32)getc(IN); header->biClrUsed |= (OPJ_UINT32)getc(IN) << 8; header->biClrUsed |= (OPJ_UINT32)getc(IN) << 16; header->biClrUsed |= (OPJ_UINT32)getc(IN) << 24; header->biClrImportant = (OPJ_UINT32)getc(IN); header->biClrImportant |= (OPJ_UINT32)getc(IN) << 8; header->biClrImportant |= (OPJ_UINT32)getc(IN) << 16; header->biClrImportant |= (OPJ_UINT32)getc(IN) << 24; } if (header->biSize >= 56U) { header->biRedMask = (OPJ_UINT32)getc(IN); header->biRedMask |= (OPJ_UINT32)getc(IN) << 8; header->biRedMask |= (OPJ_UINT32)getc(IN) << 16; header->biRedMask |= (OPJ_UINT32)getc(IN) << 24; header->biGreenMask = (OPJ_UINT32)getc(IN); header->biGreenMask |= (OPJ_UINT32)getc(IN) << 8; header->biGreenMask |= (OPJ_UINT32)getc(IN) << 16; header->biGreenMask |= (OPJ_UINT32)getc(IN) << 24; header->biBlueMask = (OPJ_UINT32)getc(IN); header->biBlueMask |= (OPJ_UINT32)getc(IN) << 8; header->biBlueMask |= (OPJ_UINT32)getc(IN) << 16; header->biBlueMask |= (OPJ_UINT32)getc(IN) << 24; header->biAlphaMask = (OPJ_UINT32)getc(IN); header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 8; header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 16; header->biAlphaMask |= (OPJ_UINT32)getc(IN) << 24; } if (header->biSize >= 108U) { header->biColorSpaceType = (OPJ_UINT32)getc(IN); header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 8; header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 16; header->biColorSpaceType |= (OPJ_UINT32)getc(IN) << 24; if (fread(&(header->biColorSpaceEP), 1U, sizeof(header->biColorSpaceEP), IN) != sizeof(header->biColorSpaceEP)) { fprintf(stderr, "Error, can't read BMP header\n"); return OPJ_FALSE; } header->biRedGamma = (OPJ_UINT32)getc(IN); header->biRedGamma |= (OPJ_UINT32)getc(IN) << 8; header->biRedGamma |= (OPJ_UINT32)getc(IN) << 16; header->biRedGamma |= (OPJ_UINT32)getc(IN) << 24; header->biGreenGamma = (OPJ_UINT32)getc(IN); header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 8; header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 16; header->biGreenGamma |= (OPJ_UINT32)getc(IN) << 24; header->biBlueGamma = (OPJ_UINT32)getc(IN); header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 8; header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 16; header->biBlueGamma |= (OPJ_UINT32)getc(IN) << 24; } if (header->biSize >= 124U) { header->biIntent = (OPJ_UINT32)getc(IN); header->biIntent |= (OPJ_UINT32)getc(IN) << 8; header->biIntent |= (OPJ_UINT32)getc(IN) << 16; header->biIntent |= (OPJ_UINT32)getc(IN) << 24; header->biIccProfileData = (OPJ_UINT32)getc(IN); header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 8; header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 16; header->biIccProfileData |= (OPJ_UINT32)getc(IN) << 24; header->biIccProfileSize = (OPJ_UINT32)getc(IN); header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 8; header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 16; header->biIccProfileSize |= (OPJ_UINT32)getc(IN) << 24; header->biReserved = (OPJ_UINT32)getc(IN); header->biReserved |= (OPJ_UINT32)getc(IN) << 8; header->biReserved |= (OPJ_UINT32)getc(IN) << 16; header->biReserved |= (OPJ_UINT32)getc(IN) << 24; } return OPJ_TRUE; } static OPJ_BOOL bmp_read_raw_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) { OPJ_ARG_NOT_USED(width); if (fread(pData, sizeof(OPJ_UINT8), stride * height, IN) != (stride * height)) { fprintf(stderr, "\nError: fread return a number of element different from the expected.\n"); return OPJ_FALSE; } return OPJ_TRUE; } static OPJ_BOOL bmp_read_rle8_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) { OPJ_UINT32 x, y; OPJ_UINT8 *pix; const OPJ_UINT8 *beyond; beyond = pData + stride * height; pix = pData; x = y = 0U; while (y < height) { int c = getc(IN); if (c) { int j; OPJ_UINT8 c1 = (OPJ_UINT8)getc(IN); for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { *pix = c1; } } else { c = getc(IN); if (c == 0x00) { /* EOL */ x = 0; ++y; pix = pData + y * stride + x; } else if (c == 0x01) { /* EOP */ break; } else if (c == 0x02) { /* MOVE by dxdy */ c = getc(IN); x += (OPJ_UINT32)c; c = getc(IN); y += (OPJ_UINT32)c; pix = pData + y * stride + x; } else { /* 03 .. 255 */ int j; for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { OPJ_UINT8 c1 = (OPJ_UINT8)getc(IN); *pix = c1; } if ((OPJ_UINT32)c & 1U) { /* skip padding byte */ getc(IN); } } } }/* while() */ return OPJ_TRUE; } static OPJ_BOOL bmp_read_rle4_data(FILE* IN, OPJ_UINT8* pData, OPJ_UINT32 stride, OPJ_UINT32 width, OPJ_UINT32 height) { OPJ_UINT32 x, y; OPJ_UINT8 *pix; const OPJ_UINT8 *beyond; beyond = pData + stride * height; pix = pData; x = y = 0U; while (y < height) { int c = getc(IN); if (c == EOF) { break; } if (c) { /* encoded mode */ int j; OPJ_UINT8 c1 = (OPJ_UINT8)getc(IN); for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { *pix = (OPJ_UINT8)((j & 1) ? (c1 & 0x0fU) : ((c1 >> 4) & 0x0fU)); } } else { /* absolute mode */ c = getc(IN); if (c == EOF) { break; } if (c == 0x00) { /* EOL */ x = 0; y++; pix = pData + y * stride; } else if (c == 0x01) { /* EOP */ break; } else if (c == 0x02) { /* MOVE by dxdy */ c = getc(IN); x += (OPJ_UINT32)c; c = getc(IN); y += (OPJ_UINT32)c; pix = pData + y * stride + x; } else { /* 03 .. 255 : absolute mode */ int j; OPJ_UINT8 c1 = 0U; for (j = 0; (j < c) && (x < width) && ((OPJ_SIZE_T)pix < (OPJ_SIZE_T)beyond); j++, x++, pix++) { if ((j & 1) == 0) { c1 = (OPJ_UINT8)getc(IN); } *pix = (OPJ_UINT8)((j & 1) ? (c1 & 0x0fU) : ((c1 >> 4) & 0x0fU)); } if (((c & 3) == 1) || ((c & 3) == 2)) { /* skip padding byte */ getc(IN); } } } } /* while(y < height) */ return OPJ_TRUE; } opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters) { opj_image_cmptparm_t cmptparm[4]; /* maximum of 4 components */ OPJ_UINT8 lut_R[256], lut_G[256], lut_B[256]; OPJ_UINT8 const* pLUT[3]; opj_image_t * image = NULL; FILE *IN; OPJ_BITMAPFILEHEADER File_h; OPJ_BITMAPINFOHEADER Info_h; OPJ_UINT32 i, palette_len, numcmpts = 1U; OPJ_BOOL l_result = OPJ_FALSE; OPJ_UINT8* pData = NULL; OPJ_UINT32 stride; pLUT[0] = lut_R; pLUT[1] = lut_G; pLUT[2] = lut_B; IN = fopen(filename, "rb"); if (!IN) { fprintf(stderr, "Failed to open %s for reading !!\n", filename); return NULL; } if (!bmp_read_file_header(IN, &File_h)) { fclose(IN); return NULL; } if (!bmp_read_info_header(IN, &Info_h)) { fclose(IN); return NULL; } /* Load palette */ if (Info_h.biBitCount <= 8U) { memset(&lut_R[0], 0, sizeof(lut_R)); memset(&lut_G[0], 0, sizeof(lut_G)); memset(&lut_B[0], 0, sizeof(lut_B)); palette_len = Info_h.biClrUsed; if ((palette_len == 0U) && (Info_h.biBitCount <= 8U)) { palette_len = (1U << Info_h.biBitCount); } if (palette_len > 256U) { palette_len = 256U; } if (palette_len > 0U) { OPJ_UINT8 has_color = 0U; for (i = 0U; i < palette_len; i++) { lut_B[i] = (OPJ_UINT8)getc(IN); lut_G[i] = (OPJ_UINT8)getc(IN); lut_R[i] = (OPJ_UINT8)getc(IN); (void)getc(IN); /* padding */ has_color |= (lut_B[i] ^ lut_G[i]) | (lut_G[i] ^ lut_R[i]); } if (has_color) { numcmpts = 3U; } } } else { numcmpts = 3U; if ((Info_h.biCompression == 3) && (Info_h.biAlphaMask != 0U)) { numcmpts++; } } if (Info_h.biWidth == 0 || Info_h.biHeight == 0) { fclose(IN); return NULL; } if (Info_h.biBitCount > (((OPJ_UINT32) - 1) - 31) / Info_h.biWidth) { fclose(IN); return NULL; } stride = ((Info_h.biWidth * Info_h.biBitCount + 31U) / 32U) * 4U; /* rows are aligned on 32bits */ if (Info_h.biBitCount == 4 && Info_h.biCompression == 2) { /* RLE 4 gets decoded as 8 bits data for now... */ if (8 > (((OPJ_UINT32) - 1) - 31) / Info_h.biWidth) { fclose(IN); return NULL; } stride = ((Info_h.biWidth * 8U + 31U) / 32U) * 4U; } if (stride > ((OPJ_UINT32) - 1) / sizeof(OPJ_UINT8) / Info_h.biHeight) { fclose(IN); return NULL; } pData = (OPJ_UINT8 *) calloc(1, stride * Info_h.biHeight * sizeof(OPJ_UINT8)); if (pData == NULL) { fclose(IN); return NULL; } /* Place the cursor at the beginning of the image information */ fseek(IN, 0, SEEK_SET); fseek(IN, (long)File_h.bfOffBits, SEEK_SET); switch (Info_h.biCompression) { case 0: case 3: /* read raw data */ l_result = bmp_read_raw_data(IN, pData, stride, Info_h.biWidth, Info_h.biHeight); break; case 1: /* read rle8 data */ l_result = bmp_read_rle8_data(IN, pData, stride, Info_h.biWidth, Info_h.biHeight); break; case 2: /* read rle4 data */ l_result = bmp_read_rle4_data(IN, pData, stride, Info_h.biWidth, Info_h.biHeight); break; default: fprintf(stderr, "Unsupported BMP compression\n"); l_result = OPJ_FALSE; break; } if (!l_result) { free(pData); fclose(IN); return NULL; } /* create the image */ memset(&cmptparm[0], 0, sizeof(cmptparm)); for (i = 0; i < 4U; i++) { cmptparm[i].prec = 8; cmptparm[i].bpp = 8; cmptparm[i].sgnd = 0; cmptparm[i].dx = (OPJ_UINT32)parameters->subsampling_dx; cmptparm[i].dy = (OPJ_UINT32)parameters->subsampling_dy; cmptparm[i].w = Info_h.biWidth; cmptparm[i].h = Info_h.biHeight; } image = opj_image_create(numcmpts, &cmptparm[0], (numcmpts == 1U) ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB); if (!image) { fclose(IN); free(pData); return NULL; } if (numcmpts == 4U) { image->comps[3].alpha = 1; } /* set image offset and reference grid */ image->x0 = (OPJ_UINT32)parameters->image_offset_x0; image->y0 = (OPJ_UINT32)parameters->image_offset_y0; image->x1 = image->x0 + (Info_h.biWidth - 1U) * (OPJ_UINT32) parameters->subsampling_dx + 1U; image->y1 = image->y0 + (Info_h.biHeight - 1U) * (OPJ_UINT32) parameters->subsampling_dy + 1U; /* Read the data */ if (Info_h.biBitCount == 24 && Info_h.biCompression == 0) { /*RGB */ bmp24toimage(pData, stride, image); } else if (Info_h.biBitCount == 8 && Info_h.biCompression == 0) { /* RGB 8bpp Indexed */ bmp8toimage(pData, stride, image, pLUT); } else if (Info_h.biBitCount == 8 && Info_h.biCompression == 1) { /*RLE8*/ bmp8toimage(pData, stride, image, pLUT); } else if (Info_h.biBitCount == 4 && Info_h.biCompression == 2) { /*RLE4*/ bmp8toimage(pData, stride, image, pLUT); /* RLE 4 gets decoded as 8 bits data for now */ } else if (Info_h.biBitCount == 32 && Info_h.biCompression == 0) { /* RGBX */ bmpmask32toimage(pData, stride, image, 0x00FF0000U, 0x0000FF00U, 0x000000FFU, 0x00000000U); } else if (Info_h.biBitCount == 32 && Info_h.biCompression == 3) { /* bitmask */ bmpmask32toimage(pData, stride, image, Info_h.biRedMask, Info_h.biGreenMask, Info_h.biBlueMask, Info_h.biAlphaMask); } else if (Info_h.biBitCount == 16 && Info_h.biCompression == 0) { /* RGBX */ bmpmask16toimage(pData, stride, image, 0x7C00U, 0x03E0U, 0x001FU, 0x0000U); } else if (Info_h.biBitCount == 16 && Info_h.biCompression == 3) { /* bitmask */ if ((Info_h.biRedMask == 0U) && (Info_h.biGreenMask == 0U) && (Info_h.biBlueMask == 0U)) { Info_h.biRedMask = 0xF800U; Info_h.biGreenMask = 0x07E0U; Info_h.biBlueMask = 0x001FU; } bmpmask16toimage(pData, stride, image, Info_h.biRedMask, Info_h.biGreenMask, Info_h.biBlueMask, Info_h.biAlphaMask); } else { opj_image_destroy(image); image = NULL; fprintf(stderr, "Other system than 24 bits/pixels or 8 bits (no RLE coding) is not yet implemented [%d]\n", Info_h.biBitCount); } free(pData); fclose(IN); return image; } int imagetobmp(opj_image_t * image, const char *outfile) { int w, h; int i, pad; FILE *fdest = NULL; int adjustR, adjustG, adjustB; if (image->comps[0].prec < 8) { fprintf(stderr, "Unsupported number of components: %d\n", image->comps[0].prec); return 1; } if (image->numcomps >= 3 && image->comps[0].dx == image->comps[1].dx && image->comps[1].dx == image->comps[2].dx && image->comps[0].dy == image->comps[1].dy && image->comps[1].dy == image->comps[2].dy && image->comps[0].prec == image->comps[1].prec && image->comps[1].prec == image->comps[2].prec) { /* -->> -->> -->> -->> 24 bits color <<-- <<-- <<-- <<-- */ fdest = fopen(outfile, "wb"); if (!fdest) { fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); return 1; } w = (int)image->comps[0].w; h = (int)image->comps[0].h; fprintf(fdest, "BM"); /* FILE HEADER */ /* ------------- */ fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)(h * w * 3 + 3 * h * (w % 2) + 54) & 0xff, (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2) + 54) >> 8) & 0xff, (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2) + 54) >> 16) & 0xff, (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2) + 54) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (54) & 0xff, ((54) >> 8) & 0xff, ((54) >> 16) & 0xff, ((54) >> 24) & 0xff); /* INFO HEADER */ /* ------------- */ fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((w) & 0xff), (OPJ_UINT8)((w) >> 8) & 0xff, (OPJ_UINT8)((w) >> 16) & 0xff, (OPJ_UINT8)((w) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((h) & 0xff), (OPJ_UINT8)((h) >> 8) & 0xff, (OPJ_UINT8)((h) >> 16) & 0xff, (OPJ_UINT8)((h) >> 24) & 0xff); fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); fprintf(fdest, "%c%c", (24) & 0xff, ((24) >> 8) & 0xff); fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)(3 * h * w + 3 * h * (w % 2)) & 0xff, (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2)) >> 8) & 0xff, (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2)) >> 16) & 0xff, (OPJ_UINT8)((h * w * 3 + 3 * h * (w % 2)) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); if (image->comps[0].prec > 8) { adjustR = (int)image->comps[0].prec - 8; printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); } else { adjustR = 0; } if (image->comps[1].prec > 8) { adjustG = (int)image->comps[1].prec - 8; printf("BMP CONVERSION: Truncating component 1 from %d bits to 8 bits\n", image->comps[1].prec); } else { adjustG = 0; } if (image->comps[2].prec > 8) { adjustB = (int)image->comps[2].prec - 8; printf("BMP CONVERSION: Truncating component 2 from %d bits to 8 bits\n", image->comps[2].prec); } else { adjustB = 0; } for (i = 0; i < w * h; i++) { OPJ_UINT8 rc, gc, bc; int r, g, b; r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); if (r > 255) { r = 255; } else if (r < 0) { r = 0; } rc = (OPJ_UINT8)r; g = image->comps[1].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); g = ((g >> adjustG) + ((g >> (adjustG - 1)) % 2)); if (g > 255) { g = 255; } else if (g < 0) { g = 0; } gc = (OPJ_UINT8)g; b = image->comps[2].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); b = ((b >> adjustB) + ((b >> (adjustB - 1)) % 2)); if (b > 255) { b = 255; } else if (b < 0) { b = 0; } bc = (OPJ_UINT8)b; fprintf(fdest, "%c%c%c", bc, gc, rc); if ((i + 1) % w == 0) { for (pad = ((3 * w) % 4) ? (4 - (3 * w) % 4) : 0; pad > 0; pad--) { /* ADD */ fprintf(fdest, "%c", 0); } } } fclose(fdest); } else { /* Gray-scale */ /* -->> -->> -->> -->> 8 bits non code (Gray scale) <<-- <<-- <<-- <<-- */ fdest = fopen(outfile, "wb"); if (!fdest) { fprintf(stderr, "ERROR -> failed to open %s for writing\n", outfile); return 1; } w = (int)image->comps[0].w; h = (int)image->comps[0].h; fprintf(fdest, "BM"); /* FILE HEADER */ /* ------------- */ fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)(h * w + 54 + 1024 + h * (w % 2)) & 0xff, (OPJ_UINT8)((h * w + 54 + 1024 + h * (w % 2)) >> 8) & 0xff, (OPJ_UINT8)((h * w + 54 + 1024 + h * (w % 2)) >> 16) & 0xff, (OPJ_UINT8)((h * w + 54 + 1024 + w * (w % 2)) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (54 + 1024) & 0xff, ((54 + 1024) >> 8) & 0xff, ((54 + 1024) >> 16) & 0xff, ((54 + 1024) >> 24) & 0xff); /* INFO HEADER */ /* ------------- */ fprintf(fdest, "%c%c%c%c", (40) & 0xff, ((40) >> 8) & 0xff, ((40) >> 16) & 0xff, ((40) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((w) & 0xff), (OPJ_UINT8)((w) >> 8) & 0xff, (OPJ_UINT8)((w) >> 16) & 0xff, (OPJ_UINT8)((w) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)((h) & 0xff), (OPJ_UINT8)((h) >> 8) & 0xff, (OPJ_UINT8)((h) >> 16) & 0xff, (OPJ_UINT8)((h) >> 24) & 0xff); fprintf(fdest, "%c%c", (1) & 0xff, ((1) >> 8) & 0xff); fprintf(fdest, "%c%c", (8) & 0xff, ((8) >> 8) & 0xff); fprintf(fdest, "%c%c%c%c", (0) & 0xff, ((0) >> 8) & 0xff, ((0) >> 16) & 0xff, ((0) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (OPJ_UINT8)(h * w + h * (w % 2)) & 0xff, (OPJ_UINT8)((h * w + h * (w % 2)) >> 8) & 0xff, (OPJ_UINT8)((h * w + h * (w % 2)) >> 16) & 0xff, (OPJ_UINT8)((h * w + h * (w % 2)) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (7834) & 0xff, ((7834) >> 8) & 0xff, ((7834) >> 16) & 0xff, ((7834) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); fprintf(fdest, "%c%c%c%c", (256) & 0xff, ((256) >> 8) & 0xff, ((256) >> 16) & 0xff, ((256) >> 24) & 0xff); if (image->comps[0].prec > 8) { adjustR = (int)image->comps[0].prec - 8; printf("BMP CONVERSION: Truncating component 0 from %d bits to 8 bits\n", image->comps[0].prec); } else { adjustR = 0; } for (i = 0; i < 256; i++) { fprintf(fdest, "%c%c%c%c", i, i, i, 0); } for (i = 0; i < w * h; i++) { int r; r = image->comps[0].data[w * h - ((i) / (w) + 1) * w + (i) % (w)]; r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); r = ((r >> adjustR) + ((r >> (adjustR - 1)) % 2)); if (r > 255) { r = 255; } else if (r < 0) { r = 0; } fprintf(fdest, "%c", (OPJ_UINT8)r); if ((i + 1) % w == 0) { for (pad = (w % 4) ? (4 - w % 4) : 0; pad > 0; pad--) { /* ADD */ fprintf(fdest, "%c", 0); } } } fclose(fdest); } return 0; }