Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginJ2K.cpp
Line
Count
Source (jump to first uncovered line)
1
// ==========================================================
2
// JPEG2000 J2K codestream Loader and Writer
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
#include "J2KHelper.h"
26
27
// ==========================================================
28
// Plugin Interface
29
// ==========================================================
30
31
static int s_format_id;
32
33
// ==========================================================
34
// Internal functions
35
// ==========================================================
36
37
/**
38
OpenJPEG Error callback 
39
*/
40
0
static void j2k_error_callback(const char *msg, void *client_data) {
41
0
  FreeImage_OutputMessageProc(s_format_id, "Error: %s", msg);
42
0
}
43
/**
44
OpenJPEG Warning callback 
45
*/
46
0
static void j2k_warning_callback(const char *msg, void *client_data) {
47
0
  FreeImage_OutputMessageProc(s_format_id, "Warning: %s", msg);
48
0
}
49
50
// ==========================================================
51
// Plugin Implementation
52
// ==========================================================
53
54
static const char * DLL_CALLCONV
55
2
Format() {
56
2
  return "J2K";
57
2
}
58
59
static const char * DLL_CALLCONV
60
0
Description() {
61
0
  return "JPEG-2000 codestream";
62
0
}
63
64
static const char * DLL_CALLCONV
65
0
Extension() {
66
0
  return "j2k,j2c";
67
0
}
68
69
static const char * DLL_CALLCONV
70
0
RegExpr() {
71
0
  return NULL;
72
0
}
73
74
static const char * DLL_CALLCONV
75
0
MimeType() {
76
0
  return "image/j2k";
77
0
}
78
79
static BOOL DLL_CALLCONV
80
29.3k
Validate(FreeImageIO *io, fi_handle handle) {
81
29.3k
  BYTE jpc_signature[] = { 0xFF, 0x4F };
82
29.3k
  BYTE signature[2] = { 0, 0 };
83
84
29.3k
  long tell = io->tell_proc(handle);
85
29.3k
  io->read_proc(signature, 1, sizeof(jpc_signature), handle);
86
29.3k
  io->seek_proc(handle, tell, SEEK_SET);
87
88
29.3k
  return (memcmp(jpc_signature, signature, sizeof(jpc_signature)) == 0);
89
29.3k
}
90
91
static BOOL DLL_CALLCONV
92
0
SupportsExportDepth(int depth) {
93
0
  return (
94
0
    (depth == 8) ||
95
0
    (depth == 24) || 
96
0
    (depth == 32)
97
0
  );
98
0
}
99
100
static BOOL DLL_CALLCONV 
101
0
SupportsExportType(FREE_IMAGE_TYPE type) {
102
0
  return (
103
0
    (type == FIT_BITMAP)  ||
104
0
    (type == FIT_UINT16)  ||
105
0
    (type == FIT_RGB16) || 
106
0
    (type == FIT_RGBA16)
107
0
  );
108
0
}
109
110
// ----------------------------------------------------------
111
112
static void * DLL_CALLCONV
113
0
Open(FreeImageIO *io, fi_handle handle, BOOL read) {
114
  // create the stream wrapper
115
0
  J2KFIO_t *fio = opj_freeimage_stream_create(io, handle, read);
116
0
  return fio;
117
0
}
118
119
static void DLL_CALLCONV
120
0
Close(FreeImageIO *io, fi_handle handle, void *data) {
121
  // destroy the stream wrapper
122
0
  J2KFIO_t *fio = (J2KFIO_t*)data;
123
0
  opj_freeimage_stream_destroy(fio);
124
0
}
125
126
// ----------------------------------------------------------
127
128
static FIBITMAP * DLL_CALLCONV
129
0
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
130
0
  J2KFIO_t *fio = (J2KFIO_t*)data;
131
0
  if (handle && fio) {
132
0
    opj_codec_t *d_codec = NULL;  // handle to a decompressor
133
0
    opj_dparameters_t parameters; // decompression parameters
134
0
    opj_image_t *image = NULL;    // decoded image 
135
136
0
    FIBITMAP *dib = NULL;
137
138
    // check the file format
139
0
    if(!Validate(io, handle)) {
140
0
      return NULL;
141
0
    }
142
143
0
    BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
144
145
    // get the OpenJPEG stream
146
0
    opj_stream_t *d_stream = fio->stream;
147
148
    // set decoding parameters to default values 
149
0
    opj_set_default_decoder_parameters(&parameters);
150
151
0
    try {
152
      // decode the JPEG-2000 codestream
153
154
      // get a decoder handle
155
0
      d_codec = opj_create_decompress(OPJ_CODEC_J2K);
156
      
157
      // configure the event callbacks
158
      // catch events using our callbacks (no local context needed here)
159
0
      opj_set_info_handler(d_codec, NULL, NULL);
160
0
      opj_set_warning_handler(d_codec, j2k_warning_callback, NULL);
161
0
      opj_set_error_handler(d_codec, j2k_error_callback, NULL);
162
163
      // setup the decoder decoding parameters using user parameters
164
0
      if( !opj_setup_decoder(d_codec, &parameters) ) {
165
0
        throw "Failed to setup the decoder\n";
166
0
      }
167
      
168
      // read the main header of the codestream and if necessary the JP2 boxes
169
0
      if( !opj_read_header(d_stream, d_codec, &image)) {
170
0
        throw "Failed to read the header\n";
171
0
      }
172
173
      // --- header only mode
174
175
0
      if (header_only) {
176
        // create output image 
177
0
        dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
178
0
        if(!dib) {
179
0
          throw "Failed to import JPEG2000 image";
180
0
        }
181
        // clean-up and return header data
182
0
        opj_destroy_codec(d_codec);
183
0
        opj_image_destroy(image);
184
0
        return dib;
185
0
      }
186
187
      // decode the stream and fill the image structure 
188
0
      if( !( opj_decode(d_codec, d_stream, image) && opj_end_decompress(d_codec, d_stream) ) ) {
189
0
        throw "Failed to decode image!\n";
190
0
      }
191
192
      // free the codec context
193
0
      opj_destroy_codec(d_codec);
194
0
      d_codec = NULL;
195
196
      // create output image 
197
0
      dib = J2KImageToFIBITMAP(s_format_id, image, header_only);
198
0
      if(!dib) {
199
0
        throw "Failed to import JPEG2000 image";
200
0
      }
201
202
      // free image data structure
203
0
      opj_image_destroy(image);
204
205
0
      return dib;
206
207
0
    } catch (const char *text) {
208
0
      if(dib) {
209
0
        FreeImage_Unload(dib);
210
0
      }
211
      // free remaining structures
212
0
      opj_destroy_codec(d_codec);
213
0
      opj_image_destroy(image);
214
215
0
      FreeImage_OutputMessageProc(s_format_id, text);
216
217
0
      return NULL;
218
0
    }
219
0
  }
220
221
0
  return NULL;
222
0
}
223
224
static BOOL DLL_CALLCONV
225
0
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
226
0
  J2KFIO_t *fio = (J2KFIO_t*)data;
227
0
  if (dib && handle && fio) {
228
0
    BOOL bSuccess;
229
0
    opj_codec_t *c_codec = NULL;  // handle to a compressor
230
0
    opj_cparameters_t parameters; // compression parameters
231
0
    opj_image_t *image = NULL;    // image to encode
232
233
    // get the OpenJPEG stream
234
0
    opj_stream_t *c_stream = fio->stream;
235
236
    // set encoding parameters to default values
237
0
    opj_set_default_encoder_parameters(&parameters);
238
239
0
    try {
240
0
      parameters.tcp_numlayers = 0;
241
      // if no rate entered, apply a 16:1 rate by default
242
0
      if(flags == J2K_DEFAULT) {
243
0
        parameters.tcp_rates[0] = (float)16;
244
0
      } else {
245
        // for now, the flags parameter is only used to specify the rate
246
0
        parameters.tcp_rates[0] = (float)(flags & 0x3FF);
247
0
      }
248
0
      parameters.tcp_numlayers++;
249
0
      parameters.cp_disto_alloc = 1;
250
251
      // convert the dib to a OpenJPEG image
252
0
      image = FIBITMAPToJ2KImage(s_format_id, dib, &parameters);
253
0
      if(!image) {
254
0
        return FALSE;
255
0
      }
256
257
      // decide if MCT should be used
258
0
      parameters.tcp_mct = (image->numcomps == 3) ? 1 : 0;
259
260
      // encode the destination image
261
262
      // get a J2K compressor handle
263
0
      c_codec = opj_create_compress(OPJ_CODEC_J2K);
264
265
      // configure the event callbacks
266
      // catch events using our callbacks (no local context needed here)
267
0
      opj_set_info_handler(c_codec, NULL, NULL);
268
0
      opj_set_warning_handler(c_codec, j2k_warning_callback, NULL);
269
0
      opj_set_error_handler(c_codec, j2k_error_callback, NULL);
270
271
      // setup the encoder parameters using the current image and using user parameters
272
0
      opj_setup_encoder(c_codec, &parameters, image);
273
274
      // encode the image
275
0
      bSuccess = opj_start_compress(c_codec, image, c_stream);
276
0
      if(bSuccess) {
277
0
        bSuccess = bSuccess && opj_encode(c_codec, c_stream);
278
0
        if(bSuccess) {
279
0
          bSuccess = bSuccess && opj_end_compress(c_codec, c_stream);
280
0
        }
281
0
      }
282
0
      if (!bSuccess) {
283
0
        throw "Failed to encode image";
284
0
      }
285
286
      // free remaining compression structures
287
0
      opj_destroy_codec(c_codec);
288
      
289
      // free image data
290
0
      opj_image_destroy(image);
291
292
0
      return TRUE;
293
294
0
    } catch (const char *text) {
295
0
      if(c_codec) opj_destroy_codec(c_codec);
296
0
      if(image) opj_image_destroy(image);
297
0
      FreeImage_OutputMessageProc(s_format_id, text);
298
0
      return FALSE;
299
0
    }
300
0
  }
301
302
0
  return FALSE;
303
0
}
304
305
// ==========================================================
306
//   Init
307
// ==========================================================
308
309
void DLL_CALLCONV
310
2
InitJ2K(Plugin *plugin, int format_id) {
311
2
  s_format_id = format_id;
312
313
2
  plugin->format_proc = Format;
314
2
  plugin->description_proc = Description;
315
2
  plugin->extension_proc = Extension;
316
2
  plugin->regexpr_proc = RegExpr;
317
2
  plugin->open_proc = Open;
318
2
  plugin->close_proc = Close;
319
2
  plugin->pagecount_proc = NULL;
320
2
  plugin->pagecapability_proc = NULL;
321
2
  plugin->load_proc = Load;
322
2
  plugin->save_proc = Save;
323
2
  plugin->validate_proc = Validate;
324
2
  plugin->mime_proc = MimeType;
325
2
  plugin->supports_export_bpp_proc = SupportsExportDepth;
326
2
  plugin->supports_export_type_proc = SupportsExportType;
327
2
  plugin->supports_icc_profiles_proc = NULL;
328
2
}