PageRenderTime 63ms CodeModel.GetById 14ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/FreeImage/J2KHelper.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 500 lines | 346 code | 82 blank | 72 comment | 79 complexity | bf9d7cf11c3e1a51f8606d4418237116 MD5 | raw file
  1// ==========================================================
  2// JPEG2000 helpers
  3//
  4// Design and implementation by
  5// - Hervé Drolon (drolon@infonie.fr)
  6//
  7// This file is part of FreeImage 3
  8//
  9// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 10// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 11// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 12// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 13// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 14// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 15// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 16// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 17// THIS DISCLAIMER.
 18//
 19// Use at your own risk!
 20// ==========================================================
 21
 22#include "FreeImage.h"
 23#include "Utilities.h"
 24#include "../LibOpenJPEG/openjpeg.h"
 25
 26/**
 27Divide an integer by a power of 2 and round upwards
 28@return Returns a divided by 2^b
 29*/
 30static int int_ceildivpow2(int a, int b) {
 31	return (a + (1 << b) - 1) >> b;
 32}
 33
 34/**
 35Convert a OpenJPEG image to a FIBITMAP
 36@param format_id Plugin ID
 37@param image OpenJPEG image
 38@return Returns the converted image if successful, returns NULL otherwise
 39*/
 40FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image) {
 41	FIBITMAP *dib = NULL;
 42
 43	try {
 44		// compute image width and height
 45
 46		//int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
 47		int wr = image->comps[0].w;
 48		int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor);
 49		
 50		//int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
 51		//int hr = image->comps[0].h;
 52		int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor);
 53
 54		// check the number of components
 55
 56		int numcomps = image->numcomps;
 57
 58		BOOL bIsValid = TRUE;
 59		for(int c = 0; c < numcomps - 1; c++) {
 60			if(	(image->comps[c].dx == image->comps[c+1].dx) && 
 61				(image->comps[c].dy == image->comps[c+1].dy) &&
 62				(image->comps[c].prec == image->comps[c+1].prec) ) {
 63				continue;
 64			} else {
 65				bIsValid = FALSE;
 66				break;
 67			}
 68		}
 69		bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4));
 70		if(!bIsValid) {
 71			if(numcomps) {
 72				FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps);
 73				numcomps = 1;
 74			} else {
 75				// unknown type
 76				throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
 77			}
 78		}
 79
 80		// create a new DIB
 81
 82		if(image->comps[0].prec <= 8) {
 83			switch(numcomps) {
 84				case 1:
 85					dib = FreeImage_Allocate(wrr, hrr, 8);
 86					break;
 87				case 3:
 88					dib = FreeImage_Allocate(wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
 89					break;
 90				case 4:
 91					dib = FreeImage_Allocate(wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
 92					break;
 93			}
 94		} else if(image->comps[0].prec <= 16) {
 95			switch(numcomps) {
 96				case 1:
 97					dib = FreeImage_AllocateT(FIT_UINT16, wrr, hrr);
 98					break;
 99				case 3:
100					dib = FreeImage_AllocateT(FIT_RGB16, wrr, hrr);
101					break;
102				case 4:
103					dib = FreeImage_AllocateT(FIT_RGBA16, wrr, hrr);
104					break;
105			}
106		} else {
107			throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
108		}
109		if(!dib) {
110			throw FI_MSG_ERROR_DIB_MEMORY;
111		}
112		
113		if(image->comps[0].prec <= 8) {
114			if(numcomps == 1) {
115				// 8-bit greyscale
116				// ----------------------------------------------------------
117
118				// build a greyscale palette
119				
120				RGBQUAD *pal = FreeImage_GetPalette(dib);
121				for (int i = 0; i < 256; i++) {
122					pal[i].rgbRed	= (BYTE)i;
123					pal[i].rgbGreen = (BYTE)i;
124					pal[i].rgbBlue	= (BYTE)i;
125				}
126
127				// load pixel data
128
129				unsigned pixel_count = 0;
130
131				for(int y = 0; y < hrr; y++) {		
132					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
133
134					for(int x = 0; x < wrr; x++) {
135						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
136
137						int index = image->comps[0].data[pixel_pos];
138						index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
139
140						bits[x] = (BYTE)index;
141
142						pixel_count++;
143					}
144				}
145			}
146			else if(numcomps == 3) {
147
148				// 24-bit RGB
149				// ----------------------------------------------------------	
150				
151				// load pixel data
152
153				unsigned pixel_count = 0;
154
155				for(int y = 0; y < hrr; y++) {		
156					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
157
158					for(int x = 0; x < wrr; x++) {
159						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
160
161						int r = image->comps[0].data[pixel_pos];
162						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
163						
164						int g = image->comps[1].data[pixel_pos];
165						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
166						
167						int b = image->comps[2].data[pixel_pos];
168						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
169
170						bits[FI_RGBA_RED]   = (BYTE)r;
171						bits[FI_RGBA_GREEN] = (BYTE)g;
172						bits[FI_RGBA_BLUE]  = (BYTE)b;
173						bits += 3;
174
175						pixel_count++;
176					}
177				}
178			}
179			else if(numcomps == 4) {
180
181				// 32-bit RGBA
182				// ----------------------------------------------------------	
183				
184				// load pixel data
185
186				unsigned pixel_count = 0;
187
188				for(int y = 0; y < hrr; y++) {		
189					BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
190
191					for(int x = 0; x < wrr; x++) {
192						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
193
194						int r = image->comps[0].data[pixel_pos];
195						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
196						
197						int g = image->comps[1].data[pixel_pos];
198						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
199						
200						int b = image->comps[2].data[pixel_pos];
201						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
202
203						int a = image->comps[3].data[pixel_pos];
204						a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
205
206						bits[FI_RGBA_RED]   = (BYTE)r;
207						bits[FI_RGBA_GREEN] = (BYTE)g;
208						bits[FI_RGBA_BLUE]  = (BYTE)b;
209						bits[FI_RGBA_ALPHA] = (BYTE)a;
210						bits += 4;
211
212						pixel_count++;
213					}
214				}
215			}
216		}
217		else if(image->comps[0].prec <= 16) {
218			if(numcomps == 1) {
219				// 16-bit greyscale
220				// ----------------------------------------------------------
221
222				// load pixel data
223
224				unsigned pixel_count = 0;
225
226				for(int y = 0; y < hrr; y++) {		
227					unsigned short *bits = (unsigned short*)FreeImage_GetScanLine(dib, hrr - 1 - y);
228
229					for(int x = 0; x < wrr; x++) {
230						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
231
232						int index = image->comps[0].data[pixel_pos];
233						index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
234
235						bits[x] = (unsigned short)index;
236
237						pixel_count++;
238					}
239				}
240			}
241			else if(numcomps == 3) {
242
243				// 48-bit RGB
244				// ----------------------------------------------------------	
245				
246				// load pixel data
247
248				unsigned pixel_count = 0;
249
250				for(int y = 0; y < hrr; y++) {		
251					FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
252
253					for(int x = 0; x < wrr; x++) {
254						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
255
256						int r = image->comps[0].data[pixel_pos];
257						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
258						
259						int g = image->comps[1].data[pixel_pos];
260						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
261						
262						int b = image->comps[2].data[pixel_pos];
263						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
264
265						bits[x].red   = (WORD)r;
266						bits[x].green = (WORD)g;
267						bits[x].blue  = (WORD)b;
268
269						pixel_count++;
270					}
271				}
272			}
273			else if(numcomps == 4) {
274
275				// 64-bit RGBA
276				// ----------------------------------------------------------	
277				
278				// load pixel data
279
280				unsigned pixel_count = 0;
281
282				for(int y = 0; y < hrr; y++) {		
283					FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
284
285					for(int x = 0; x < wrr; x++) {
286						const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
287
288						int r = image->comps[0].data[pixel_pos];
289						r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
290						
291						int g = image->comps[1].data[pixel_pos];
292						g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
293						
294						int b = image->comps[2].data[pixel_pos];
295						b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
296
297						int a = image->comps[3].data[pixel_pos];
298						a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
299
300						bits[x].red   = (WORD)r;
301						bits[x].green = (WORD)g;
302						bits[x].blue  = (WORD)b;
303						bits[x].alpha = (WORD)a;
304
305						pixel_count++;
306					}
307				}
308			}
309		}
310
311		return dib;
312
313	} catch(const char *text) {
314		if(dib) FreeImage_Unload(dib);
315		FreeImage_OutputMessageProc(format_id, text);
316		return NULL;
317	}
318
319}
320
321/**
322Convert a FIBITMAP to a OpenJPEG image
323@param format_id Plugin ID
324@param dib FreeImage image
325@param parameters Compression parameters
326@return Returns the converted image if successful, returns NULL otherwise
327*/
328opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) {
329	int prec, numcomps, x, y, index;
330	OPJ_COLOR_SPACE color_space;
331	opj_image_cmptparm_t cmptparm[4];	// maximum of 4 components 
332	opj_image_t *image = NULL;			// image to encode
333
334	try {
335		int w = FreeImage_GetWidth(dib);
336		int h = FreeImage_GetHeight(dib);
337
338		// get image characteristics
339		FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
340
341		if(image_type == FIT_BITMAP) {
342			// standard image ...
343			prec = 8;
344			switch(FreeImage_GetColorType(dib)) {
345				case FIC_MINISBLACK:
346					numcomps = 1;
347					color_space = CLRSPC_GRAY;
348					break;
349				case FIC_RGB:
350					if(FreeImage_GetBPP(dib) == 32) {
351						// 32-bit image with a fully opaque layer
352						numcomps = 4;
353						color_space = CLRSPC_SRGB;
354					} else {
355						// 24-bit image
356						numcomps = 3;
357						color_space = CLRSPC_SRGB;
358					}
359					break;
360				case FIC_RGBALPHA:
361					numcomps = 4;
362					color_space = CLRSPC_SRGB;
363					break;
364				default:
365					return NULL;
366			}
367		} else {
368			// HDR image ...
369			prec = 16;
370			switch(image_type) {
371				case FIT_UINT16:
372					numcomps = 1;
373					color_space = CLRSPC_GRAY;
374					break;
375				case FIT_RGB16:
376					numcomps = 3;
377					color_space = CLRSPC_SRGB;
378					break;
379				case FIT_RGBA16:
380					numcomps = 4;
381					color_space = CLRSPC_SRGB;
382					break;
383				default:
384					return NULL;
385			}
386		}
387
388		// initialize image components 
389		memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
390		for(int i = 0; i < numcomps; i++) {
391			cmptparm[i].dx = parameters->subsampling_dx;
392			cmptparm[i].dy = parameters->subsampling_dy;
393			cmptparm[i].w = w;
394			cmptparm[i].h = h;
395			cmptparm[i].prec = prec;
396			cmptparm[i].bpp = prec;
397			cmptparm[i].sgnd = 0;
398		}
399		// create the image 
400		image = opj_image_create(numcomps, &cmptparm[0], color_space);
401		if(!image) {
402			throw FI_MSG_ERROR_DIB_MEMORY;
403		}
404
405		// set image offset and reference grid 
406		image->x0 = parameters->image_offset_x0;
407		image->y0 = parameters->image_offset_y0;
408		image->x1 = parameters->image_offset_x0 + (w - 1) *	parameters->subsampling_dx + 1;
409		image->y1 = parameters->image_offset_y0 + (h - 1) *	parameters->subsampling_dy + 1;
410
411		// set image data 
412		if(prec == 8) {
413			switch(numcomps) {
414				case 1:
415					index = 0;
416					for(y = 0; y < h; y++) {
417						BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
418						for(x = 0; x < w; x++) {
419							image->comps[0].data[index] = bits[x];
420							index++;
421						}
422					}
423					break;
424				case 3:
425					index = 0;
426					for(y = 0; y < h; y++) {
427						BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
428						for(x = 0; x < w; x++) {
429							image->comps[0].data[index] = bits[FI_RGBA_RED];
430							image->comps[1].data[index] = bits[FI_RGBA_GREEN];
431							image->comps[2].data[index] = bits[FI_RGBA_BLUE];
432							bits += 3;
433							index++;
434						}
435					}
436					break;
437				case 4:
438					index = 0;
439					for(y = 0; y < h; y++) {
440						BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
441						for(x = 0; x < w; x++) {
442							image->comps[0].data[index] = bits[FI_RGBA_RED];
443							image->comps[1].data[index] = bits[FI_RGBA_GREEN];
444							image->comps[2].data[index] = bits[FI_RGBA_BLUE];
445							image->comps[3].data[index] = bits[FI_RGBA_ALPHA];
446							bits += 4;
447							index++;
448						}
449					}
450					break;
451			}
452		}
453		else if(prec == 16) {
454			switch(numcomps) {
455				case 1:
456					index = 0;
457					for(y = 0; y < h; y++) {
458						WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y);
459						for(x = 0; x < w; x++) {
460							image->comps[0].data[index] = bits[x];
461							index++;
462						}
463					}
464					break;
465				case 3:
466					index = 0;
467					for(y = 0; y < h; y++) {
468						FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y);
469						for(x = 0; x < w; x++) {
470							image->comps[0].data[index] = bits[x].red;
471							image->comps[1].data[index] = bits[x].green;
472							image->comps[2].data[index] = bits[x].blue;
473							index++;
474						}
475					}
476					break;
477				case 4:
478					index = 0;
479					for(y = 0; y < h; y++) {
480						FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y);
481						for(x = 0; x < w; x++) {
482							image->comps[0].data[index] = bits[x].red;
483							image->comps[1].data[index] = bits[x].green;
484							image->comps[2].data[index] = bits[x].blue;
485							image->comps[3].data[index] = bits[x].alpha;
486							index++;
487						}
488					}
489					break;
490			}
491		}
492
493		return image;
494
495	} catch (const char *text) {
496		if(image) opj_image_destroy(image);
497		FreeImage_OutputMessageProc(format_id, text);
498		return NULL;
499	}
500}