test_decode_area.c: assign tdy to *ptileh instead of *ptilew (fixes #1195)
[openjpeg.git] / tests / test_decode_area.c
1 /*
2  * The copyright in this software is being made available under the 2-clauses
3  * BSD License, included below. This software may be subject to other third
4  * party and contributor rights, including patent rights, and no such rights
5  * are granted under this license.
6  *
7  * Copyright (c) 2017, IntoPix SA <contact@intopix.com>
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <string.h>
33 #include <stdlib.h>
34
35 #include "openjpeg.h"
36 #include "format_defs.h"
37
38
39 /* -------------------------------------------------------------------------- */
40 #define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
41 #define JP2_MAGIC "\x0d\x0a\x87\x0a"
42 /* position 45: "\xff\x52" */
43 #define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
44
45 static int infile_format(const char *fname)
46 {
47     FILE *reader;
48     unsigned char buf[12];
49     unsigned int l_nb_read;
50
51     reader = fopen(fname, "rb");
52
53     if (reader == NULL) {
54         return -1;
55     }
56
57     memset(buf, 0, 12);
58     l_nb_read = (unsigned int)fread(buf, 1, 12, reader);
59     fclose(reader);
60     if (l_nb_read != 12) {
61         return -1;
62     }
63
64     if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) {
65         return JP2_CFMT;
66     } else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) {
67         return J2K_CFMT;
68     } else {
69         return -1;
70     }
71 }
72
73
74 /* -------------------------------------------------------------------------- */
75
76 /**
77   sample error debug callback expecting no client object
78  */
79 static void error_callback(const char *msg, void *client_data)
80 {
81     (void)client_data;
82     fprintf(stdout, "[ERROR] %s", msg);
83 }
84 /**
85   sample warning debug callback expecting no client object
86  */
87 static void warning_callback(const char *msg, void *client_data)
88 {
89     (void)client_data;
90     fprintf(stdout, "[WARNING] %s", msg);
91 }
92 /**
93   sample debug callback expecting no client object
94  */
95 static void info_callback(const char *msg, void *client_data)
96 {
97     (void)client_data;
98     (void)msg;
99     /*fprintf(stdout, "[INFO] %s", msg);*/
100 }
101
102 static opj_codec_t* create_codec_and_stream(const char* input_file,
103         opj_stream_t** pOutStream)
104 {
105     opj_dparameters_t l_param;
106     opj_codec_t * l_codec = NULL;
107     opj_stream_t * l_stream = NULL;
108
109     l_stream = opj_stream_create_default_file_stream(input_file, OPJ_TRUE);
110     if (!l_stream) {
111         fprintf(stderr, "ERROR -> failed to create the stream from the file\n");
112         return NULL;
113     }
114
115     /* Set the default decoding parameters */
116     opj_set_default_decoder_parameters(&l_param);
117
118     /* */
119     l_param.decod_format = infile_format(input_file);
120
121
122     switch (l_param.decod_format) {
123     case J2K_CFMT: { /* JPEG-2000 codestream */
124         /* Get a decoder handle */
125         l_codec = opj_create_decompress(OPJ_CODEC_J2K);
126         break;
127     }
128     case JP2_CFMT: { /* JPEG 2000 compressed image data */
129         /* Get a decoder handle */
130         l_codec = opj_create_decompress(OPJ_CODEC_JP2);
131         break;
132     }
133     default: {
134         fprintf(stderr, "ERROR -> Not a valid JPEG2000 file!\n");
135         opj_stream_destroy(l_stream);
136         return NULL;
137     }
138     }
139
140     /* catch events using our callbacks and give a local context */
141     opj_set_info_handler(l_codec, info_callback, 00);
142     opj_set_warning_handler(l_codec, warning_callback, 00);
143     opj_set_error_handler(l_codec, error_callback, 00);
144
145     /* Setup the decoder decoding parameters using user parameters */
146     if (! opj_setup_decoder(l_codec, &l_param)) {
147         fprintf(stderr, "ERROR ->failed to setup the decoder\n");
148         opj_stream_destroy(l_stream);
149         opj_destroy_codec(l_codec);
150         return NULL;
151     }
152
153     *pOutStream = l_stream;
154     return l_codec;
155 }
156
157
158 opj_image_t* decode(
159     OPJ_BOOL quiet,
160     const char* input_file,
161     OPJ_INT32 x0,
162     OPJ_INT32 y0,
163     OPJ_INT32 x1,
164     OPJ_INT32 y1,
165     OPJ_UINT32* ptilew,
166     OPJ_UINT32* ptileh,
167     OPJ_UINT32* pcblkw,
168     OPJ_UINT32* pcblkh)
169 {
170     opj_codec_t * l_codec = NULL;
171     opj_image_t * l_image = NULL;
172     opj_stream_t * l_stream = NULL;
173
174     if (!quiet) {
175         if (x0 != 0 || x1 != 0 || y0 != 0 || y1 != 0) {
176             printf("Decoding %d,%d,%d,%d\n", x0, y0, x1, y1);
177         } else {
178             printf("Decoding full image\n");
179         }
180     }
181
182     l_codec = create_codec_and_stream(input_file, &l_stream);
183     if (l_codec == NULL) {
184         return NULL;
185     }
186
187     /* Read the main header of the codestream and if necessary the JP2 boxes*/
188     if (! opj_read_header(l_stream, l_codec, &l_image)) {
189         fprintf(stderr, "ERROR -> failed to read the header\n");
190         opj_stream_destroy(l_stream);
191         opj_destroy_codec(l_codec);
192         return NULL;
193     }
194
195     {
196         opj_codestream_info_v2_t* pCodeStreamInfo = opj_get_cstr_info(l_codec);
197         if (ptilew) {
198             *ptilew = pCodeStreamInfo->tdx;
199         }
200         if (ptileh) {
201             *ptileh = pCodeStreamInfo->tdy;
202         }
203         //int numResolutions = pCodeStreamInfo->m_default_tile_info.tccp_info[0].numresolutions;
204         if (pcblkw) {
205             *pcblkw = 1U << pCodeStreamInfo->m_default_tile_info.tccp_info[0].cblkw;
206         }
207         if (pcblkh) {
208             *pcblkh = 1U << pCodeStreamInfo->m_default_tile_info.tccp_info[0].cblkh;
209         }
210         opj_destroy_cstr_info(&pCodeStreamInfo);
211     }
212
213     if (x0 != 0 || x1 != 0 || y0 != 0 || y1 != 0) {
214         if (!opj_set_decode_area(l_codec, l_image, x0, y0, x1, y1)) {
215             fprintf(stderr, "ERROR -> failed to set the decoded area\n");
216             opj_stream_destroy(l_stream);
217             opj_destroy_codec(l_codec);
218             opj_image_destroy(l_image);
219             return NULL;
220         }
221     }
222
223     /* Get the decoded image */
224     if (!(opj_decode(l_codec, l_stream, l_image))) {
225         fprintf(stderr, "ERROR -> failed to decode image!\n");
226         opj_stream_destroy(l_stream);
227         opj_destroy_codec(l_codec);
228         opj_image_destroy(l_image);
229         return NULL;
230     }
231
232     if (! opj_end_decompress(l_codec, l_stream)) {
233         opj_stream_destroy(l_stream);
234         opj_destroy_codec(l_codec);
235         opj_image_destroy(l_image);
236         return NULL;
237     }
238
239
240     opj_stream_destroy(l_stream);
241     opj_destroy_codec(l_codec);
242     return l_image;
243 }
244
245 int decode_by_strip(OPJ_BOOL quiet,
246                     const char* input_file,
247                     OPJ_UINT32 strip_height,
248                     OPJ_INT32 da_x0,
249                     OPJ_INT32 da_y0,
250                     OPJ_INT32 da_x1,
251                     OPJ_INT32 da_y1,
252                     opj_image_t* full_image)
253 {
254     /* OPJ_UINT32 tilew, tileh; */
255     opj_codec_t * l_codec = NULL;
256     opj_image_t * l_image = NULL;
257     opj_stream_t * l_stream = NULL;
258     OPJ_UINT32 x0, y0, x1, y1, y;
259     OPJ_UINT32 full_x0, full_y0, full_x1, full_y1;
260
261     l_codec = create_codec_and_stream(input_file, &l_stream);
262     if (l_codec == NULL) {
263         return 1;
264     }
265
266     /* Read the main header of the codestream and if necessary the JP2 boxes*/
267     if (! opj_read_header(l_stream, l_codec, &l_image)) {
268         fprintf(stderr, "ERROR -> failed to read the header\n");
269         opj_stream_destroy(l_stream);
270         opj_destroy_codec(l_codec);
271         return 1;
272     }
273
274     full_x0 = l_image->x0;
275     full_y0 = l_image->y0;
276     full_x1 = l_image->x1;
277     full_y1 = l_image->y1;
278
279     if (da_x0 != 0 || da_y0 != 0 || da_x1 != 0 || da_y1 != 0) {
280         x0 = (OPJ_UINT32)da_x0;
281         y0 = (OPJ_UINT32)da_y0;
282         x1 = (OPJ_UINT32)da_x1;
283         y1 = (OPJ_UINT32)da_y1;
284     } else {
285         x0 = l_image->x0;
286         y0 = l_image->y0;
287         x1 = l_image->x1;
288         y1 = l_image->y1;
289     }
290     for (y = y0; y < y1; y += strip_height) {
291         OPJ_UINT32 h_req = strip_height;
292         if (y + h_req > y1) {
293             h_req = y1 - y;
294         }
295         if (!quiet) {
296             printf("Decoding %u...%u\n", y, y + h_req);
297         }
298         if (!opj_set_decode_area(l_codec, l_image, (OPJ_INT32)x0, (OPJ_INT32)y,
299                                  (OPJ_INT32)x1, (OPJ_INT32)(y + h_req))) {
300             fprintf(stderr, "ERROR -> failed to set the decoded area\n");
301             opj_stream_destroy(l_stream);
302             opj_destroy_codec(l_codec);
303             opj_image_destroy(l_image);
304             return 1;
305         }
306
307         /* Get the decoded image */
308         if (!(opj_decode(l_codec, l_stream, l_image))) {
309             fprintf(stderr, "ERROR -> failed to decode image!\n");
310             opj_stream_destroy(l_stream);
311             opj_destroy_codec(l_codec);
312             opj_image_destroy(l_image);
313             return 1;
314         }
315
316         if (full_image) {
317             OPJ_UINT32 y_check, x;
318             OPJ_UINT32 compno;
319             for (compno = 0; compno < l_image->numcomps; compno ++) {
320                 for (y_check = 0; y_check < h_req; y_check++) {
321                     for (x = x0; x < x1; x++) {
322                         OPJ_INT32 sub_image_val =
323                             l_image->comps[compno].data[y_check * (x1 - x0) + (x - x0)];
324                         OPJ_INT32 image_val =
325                             full_image->comps[compno].data[(y + y_check) * (x1 - x0) + (x - x0)];
326                         if (sub_image_val != image_val) {
327                             fprintf(stderr,
328                                     "Difference found at subimage pixel (%u,%u) "
329                                     "of compno=%u: got %d, expected %d\n",
330                                     x, y_check + y, compno, sub_image_val, image_val);
331                             return 1;
332                         }
333                     }
334                 }
335             }
336         }
337
338     }
339
340     /* If image is small enough, try a final whole image read */
341     if (full_x1 - full_x0 < 10000 && full_y1 - full_y0 < 10000) {
342         if (!quiet) {
343             printf("Decoding full image\n");
344         }
345         if (!opj_set_decode_area(l_codec, l_image,
346                                  (OPJ_INT32)full_x0, (OPJ_INT32)full_y0,
347                                  (OPJ_INT32)full_x1, (OPJ_INT32)full_y1)) {
348             fprintf(stderr, "ERROR -> failed to set the decoded area\n");
349             opj_stream_destroy(l_stream);
350             opj_destroy_codec(l_codec);
351             opj_image_destroy(l_image);
352             return 1;
353         }
354
355         /* Get the decoded image */
356         if (!(opj_decode(l_codec, l_stream, l_image))) {
357             fprintf(stderr, "ERROR -> failed to decode image!\n");
358             opj_stream_destroy(l_stream);
359             opj_destroy_codec(l_codec);
360             opj_image_destroy(l_image);
361             return 1;
362         }
363     }
364
365     if (! opj_end_decompress(l_codec, l_stream)) {
366         opj_stream_destroy(l_stream);
367         opj_destroy_codec(l_codec);
368         opj_image_destroy(l_image);
369         return 1;
370     }
371
372
373     opj_stream_destroy(l_stream);
374     opj_destroy_codec(l_codec);
375     opj_image_destroy(l_image);
376     return 0;
377 }
378
379 OPJ_BOOL check_consistency(opj_image_t* p_image, opj_image_t* p_sub_image)
380 {
381     OPJ_UINT32 compno;
382     for (compno = 0; compno < p_image->numcomps; compno ++) {
383         OPJ_UINT32 y;
384         OPJ_UINT32 shift_y = p_sub_image->comps[compno].y0 - p_image->comps[compno].y0;
385         OPJ_UINT32 shift_x = p_sub_image->comps[compno].x0 - p_image->comps[compno].x0;
386         OPJ_UINT32 image_w = p_image->comps[compno].w;
387         OPJ_UINT32 sub_image_w = p_sub_image->comps[compno].w;
388         for (y = 0; y < p_sub_image->comps[compno].h; y++) {
389             OPJ_UINT32 x;
390
391             for (x = 0; x < sub_image_w; x++) {
392                 OPJ_INT32 sub_image_val =
393                     p_sub_image->comps[compno].data[y * sub_image_w + x];
394                 OPJ_INT32 image_val =
395                     p_image->comps[compno].data[(y + shift_y) * image_w + x + shift_x];
396                 if (sub_image_val != image_val) {
397                     fprintf(stderr,
398                             "Difference found at subimage pixel (%u,%u) "
399                             "of compno=%u: got %d, expected %d\n",
400                             x, y, compno, sub_image_val, image_val);
401                     return OPJ_FALSE;
402                 }
403             }
404         }
405     }
406     return OPJ_TRUE;
407 }
408
409 static INLINE OPJ_UINT32 opj_uint_min(OPJ_UINT32  a, OPJ_UINT32  b)
410 {
411     return (a < b) ? a : b;
412 }
413
414 int main(int argc, char** argv)
415 {
416     opj_image_t * l_image = NULL;
417     opj_image_t * l_sub_image = NULL;
418     OPJ_INT32 da_x0 = 0, da_y0 = 0, da_x1 = 0, da_y1 = 0;
419     const char* input_file = NULL;
420     OPJ_UINT32 tilew, tileh, cblkw, cblkh;
421     OPJ_UINT32 w, h;
422     OPJ_UINT32 x, y;
423     OPJ_UINT32 step_x, step_y;
424     OPJ_BOOL quiet = OPJ_FALSE;
425     OPJ_UINT32 nsteps = 100;
426     OPJ_UINT32 strip_height = 0;
427     OPJ_BOOL strip_check = OPJ_FALSE;
428
429     if (argc < 2) {
430         fprintf(stderr,
431                 "Usage: test_decode_area [-q] [-steps n] input_file_jp2_or_jk2 [x0 y0 x1 y1]\n"
432                 "or   : test_decode_area [-q] [-strip_height h] [-strip_check] input_file_jp2_or_jk2 [x0 y0 x1 y1]\n");
433         return 1;
434     }
435
436     {
437         int iarg;
438         for (iarg = 1; iarg < argc; iarg++) {
439             if (strcmp(argv[iarg], "-q") == 0) {
440                 quiet = OPJ_TRUE;
441             } else if (strcmp(argv[iarg], "-steps") == 0 && iarg + 1 < argc) {
442                 nsteps = (OPJ_UINT32)atoi(argv[iarg + 1]);
443                 iarg ++;
444             } else if (strcmp(argv[iarg], "-strip_height") == 0 && iarg + 1 < argc) {
445                 strip_height = (OPJ_UINT32)atoi(argv[iarg + 1]);
446                 iarg ++;
447             } else if (strcmp(argv[iarg], "-strip_check") == 0) {
448                 strip_check = OPJ_TRUE;
449             } else if (input_file == NULL) {
450                 input_file = argv[iarg];
451             } else if (iarg + 3 < argc) {
452                 da_x0 = atoi(argv[iarg]);
453                 da_y0 = atoi(argv[iarg + 1]);
454                 da_x1 = atoi(argv[iarg + 2]);
455                 da_y1 = atoi(argv[iarg + 3]);
456                 if (da_x0 < 0 || da_y0 < 0 || da_x1 < 0 || da_y1 < 0) {
457                     fprintf(stderr, "Wrong bounds\n");
458                     return 1;
459                 }
460                 iarg += 3;
461             }
462         }
463     }
464
465     if (!strip_height || strip_check) {
466         l_image = decode(quiet, input_file, 0, 0, 0, 0,
467                          &tilew, &tileh, &cblkw, &cblkh);
468         if (!l_image) {
469             return 1;
470         }
471     }
472
473     if (strip_height) {
474         int ret = decode_by_strip(quiet, input_file, strip_height, da_x0, da_y0, da_x1,
475                                   da_y1, l_image);
476         if (l_image) {
477             opj_image_destroy(l_image);
478         }
479         return ret;
480     }
481
482     if (da_x0 != 0 || da_x1 != 0 || da_y0 != 0 || da_y1 != 0) {
483         l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
484                              NULL, NULL, NULL, NULL);
485         if (!l_sub_image) {
486             fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
487                     da_x0, da_y0, da_x1, da_y1);
488             opj_image_destroy(l_sub_image);
489             opj_image_destroy(l_image);
490             return 1;
491         }
492
493         if (!check_consistency(l_image, l_sub_image)) {
494             fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
495                     da_x0, da_y0, da_x1, da_y1);
496             opj_image_destroy(l_sub_image);
497             opj_image_destroy(l_image);
498             return 1;
499         }
500         opj_image_destroy(l_sub_image);
501         opj_image_destroy(l_image);
502         return 0;
503     }
504
505     w = l_image->x1 - l_image->x0;
506     h = l_image->y1 - l_image->y0;
507     step_x = w > nsteps ? w / nsteps : 1;
508     step_y = h > nsteps ? h / nsteps : 1;
509     for (y = 0; y < h; y += step_y) {
510         for (x = 0; x < w; x += step_x) {
511             da_x0 = (OPJ_INT32)(l_image->x0 + x);
512             da_y0 = (OPJ_INT32)(l_image->y0 + y);
513             da_x1 = (OPJ_INT32)opj_uint_min(l_image->x1, l_image->x0 + x + 1);
514             da_y1 = (OPJ_INT32)opj_uint_min(l_image->y1, l_image->y0 + y + 1);
515             l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
516                                  NULL, NULL, NULL, NULL);
517             if (!l_sub_image) {
518                 fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
519                         da_x0, da_y0, da_x1, da_y1);
520                 opj_image_destroy(l_sub_image);
521                 opj_image_destroy(l_image);
522                 return 1;
523             }
524
525             if (!check_consistency(l_image, l_sub_image)) {
526                 fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
527                         da_x0, da_y0, da_x1, da_y1);
528                 opj_image_destroy(l_sub_image);
529                 opj_image_destroy(l_image);
530                 return 1;
531             }
532             opj_image_destroy(l_sub_image);
533
534             if (step_x > 1 || step_y > 1) {
535                 if (step_x > 1) {
536                     da_x0 = (OPJ_INT32)opj_uint_min(l_image->x1, (OPJ_UINT32)da_x0 + 1);
537                     da_x1 = (OPJ_INT32)opj_uint_min(l_image->x1, (OPJ_UINT32)da_x1 + 1);
538                 }
539                 if (step_y > 1) {
540                     da_y0 = (OPJ_INT32)opj_uint_min(l_image->y1, (OPJ_UINT32)da_y0 + 1);
541                     da_y1 = (OPJ_INT32)opj_uint_min(l_image->y1, (OPJ_UINT32)da_y1 + 1);
542                 }
543                 if (da_x0 < (OPJ_INT32)l_image->x1 && da_y0 < (OPJ_INT32)l_image->y1) {
544                     l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
545                                          NULL, NULL, NULL, NULL);
546                     if (!l_sub_image) {
547                         fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
548                                 da_x0, da_y0, da_x1, da_y1);
549                         opj_image_destroy(l_sub_image);
550                         opj_image_destroy(l_image);
551                         return 1;
552                     }
553
554                     if (!check_consistency(l_image, l_sub_image)) {
555                         fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
556                                 da_x0, da_y0, da_x1, da_y1);
557                         opj_image_destroy(l_sub_image);
558                         opj_image_destroy(l_image);
559                         return 1;
560                     }
561                     opj_image_destroy(l_sub_image);
562                 }
563             }
564         }
565     }
566
567     opj_image_destroy(l_image);
568     return 0;
569 }