From d2d798d0f11abcbf141db69869e76e8d123ec1eb Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Sat, 13 Dec 2014 20:28:24 +0000 Subject: FreeImage updated to 3.16 git-svn-id: http://svn.miranda-ng.org/main/trunk@11379 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/AdvaImg/src/FreeImage/J2KHelper.cpp | 1091 +++++++++++++++------------ 1 file changed, 591 insertions(+), 500 deletions(-) (limited to 'plugins/AdvaImg/src/FreeImage/J2KHelper.cpp') diff --git a/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp b/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp index c9f8fa57af..1776c3bfd2 100644 --- a/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp +++ b/plugins/AdvaImg/src/FreeImage/J2KHelper.cpp @@ -1,500 +1,591 @@ -// ========================================================== -// JPEG2000 helpers -// -// Design and implementation by -// - Hervé Drolon (drolon@infonie.fr) -// -// This file is part of FreeImage 3 -// -// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY -// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES -// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE -// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED -// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT -// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY -// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL -// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER -// THIS DISCLAIMER. -// -// Use at your own risk! -// ========================================================== - -#include "FreeImage.h" -#include "Utilities.h" -#include "../LibOpenJPEG/openjpeg.h" - -/** -Divide an integer by a power of 2 and round upwards -@return Returns a divided by 2^b -*/ -static int int_ceildivpow2(int a, int b) { - return (a + (1 << b) - 1) >> b; -} - -/** -Convert a OpenJPEG image to a FIBITMAP -@param format_id Plugin ID -@param image OpenJPEG image -@return Returns the converted image if successful, returns NULL otherwise -*/ -FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image) { - FIBITMAP *dib = NULL; - - try { - // compute image width and height - - //int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); - int wr = image->comps[0].w; - int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor); - - //int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); - //int hr = image->comps[0].h; - int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor); - - // check the number of components - - int numcomps = image->numcomps; - - BOOL bIsValid = TRUE; - for(int c = 0; c < numcomps - 1; c++) { - if( (image->comps[c].dx == image->comps[c+1].dx) && - (image->comps[c].dy == image->comps[c+1].dy) && - (image->comps[c].prec == image->comps[c+1].prec) ) { - continue; - } else { - bIsValid = FALSE; - break; - } - } - bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4)); - if(!bIsValid) { - if(numcomps) { - FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps); - numcomps = 1; - } else { - // unknown type - throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; - } - } - - // create a new DIB - - if(image->comps[0].prec <= 8) { - switch(numcomps) { - case 1: - dib = FreeImage_Allocate(wrr, hrr, 8); - break; - case 3: - dib = FreeImage_Allocate(wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); - break; - case 4: - dib = FreeImage_Allocate(wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); - break; - } - } else if(image->comps[0].prec <= 16) { - switch(numcomps) { - case 1: - dib = FreeImage_AllocateT(FIT_UINT16, wrr, hrr); - break; - case 3: - dib = FreeImage_AllocateT(FIT_RGB16, wrr, hrr); - break; - case 4: - dib = FreeImage_AllocateT(FIT_RGBA16, wrr, hrr); - break; - } - } else { - throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; - } - if(!dib) { - throw FI_MSG_ERROR_DIB_MEMORY; - } - - if(image->comps[0].prec <= 8) { - if(numcomps == 1) { - // 8-bit greyscale - // ---------------------------------------------------------- - - // build a greyscale palette - - RGBQUAD *pal = FreeImage_GetPalette(dib); - for (int i = 0; i < 256; i++) { - pal[i].rgbRed = (BYTE)i; - pal[i].rgbGreen = (BYTE)i; - pal[i].rgbBlue = (BYTE)i; - } - - // load pixel data - - unsigned pixel_count = 0; - - for(int y = 0; y < hrr; y++) { - BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); - - for(int x = 0; x < wrr; x++) { - const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; - - int index = image->comps[0].data[pixel_pos]; - index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - - bits[x] = (BYTE)index; - - pixel_count++; - } - } - } - else if(numcomps == 3) { - - // 24-bit RGB - // ---------------------------------------------------------- - - // load pixel data - - unsigned pixel_count = 0; - - for(int y = 0; y < hrr; y++) { - BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); - - for(int x = 0; x < wrr; x++) { - const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; - - int r = image->comps[0].data[pixel_pos]; - r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - - int g = image->comps[1].data[pixel_pos]; - g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); - - int b = image->comps[2].data[pixel_pos]; - b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); - - bits[FI_RGBA_RED] = (BYTE)r; - bits[FI_RGBA_GREEN] = (BYTE)g; - bits[FI_RGBA_BLUE] = (BYTE)b; - bits += 3; - - pixel_count++; - } - } - } - else if(numcomps == 4) { - - // 32-bit RGBA - // ---------------------------------------------------------- - - // load pixel data - - unsigned pixel_count = 0; - - for(int y = 0; y < hrr; y++) { - BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); - - for(int x = 0; x < wrr; x++) { - const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; - - int r = image->comps[0].data[pixel_pos]; - r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - - int g = image->comps[1].data[pixel_pos]; - g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); - - int b = image->comps[2].data[pixel_pos]; - b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); - - int a = image->comps[3].data[pixel_pos]; - a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); - - bits[FI_RGBA_RED] = (BYTE)r; - bits[FI_RGBA_GREEN] = (BYTE)g; - bits[FI_RGBA_BLUE] = (BYTE)b; - bits[FI_RGBA_ALPHA] = (BYTE)a; - bits += 4; - - pixel_count++; - } - } - } - } - else if(image->comps[0].prec <= 16) { - if(numcomps == 1) { - // 16-bit greyscale - // ---------------------------------------------------------- - - // load pixel data - - unsigned pixel_count = 0; - - for(int y = 0; y < hrr; y++) { - unsigned short *bits = (unsigned short*)FreeImage_GetScanLine(dib, hrr - 1 - y); - - for(int x = 0; x < wrr; x++) { - const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; - - int index = image->comps[0].data[pixel_pos]; - index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - - bits[x] = (unsigned short)index; - - pixel_count++; - } - } - } - else if(numcomps == 3) { - - // 48-bit RGB - // ---------------------------------------------------------- - - // load pixel data - - unsigned pixel_count = 0; - - for(int y = 0; y < hrr; y++) { - FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y); - - for(int x = 0; x < wrr; x++) { - const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; - - int r = image->comps[0].data[pixel_pos]; - r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - - int g = image->comps[1].data[pixel_pos]; - g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); - - int b = image->comps[2].data[pixel_pos]; - b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); - - bits[x].red = (WORD)r; - bits[x].green = (WORD)g; - bits[x].blue = (WORD)b; - - pixel_count++; - } - } - } - else if(numcomps == 4) { - - // 64-bit RGBA - // ---------------------------------------------------------- - - // load pixel data - - unsigned pixel_count = 0; - - for(int y = 0; y < hrr; y++) { - FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y); - - for(int x = 0; x < wrr; x++) { - const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; - - int r = image->comps[0].data[pixel_pos]; - r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); - - int g = image->comps[1].data[pixel_pos]; - g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); - - int b = image->comps[2].data[pixel_pos]; - b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); - - int a = image->comps[3].data[pixel_pos]; - a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); - - bits[x].red = (WORD)r; - bits[x].green = (WORD)g; - bits[x].blue = (WORD)b; - bits[x].alpha = (WORD)a; - - pixel_count++; - } - } - } - } - - return dib; - - } catch(const char *text) { - if(dib) FreeImage_Unload(dib); - FreeImage_OutputMessageProc(format_id, text); - return NULL; - } - -} - -/** -Convert a FIBITMAP to a OpenJPEG image -@param format_id Plugin ID -@param dib FreeImage image -@param parameters Compression parameters -@return Returns the converted image if successful, returns NULL otherwise -*/ -opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) { - int prec, numcomps, x, y, index; - OPJ_COLOR_SPACE color_space; - opj_image_cmptparm_t cmptparm[4]; // maximum of 4 components - opj_image_t *image = NULL; // image to encode - - try { - int w = FreeImage_GetWidth(dib); - int h = FreeImage_GetHeight(dib); - - // get image characteristics - FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); - - if(image_type == FIT_BITMAP) { - // standard image ... - prec = 8; - switch(FreeImage_GetColorType(dib)) { - case FIC_MINISBLACK: - numcomps = 1; - color_space = CLRSPC_GRAY; - break; - case FIC_RGB: - if(FreeImage_GetBPP(dib) == 32) { - // 32-bit image with a fully opaque layer - numcomps = 4; - color_space = CLRSPC_SRGB; - } else { - // 24-bit image - numcomps = 3; - color_space = CLRSPC_SRGB; - } - break; - case FIC_RGBALPHA: - numcomps = 4; - color_space = CLRSPC_SRGB; - break; - default: - return NULL; - } - } else { - // HDR image ... - prec = 16; - switch(image_type) { - case FIT_UINT16: - numcomps = 1; - color_space = CLRSPC_GRAY; - break; - case FIT_RGB16: - numcomps = 3; - color_space = CLRSPC_SRGB; - break; - case FIT_RGBA16: - numcomps = 4; - color_space = CLRSPC_SRGB; - break; - default: - return NULL; - } - } - - // initialize image components - memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); - for(int i = 0; i < numcomps; i++) { - cmptparm[i].dx = parameters->subsampling_dx; - cmptparm[i].dy = parameters->subsampling_dy; - cmptparm[i].w = w; - cmptparm[i].h = h; - cmptparm[i].prec = prec; - cmptparm[i].bpp = prec; - cmptparm[i].sgnd = 0; - } - // create the image - image = opj_image_create(numcomps, &cmptparm[0], color_space); - if(!image) { - throw FI_MSG_ERROR_DIB_MEMORY; - } - - // set image offset and reference grid - image->x0 = parameters->image_offset_x0; - image->y0 = parameters->image_offset_y0; - image->x1 = parameters->image_offset_x0 + (w - 1) * parameters->subsampling_dx + 1; - image->y1 = parameters->image_offset_y0 + (h - 1) * parameters->subsampling_dy + 1; - - // set image data - if(prec == 8) { - switch(numcomps) { - case 1: - index = 0; - for(y = 0; y < h; y++) { - BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); - for(x = 0; x < w; x++) { - image->comps[0].data[index] = bits[x]; - index++; - } - } - break; - case 3: - index = 0; - for(y = 0; y < h; y++) { - BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); - for(x = 0; x < w; x++) { - image->comps[0].data[index] = bits[FI_RGBA_RED]; - image->comps[1].data[index] = bits[FI_RGBA_GREEN]; - image->comps[2].data[index] = bits[FI_RGBA_BLUE]; - bits += 3; - index++; - } - } - break; - case 4: - index = 0; - for(y = 0; y < h; y++) { - BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); - for(x = 0; x < w; x++) { - image->comps[0].data[index] = bits[FI_RGBA_RED]; - image->comps[1].data[index] = bits[FI_RGBA_GREEN]; - image->comps[2].data[index] = bits[FI_RGBA_BLUE]; - image->comps[3].data[index] = bits[FI_RGBA_ALPHA]; - bits += 4; - index++; - } - } - break; - } - } - else if(prec == 16) { - switch(numcomps) { - case 1: - index = 0; - for(y = 0; y < h; y++) { - WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y); - for(x = 0; x < w; x++) { - image->comps[0].data[index] = bits[x]; - index++; - } - } - break; - case 3: - index = 0; - for(y = 0; y < h; y++) { - FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y); - for(x = 0; x < w; x++) { - image->comps[0].data[index] = bits[x].red; - image->comps[1].data[index] = bits[x].green; - image->comps[2].data[index] = bits[x].blue; - index++; - } - } - break; - case 4: - index = 0; - for(y = 0; y < h; y++) { - FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y); - for(x = 0; x < w; x++) { - image->comps[0].data[index] = bits[x].red; - image->comps[1].data[index] = bits[x].green; - image->comps[2].data[index] = bits[x].blue; - image->comps[3].data[index] = bits[x].alpha; - index++; - } - } - break; - } - } - - return image; - - } catch (const char *text) { - if(image) opj_image_destroy(image); - FreeImage_OutputMessageProc(format_id, text); - return NULL; - } -} +// ========================================================== +// JPEG2000 helpers +// +// Design and implementation by +// - Hervé Drolon (drolon@infonie.fr) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" +#include "../LibOpenJPEG/openjpeg.h" +#include "J2KHelper.h" + +// -------------------------------------------------------------------------- + +static OPJ_UINT64 +_LengthProc(J2KFIO_t *fio) { + long start_pos = fio->io->tell_proc(fio->handle); + fio->io->seek_proc(fio->handle, 0, SEEK_END); + unsigned file_length = fio->io->tell_proc(fio->handle) - start_pos; + fio->io->seek_proc(fio->handle, start_pos, SEEK_SET); + return (OPJ_UINT64)file_length; +} + +static OPJ_SIZE_T +_ReadProc(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) { + J2KFIO_t *fio = (J2KFIO_t*)p_user_data; + OPJ_SIZE_T l_nb_read = fio->io->read_proc(p_buffer, 1, (unsigned)p_nb_bytes, fio->handle); + return l_nb_read ? l_nb_read : (OPJ_SIZE_T)-1; +} + +static OPJ_SIZE_T +_WriteProc(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) { + J2KFIO_t *fio = (J2KFIO_t*)p_user_data; + return fio->io->write_proc(p_buffer, 1, (unsigned)p_nb_bytes, fio->handle); +} + +static OPJ_OFF_T +_SkipProc(OPJ_OFF_T p_nb_bytes, void *p_user_data) { + J2KFIO_t *fio = (J2KFIO_t*)p_user_data; + if( fio->io->seek_proc(fio->handle, (long)p_nb_bytes, SEEK_CUR) ) { + return -1; + } + return p_nb_bytes; +} + +static OPJ_BOOL +_SeekProc(OPJ_OFF_T p_nb_bytes, FILE * p_user_data) { + J2KFIO_t *fio = (J2KFIO_t*)p_user_data; + if( fio->io->seek_proc(fio->handle, (long)p_nb_bytes, SEEK_SET) ) { + return OPJ_FALSE; + } + return OPJ_TRUE; +} + +// -------------------------------------------------------------------------- + +J2KFIO_t* +opj_freeimage_stream_create(FreeImageIO *io, fi_handle handle, BOOL bRead) { + if(!handle) { + return NULL; + } + J2KFIO_t *fio = (J2KFIO_t*)malloc(sizeof(J2KFIO_t)); + if(fio) { + fio->io = io; + fio->handle = handle; + + opj_stream_t *l_stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, bRead ? OPJ_TRUE : OPJ_FALSE); + if (l_stream) { + opj_stream_set_user_data(l_stream, fio, NULL); + opj_stream_set_user_data_length(l_stream, _LengthProc(fio)); + opj_stream_set_read_function(l_stream, (opj_stream_read_fn)_ReadProc); + opj_stream_set_write_function(l_stream, (opj_stream_write_fn)_WriteProc); + opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn)_SkipProc); + opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn)_SeekProc); + fio->stream = l_stream; + return fio; + } else { + free(fio); + } + } + + return NULL; +} + +void +opj_freeimage_stream_destroy(J2KFIO_t* fio) { + if(fio) { + if(fio->stream) { + opj_stream_destroy(fio->stream); + } + free(fio); + } +} + +// -------------------------------------------------------------------------- + +/** +Divide an integer by a power of 2 and round upwards +@return Returns a divided by 2^b +*/ +static int int_ceildivpow2(int a, int b) { + return (a + (1 << b) - 1) >> b; +} + +/** +Convert a OpenJPEG image to a FIBITMAP +@param format_id Plugin ID +@param image OpenJPEG image +@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP +@return Returns the converted image if successful, returns NULL otherwise +*/ +FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image, BOOL header_only) { + FIBITMAP *dib = NULL; + + try { + // compute image width and height + + //int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); + int wr = image->comps[0].w; + int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor); + + //int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); + //int hr = image->comps[0].h; + int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor); + + // check the number of components + + int numcomps = image->numcomps; + + BOOL bIsValid = TRUE; + for(int c = 0; c < numcomps - 1; c++) { + if( (image->comps[c].dx == image->comps[c+1].dx) && + (image->comps[c].dy == image->comps[c+1].dy) && + (image->comps[c].prec == image->comps[c+1].prec) ) { + continue; + } else { + bIsValid = FALSE; + break; + } + } + bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4)); + if(!bIsValid) { + if(numcomps) { + FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps); + numcomps = 1; + } else { + // unknown type + throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; + } + } + + // create a new DIB + + if(image->comps[0].prec <= 8) { + switch(numcomps) { + case 1: + dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 8); + break; + case 3: + dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + break; + case 4: + dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + break; + } + } else if(image->comps[0].prec <= 16) { + switch(numcomps) { + case 1: + dib = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, wrr, hrr); + break; + case 3: + dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, wrr, hrr); + break; + case 4: + dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBA16, wrr, hrr); + break; + } + } else { + throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; + } + if(!dib) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + + // "header only" FIBITMAP ? + if(header_only) { + return dib; + } + + if(image->comps[0].prec <= 8) { + if(numcomps == 1) { + // 8-bit greyscale + // ---------------------------------------------------------- + + // build a greyscale palette + + RGBQUAD *pal = FreeImage_GetPalette(dib); + for (int i = 0; i < 256; i++) { + pal[i].rgbRed = (BYTE)i; + pal[i].rgbGreen = (BYTE)i; + pal[i].rgbBlue = (BYTE)i; + } + + // load pixel data + + unsigned pixel_count = 0; + + for(int y = 0; y < hrr; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); + + for(int x = 0; x < wrr; x++) { + const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; + + int index = image->comps[0].data[pixel_pos]; + index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + bits[x] = (BYTE)index; + + pixel_count++; + } + } + } + else if(numcomps == 3) { + + // 24-bit RGB + // ---------------------------------------------------------- + + // load pixel data + + unsigned pixel_count = 0; + + for(int y = 0; y < hrr; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); + + for(int x = 0; x < wrr; x++) { + const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; + + int r = image->comps[0].data[pixel_pos]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + int g = image->comps[1].data[pixel_pos]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + + int b = image->comps[2].data[pixel_pos]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + + bits[FI_RGBA_RED] = (BYTE)r; + bits[FI_RGBA_GREEN] = (BYTE)g; + bits[FI_RGBA_BLUE] = (BYTE)b; + bits += 3; + + pixel_count++; + } + } + } + else if(numcomps == 4) { + + // 32-bit RGBA + // ---------------------------------------------------------- + + // load pixel data + + unsigned pixel_count = 0; + + for(int y = 0; y < hrr; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); + + for(int x = 0; x < wrr; x++) { + const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; + + int r = image->comps[0].data[pixel_pos]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + int g = image->comps[1].data[pixel_pos]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + + int b = image->comps[2].data[pixel_pos]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + + int a = image->comps[3].data[pixel_pos]; + a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); + + bits[FI_RGBA_RED] = (BYTE)r; + bits[FI_RGBA_GREEN] = (BYTE)g; + bits[FI_RGBA_BLUE] = (BYTE)b; + bits[FI_RGBA_ALPHA] = (BYTE)a; + bits += 4; + + pixel_count++; + } + } + } + } + else if(image->comps[0].prec <= 16) { + if(numcomps == 1) { + // 16-bit greyscale + // ---------------------------------------------------------- + + // load pixel data + + unsigned pixel_count = 0; + + for(int y = 0; y < hrr; y++) { + WORD *bits = (WORD*)FreeImage_GetScanLine(dib, hrr - 1 - y); + + for(int x = 0; x < wrr; x++) { + const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; + + int index = image->comps[0].data[pixel_pos]; + index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + bits[x] = (WORD)index; + + pixel_count++; + } + } + } + else if(numcomps == 3) { + + // 48-bit RGB + // ---------------------------------------------------------- + + // load pixel data + + unsigned pixel_count = 0; + + for(int y = 0; y < hrr; y++) { + FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y); + + for(int x = 0; x < wrr; x++) { + const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; + + int r = image->comps[0].data[pixel_pos]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + int g = image->comps[1].data[pixel_pos]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + + int b = image->comps[2].data[pixel_pos]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + + bits[x].red = (WORD)r; + bits[x].green = (WORD)g; + bits[x].blue = (WORD)b; + + pixel_count++; + } + } + } + else if(numcomps == 4) { + + // 64-bit RGBA + // ---------------------------------------------------------- + + // load pixel data + + unsigned pixel_count = 0; + + for(int y = 0; y < hrr; y++) { + FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y); + + for(int x = 0; x < wrr; x++) { + const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; + + int r = image->comps[0].data[pixel_pos]; + r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); + + int g = image->comps[1].data[pixel_pos]; + g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); + + int b = image->comps[2].data[pixel_pos]; + b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); + + int a = image->comps[3].data[pixel_pos]; + a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); + + bits[x].red = (WORD)r; + bits[x].green = (WORD)g; + bits[x].blue = (WORD)b; + bits[x].alpha = (WORD)a; + + pixel_count++; + } + } + } + } + + return dib; + + } catch(const char *text) { + if(dib) FreeImage_Unload(dib); + FreeImage_OutputMessageProc(format_id, text); + return NULL; + } + +} + +/** +Convert a FIBITMAP to a OpenJPEG image +@param format_id Plugin ID +@param dib FreeImage image +@param parameters Compression parameters +@return Returns the converted image if successful, returns NULL otherwise +*/ +opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) { + int prec, numcomps, x, y, index; + OPJ_COLOR_SPACE color_space; + opj_image_cmptparm_t cmptparm[4]; // maximum of 4 components + opj_image_t *image = NULL; // image to encode + + try { + int w = FreeImage_GetWidth(dib); + int h = FreeImage_GetHeight(dib); + + // get image characteristics + FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); + + if(image_type == FIT_BITMAP) { + // standard image ... + prec = 8; + switch(FreeImage_GetColorType(dib)) { + case FIC_MINISBLACK: + numcomps = 1; + color_space = OPJ_CLRSPC_GRAY; + break; + case FIC_RGB: + if(FreeImage_GetBPP(dib) == 32) { + // 32-bit image with a fully opaque layer + numcomps = 4; + color_space = OPJ_CLRSPC_SRGB; + } else { + // 24-bit image + numcomps = 3; + color_space = OPJ_CLRSPC_SRGB; + } + break; + case FIC_RGBALPHA: + numcomps = 4; + color_space = OPJ_CLRSPC_SRGB; + break; + default: + return NULL; + } + } else { + // HDR image ... + prec = 16; + switch(image_type) { + case FIT_UINT16: + numcomps = 1; + color_space = OPJ_CLRSPC_GRAY; + break; + case FIT_RGB16: + numcomps = 3; + color_space = OPJ_CLRSPC_SRGB; + break; + case FIT_RGBA16: + numcomps = 4; + color_space = OPJ_CLRSPC_SRGB; + break; + default: + return NULL; + } + } + + // initialize image components + memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); + for(int i = 0; i < numcomps; i++) { + cmptparm[i].dx = parameters->subsampling_dx; + cmptparm[i].dy = parameters->subsampling_dy; + cmptparm[i].w = w; + cmptparm[i].h = h; + cmptparm[i].prec = prec; + cmptparm[i].bpp = prec; + cmptparm[i].sgnd = 0; + } + // create the image + image = opj_image_create(numcomps, &cmptparm[0], color_space); + if(!image) { + throw FI_MSG_ERROR_DIB_MEMORY; + } + + // set image offset and reference grid + image->x0 = parameters->image_offset_x0; + image->y0 = parameters->image_offset_y0; + image->x1 = parameters->image_offset_x0 + (w - 1) * parameters->subsampling_dx + 1; + image->y1 = parameters->image_offset_y0 + (h - 1) * parameters->subsampling_dy + 1; + + // set image data + if(prec == 8) { + switch(numcomps) { + case 1: + index = 0; + for(y = 0; y < h; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); + for(x = 0; x < w; x++) { + image->comps[0].data[index] = bits[x]; + index++; + } + } + break; + case 3: + index = 0; + for(y = 0; y < h; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); + for(x = 0; x < w; x++) { + image->comps[0].data[index] = bits[FI_RGBA_RED]; + image->comps[1].data[index] = bits[FI_RGBA_GREEN]; + image->comps[2].data[index] = bits[FI_RGBA_BLUE]; + bits += 3; + index++; + } + } + break; + case 4: + index = 0; + for(y = 0; y < h; y++) { + BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); + for(x = 0; x < w; x++) { + image->comps[0].data[index] = bits[FI_RGBA_RED]; + image->comps[1].data[index] = bits[FI_RGBA_GREEN]; + image->comps[2].data[index] = bits[FI_RGBA_BLUE]; + image->comps[3].data[index] = bits[FI_RGBA_ALPHA]; + bits += 4; + index++; + } + } + break; + } + } + else if(prec == 16) { + switch(numcomps) { + case 1: + index = 0; + for(y = 0; y < h; y++) { + WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y); + for(x = 0; x < w; x++) { + image->comps[0].data[index] = bits[x]; + index++; + } + } + break; + case 3: + index = 0; + for(y = 0; y < h; y++) { + FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y); + for(x = 0; x < w; x++) { + image->comps[0].data[index] = bits[x].red; + image->comps[1].data[index] = bits[x].green; + image->comps[2].data[index] = bits[x].blue; + index++; + } + } + break; + case 4: + index = 0; + for(y = 0; y < h; y++) { + FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y); + for(x = 0; x < w; x++) { + image->comps[0].data[index] = bits[x].red; + image->comps[1].data[index] = bits[x].green; + image->comps[2].data[index] = bits[x].blue; + image->comps[3].data[index] = bits[x].alpha; + index++; + } + } + break; + } + } + + return image; + + } catch (const char *text) { + if(image) opj_image_destroy(image); + FreeImage_OutputMessageProc(format_id, text); + return NULL; + } +} -- cgit v1.2.3