summaryrefslogtreecommitdiff
path: root/tests/test_decode_area.c
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2017-08-14 13:23:57 +0200
committerEven Rouault <even.rouault@spatialys.com>2017-08-17 19:05:54 +0200
commitfe338a057c39797bf61939471ebaef09e44464c7 (patch)
treec468abed56c47f7a1fd8d40f0ebbb44c2a404383 /tests/test_decode_area.c
parent17ea17f487a777d14bd322ac06c4e6cb9124a226 (diff)
Sub-tile decoding: only decode precincts and codeblocks that intersect the window specified in opj_set_decode_area()
Diffstat (limited to 'tests/test_decode_area.c')
-rw-r--r--tests/test_decode_area.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/tests/test_decode_area.c b/tests/test_decode_area.c
new file mode 100644
index 00000000..5a36747a
--- /dev/null
+++ b/tests/test_decode_area.c
@@ -0,0 +1,394 @@
+/*
+ * 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) 2017, IntoPix SA <contact@intopix.com>
+ * 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 <string.h>
+#include <stdlib.h>
+
+#include "openjpeg.h"
+#include "format_defs.h"
+
+
+/* -------------------------------------------------------------------------- */
+#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
+#define JP2_MAGIC "\x0d\x0a\x87\x0a"
+/* position 45: "\xff\x52" */
+#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
+
+static int infile_format(const char *fname)
+{
+ FILE *reader;
+ unsigned char buf[12];
+ unsigned int l_nb_read;
+
+ reader = fopen(fname, "rb");
+
+ if (reader == NULL) {
+ return -1;
+ }
+
+ memset(buf, 0, 12);
+ l_nb_read = (unsigned int)fread(buf, 1, 12, reader);
+ fclose(reader);
+ if (l_nb_read != 12) {
+ return -1;
+ }
+
+ if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) {
+ return JP2_CFMT;
+ } else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) {
+ return J2K_CFMT;
+ } else {
+ return -1;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ sample error debug callback expecting no client object
+ */
+static void error_callback(const char *msg, void *client_data)
+{
+ (void)client_data;
+ fprintf(stdout, "[ERROR] %s", msg);
+}
+/**
+ sample warning debug callback expecting no client object
+ */
+static void warning_callback(const char *msg, void *client_data)
+{
+ (void)client_data;
+ fprintf(stdout, "[WARNING] %s", msg);
+}
+/**
+ sample debug callback expecting no client object
+ */
+static void info_callback(const char *msg, void *client_data)
+{
+ (void)client_data;
+ (void)msg;
+ /*fprintf(stdout, "[INFO] %s", msg);*/
+}
+
+opj_image_t* decode(
+ OPJ_BOOL quiet,
+ const char* input_file,
+ OPJ_INT32 x0,
+ OPJ_INT32 y0,
+ OPJ_INT32 x1,
+ OPJ_INT32 y1,
+ OPJ_UINT32* ptilew,
+ OPJ_UINT32* ptileh,
+ OPJ_UINT32* pcblkw,
+ OPJ_UINT32* pcblkh)
+{
+ opj_dparameters_t l_param;
+ opj_codec_t * l_codec = NULL;
+ opj_image_t * l_image = NULL;
+ opj_stream_t * l_stream = NULL;
+
+ if (!quiet) {
+ if (x0 != 0 || x1 != 0 || y0 != 0 || y1 != 0) {
+ printf("Decoding %d,%d,%d,%d\n", x0, y0, x1, y1);
+ } else {
+ printf("Decoding full image\n");
+ }
+ }
+
+ l_stream = opj_stream_create_default_file_stream(input_file, OPJ_TRUE);
+ if (!l_stream) {
+ fprintf(stderr, "ERROR -> failed to create the stream from the file\n");
+ return NULL;
+ }
+
+ /* Set the default decoding parameters */
+ opj_set_default_decoder_parameters(&l_param);
+
+ /* */
+ l_param.decod_format = infile_format(input_file);
+
+
+ switch (l_param.decod_format) {
+ case J2K_CFMT: { /* JPEG-2000 codestream */
+ /* Get a decoder handle */
+ l_codec = opj_create_decompress(OPJ_CODEC_J2K);
+ break;
+ }
+ case JP2_CFMT: { /* JPEG 2000 compressed image data */
+ /* Get a decoder handle */
+ l_codec = opj_create_decompress(OPJ_CODEC_JP2);
+ break;
+ }
+ default: {
+ fprintf(stderr, "ERROR -> Not a valid JPEG2000 file!\n");
+ opj_stream_destroy(l_stream);
+ return NULL;
+ }
+ }
+
+ /* catch events using our callbacks and give a local context */
+ opj_set_info_handler(l_codec, info_callback, 00);
+ opj_set_warning_handler(l_codec, warning_callback, 00);
+ opj_set_error_handler(l_codec, error_callback, 00);
+
+ /* Setup the decoder decoding parameters using user parameters */
+ if (! opj_setup_decoder(l_codec, &l_param)) {
+ fprintf(stderr, "ERROR ->failed to setup the decoder\n");
+ opj_stream_destroy(l_stream);
+ opj_destroy_codec(l_codec);
+ return NULL;
+ }
+
+ /* Read the main header of the codestream and if necessary the JP2 boxes*/
+ if (! opj_read_header(l_stream, l_codec, &l_image)) {
+ fprintf(stderr, "ERROR -> failed to read the header\n");
+ opj_stream_destroy(l_stream);
+ opj_destroy_codec(l_codec);
+ return NULL;
+ }
+
+ {
+ opj_codestream_info_v2_t* pCodeStreamInfo = opj_get_cstr_info(l_codec);
+ if (ptilew) {
+ *ptilew = pCodeStreamInfo->tdx;
+ }
+ if (ptileh) {
+ *ptilew = pCodeStreamInfo->tdy;
+ }
+ //int numResolutions = pCodeStreamInfo->m_default_tile_info.tccp_info[0].numresolutions;
+ if (pcblkw) {
+ *pcblkw = 1U << pCodeStreamInfo->m_default_tile_info.tccp_info[0].cblkw;
+ }
+ if (pcblkh) {
+ *pcblkh = 1U << pCodeStreamInfo->m_default_tile_info.tccp_info[0].cblkh;
+ }
+ opj_destroy_cstr_info(&pCodeStreamInfo);
+ }
+
+ if (x0 != 0 || x1 != 0 || y0 != 0 || y1 != 0) {
+ if (!opj_set_decode_area(l_codec, l_image, x0, y0, x1, y1)) {
+ fprintf(stderr, "ERROR -> failed to set the decoded area\n");
+ opj_stream_destroy(l_stream);
+ opj_destroy_codec(l_codec);
+ opj_image_destroy(l_image);
+ return NULL;
+ }
+ }
+
+ /* Get the decoded image */
+ if (!(opj_decode(l_codec, l_stream, l_image))) {
+ fprintf(stderr, "ERROR -> failed to decode image!\n");
+ opj_stream_destroy(l_stream);
+ opj_destroy_codec(l_codec);
+ opj_image_destroy(l_image);
+ return NULL;
+ }
+
+ if (! opj_end_decompress(l_codec, l_stream)) {
+ opj_stream_destroy(l_stream);
+ opj_destroy_codec(l_codec);
+ opj_image_destroy(l_image);
+ return NULL;
+ }
+
+
+ opj_stream_destroy(l_stream);
+ opj_destroy_codec(l_codec);
+ return l_image;
+}
+
+OPJ_BOOL check_consistency(opj_image_t* p_image, opj_image_t* p_sub_image)
+{
+ OPJ_UINT32 compno;
+ for (compno = 0; compno < p_image->numcomps; compno ++) {
+ OPJ_UINT32 y;
+ OPJ_UINT32 shift_y = p_sub_image->comps[compno].y0 - p_image->comps[compno].y0;
+ OPJ_UINT32 shift_x = p_sub_image->comps[compno].x0 - p_image->comps[compno].x0;
+ OPJ_UINT32 image_w = p_image->comps[compno].w;
+ OPJ_UINT32 sub_image_w = p_sub_image->comps[compno].w;
+ for (y = 0; y < p_sub_image->comps[compno].h; y++) {
+ OPJ_UINT32 x;
+
+ for (x = 0; x < sub_image_w; x++) {
+ OPJ_INT32 sub_image_val =
+ p_sub_image->comps[compno].data[y * sub_image_w + x];
+ OPJ_INT32 image_val =
+ p_image->comps[compno].data[(y + shift_y) * image_w + x + shift_x];
+ if (sub_image_val != image_val) {
+ fprintf(stderr,
+ "Difference found at subimage pixel (%u,%u) "
+ "of compno=%u: got %d, expected %d\n",
+ x, y, compno, sub_image_val, image_val);
+ return OPJ_FALSE;
+ }
+ }
+ }
+ }
+ return OPJ_TRUE;
+}
+
+static INLINE OPJ_UINT32 opj_uint_min(OPJ_UINT32 a, OPJ_UINT32 b)
+{
+ return (a < b) ? a : b;
+}
+
+int main(int argc, char** argv)
+{
+ opj_image_t * l_image = NULL;
+ opj_image_t * l_sub_image = NULL;
+ OPJ_INT32 da_x0 = 0, da_y0 = 0, da_x1 = 0, da_y1 = 0;
+ const char* input_file = NULL;
+ OPJ_UINT32 tilew, tileh, cblkw, cblkh;
+ OPJ_UINT32 w, h;
+ OPJ_UINT32 x, y;
+ OPJ_UINT32 step_x, step_y;
+ OPJ_BOOL quiet = OPJ_FALSE;
+ OPJ_UINT32 nsteps = 100;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Usage: test_decode_area [-q] [-steps n] input_file_jp2_or_jk2 [x0 y0 x1 y1]\n");
+ return 1;
+ }
+
+ {
+ int iarg;
+ for (iarg = 1; iarg < argc; iarg++) {
+ if (strcmp(argv[iarg], "-q") == 0) {
+ quiet = OPJ_TRUE;
+ } else if (strcmp(argv[iarg], "-steps") == 0 && iarg + 1 < argc) {
+ nsteps = (OPJ_UINT32)atoi(argv[iarg + 1]);
+ iarg ++;
+ } else if (input_file == NULL) {
+ input_file = argv[iarg];
+ } else if (iarg + 3 < argc) {
+ da_x0 = atoi(argv[iarg]);
+ da_y0 = atoi(argv[iarg + 1]);
+ da_x1 = atoi(argv[iarg + 2]);
+ da_y1 = atoi(argv[iarg + 3]);
+ iarg += 3;
+ }
+ }
+ }
+
+ l_image = decode(quiet, input_file, 0, 0, 0, 0,
+ &tilew, &tileh, &cblkw, &cblkh);
+ if (!l_image) {
+ return 1;
+ }
+
+ if (da_x0 != 0 || da_x1 != 0 || da_y0 != 0 || da_y1 != 0) {
+ l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
+ NULL, NULL, NULL, NULL);
+ if (!l_sub_image) {
+ fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
+ da_x0, da_y0, da_x1, da_y1);
+ opj_image_destroy(l_sub_image);
+ opj_image_destroy(l_image);
+ return 1;
+ }
+
+ if (!check_consistency(l_image, l_sub_image)) {
+ fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
+ da_x0, da_y0, da_x1, da_y1);
+ opj_image_destroy(l_sub_image);
+ opj_image_destroy(l_image);
+ return 1;
+ }
+ opj_image_destroy(l_sub_image);
+ opj_image_destroy(l_image);
+ return 0;
+ }
+
+ w = l_image->x1 - l_image->x0;
+ h = l_image->y1 - l_image->y0;
+ step_x = w > nsteps ? w / nsteps : 1;
+ step_y = h > nsteps ? h / nsteps : 1;
+ for (y = 0; y < h; y += step_y) {
+ for (x = 0; x < w; x += step_x) {
+ da_x0 = (OPJ_INT32)(l_image->x0 + x);
+ da_y0 = (OPJ_INT32)(l_image->y0 + y);
+ da_x1 = (OPJ_INT32)opj_uint_min(l_image->x1, l_image->x0 + x + 1);
+ da_y1 = (OPJ_INT32)opj_uint_min(l_image->y1, l_image->y0 + y + 1);
+ l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
+ NULL, NULL, NULL, NULL);
+ if (!l_sub_image) {
+ fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
+ da_x0, da_y0, da_x1, da_y1);
+ opj_image_destroy(l_sub_image);
+ opj_image_destroy(l_image);
+ return 1;
+ }
+
+ if (!check_consistency(l_image, l_sub_image)) {
+ fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
+ da_x0, da_y0, da_x1, da_y1);
+ opj_image_destroy(l_sub_image);
+ opj_image_destroy(l_image);
+ return 1;
+ }
+ opj_image_destroy(l_sub_image);
+
+ if (step_x > 1 || step_y > 1) {
+ if (step_x > 1) {
+ da_x0 = (OPJ_INT32)opj_uint_min(l_image->x1, (OPJ_UINT32)da_x0 + 1);
+ da_x1 = (OPJ_INT32)opj_uint_min(l_image->x1, (OPJ_UINT32)da_x1 + 1);
+ }
+ if (step_y > 1) {
+ da_y0 = (OPJ_INT32)opj_uint_min(l_image->y1, (OPJ_UINT32)da_y0 + 1);
+ da_y1 = (OPJ_INT32)opj_uint_min(l_image->y1, (OPJ_UINT32)da_y1 + 1);
+ }
+ l_sub_image = decode(quiet, input_file, da_x0, da_y0, da_x1, da_y1,
+ NULL, NULL, NULL, NULL);
+ if (!l_sub_image) {
+ fprintf(stderr, "decode failed for %d,%d,%d,%d\n",
+ da_x0, da_y0, da_x1, da_y1);
+ opj_image_destroy(l_sub_image);
+ opj_image_destroy(l_image);
+ return 1;
+ }
+
+ if (!check_consistency(l_image, l_sub_image)) {
+ fprintf(stderr, "Consistency checked failed for %d,%d,%d,%d\n",
+ da_x0, da_y0, da_x1, da_y1);
+ opj_image_destroy(l_sub_image);
+ opj_image_destroy(l_image);
+ return 1;
+ }
+ opj_image_destroy(l_sub_image);
+ }
+ }
+ }
+
+ opj_image_destroy(l_image);
+ return 0;
+}