uclouvain / openjpeg

Official repository of the OpenJPEG project
Other
954 stars 456 forks source link

JP2_RES proposition for implementation #378

Open gcode-importer opened 9 years ago

gcode-importer commented 9 years ago

Originally reported on Google Code with ID 378

I attached a file containing the modification I have done for getting/setting the resolution.

I've got another stupid question:
Can anybody explain me about the reason it is like that:
/**
 * Supported image color spaces
*/
typedef enum COLOR_SPACE {
    OPJ_CLRSPC_UNKNOWN = -1,    /**< not supported by the library */
    OPJ_CLRSPC_UNSPECIFIED = 0, /**< not specified in the codestream */
    OPJ_CLRSPC_SRGB = 1,        /**< sRGB */
    OPJ_CLRSPC_GRAY = 2,        /**< grayscale */
    OPJ_CLRSPC_SYCC = 3,        /**< YUV */
    OPJ_CLRSPC_EYCC = 4,        /**< e-YCC */
    OPJ_CLRSPC_CMYK = 5         /**< CMYK */
} OPJ_COLOR_SPACE;

instead of instead of using the values defined in the norme:

typedef enum COLOR_SPACE {
    OPJ_CLRSPC_UNKNOWN = -1,    /**< not supported by the library */
    OPJ_CLRSPC_UNSPECIFIED = 0, /**< not specified in the codestream */
    OPJ_CLRSPC_CMYK = 12,
    OPJ_CLRSPC_YCCK = 13,
    OPJ_CLRSPC_LAB = 14,  
    OPJ_CLRSPC_SRGB = 16,       /**< sRGB */
    OPJ_CLRSPC_GRAY = 17,       /**< grayscale */
    OPJ_CLRSPC_SYCC = 18            /**< YUV */
    OPJ_CLRSPC_EYCC = 24,        /**< e-YCC */
} OPJ_COLOR_SPACE;

Thanks .

Mika

Reported by leguilc on 2014-08-20 15:25:33


gcode-importer commented 9 years ago
The norm ISO/IEC 15444-1 does define values for ENUMCS.

winfried

Reported by szukw000 on 2014-08-25 16:07:19

gcode-importer commented 9 years ago

Reported by mayeut on 2014-10-09 18:11:01

sebras commented 8 years ago

I'm not sure if writing +1, 👍 or just cheering you guys on is appropriate, but I'd like to see this patch (or some version of it) be added to master. Having the possiblity to determine the resolution of an image would be really nice. :) If I can help you in any way, let me know.

jerem commented 6 years ago

Here is a copy the original patch:

diff --git a/src/lib/openjp2/jp2.c b/src/lib/openjp2/jp2.c
index 5c88c4d..f3d49c0 100644
--- a/src/lib/openjp2/jp2.c
+++ b/src/lib/openjp2/jp2.c
@@ -118,6 +118,16 @@ static void opj_jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color);
 */
 static OPJ_BYTE * opj_jp2_write_colr(   opj_jp2_t *jp2,
                                        OPJ_UINT32 * p_nb_bytes_written );
+/**
+ * Writes the Colour Specification box.
+ *
+ * @param jp2                  jpeg2000 file codec.
+ * @param p_nb_bytes_written   pointer to store the nb of bytes written by the function.
+ *
+ * @return the data being copied.
+*/
+static OPJ_BYTE * opj_jp2_write_res(   opj_jp2_t *jp2,
+                                       OPJ_UINT32 * p_nb_bytes_written );

 /**
  * Writes a FTYP box - File type box
@@ -294,6 +304,21 @@ static OPJ_BOOL opj_jp2_read_colr(  opj_jp2_t *jp2,
                                     OPJ_UINT32 p_colr_header_size,
                                     opj_event_mgr_t * p_manager );

+/**
+ * Reads the Color Specification box.
+ *
+ * @param  p_colr_header_data          pointer to actual data (already read from file)
+ * @param  jp2                         the jpeg2000 file codec.
+ * @param  p_colr_header_size          the size of the color header
+ * @param  p_manager                   the user event manager.
+ *
+ * @return true if the bpc header is valid, fale else.
+*/
+static OPJ_BOOL opj_jp2_read_res(  opj_jp2_t *jp2,
+                                   OPJ_BYTE * p_colr_header_data,
+                                   OPJ_UINT32 p_colr_header_size,
+                                   opj_event_mgr_t * p_manager );
+
 /*@}*/

 /*@}*/
@@ -397,6 +422,7 @@ const opj_jp2_header_handler_t jp2_img_header [] =
 {
    {JP2_IHDR,opj_jp2_read_ihdr},
    {JP2_COLR,opj_jp2_read_colr},
+   {JP2_RES,opj_jp2_read_res},
    {JP2_BPCC,opj_jp2_read_bpcc},
    {JP2_PCLR,opj_jp2_read_pclr},
    {JP2_CMAP,opj_jp2_read_cmap},
@@ -749,6 +775,106 @@ OPJ_BYTE * opj_jp2_write_colr(  opj_jp2_t *jp2,
    return l_colr_data;
 }

+void opj_res (OPJ_FLOAT64 res, OPJ_UINT32 * rcn, OPJ_UINT32 *rcd) {
+    const int NUMFRACS = 30;
+    int i;
+
+    OPJ_UINT32 numerator [NUMFRACS];
+    OPJ_UINT32 denominator [NUMFRACS];
+    
+    OPJ_FLOAT64 d=0, d2=0, d3, d4 = -1;
+    OPJ_UINT32   maxNumerator, L2;
+    (*rcn) = (int)(res / 100);
+    (*rcd) = 1;
+    d = d2 = (res / 100);
+    
+    maxNumerator = 0x0ffff;
+
+    numerator[0]=0; denominator[0]=1;
+    numerator[1]=1; denominator[1]=0;
+
+    for(i=2; i<NUMFRACS; ++i)
+    {
+      L2 = (OPJ_UINT32)(d2 + 0.5);
+      numerator[i]= L2 * numerator[i-1] + numerator[i-2];
+      denominator[i]= L2 *denominator[i-1] + denominator[i-2];
+      
+      d3 = ((OPJ_FLOAT64)(numerator[i])) / ((OPJ_FLOAT64)(denominator[i]));
+      
+      if(d3==d4) break; 
+      
+      if(abs (numerator[i]) > maxNumerator) break; 
+
+      (*rcn) = abs (numerator[i]);
+      (*rcd) = abs (denominator[i]);
+
+      if(d3==d) break; 
+
+      d4=d3;
+      
+      d2 = 1/(d2-L2);
+    }
+}
+
+OPJ_BYTE * opj_jp2_write_res(  opj_jp2_t *jp2,
+                              OPJ_UINT32 * p_nb_bytes_written)
+{
+   OPJ_UINT32 l_res_size = 26, l_resc_size = 18;
+   OPJ_BYTE * l_res_data, * l_current_res_ptr;
+  
+    OPJ_UINT32 rcn, rcd, rce = 2;
+   /* preconditions */
+   assert(jp2 != 00);
+   assert(p_nb_bytes_written != 00);
+    
+   l_res_data = (OPJ_BYTE *) opj_malloc(l_res_size);
+   if (l_res_data == 00) {
+       return 00;
+   }
+
+   memset(l_res_data,0,l_res_size);
+   
+   l_current_res_ptr = l_res_data;
+
+   opj_write_bytes(l_current_res_ptr,l_res_size,4);                /* write box size */
+   l_current_res_ptr += 4;
+   
+   opj_write_bytes(l_current_res_ptr,JP2_RES,4);                   /* RES */
+   l_current_res_ptr += 4;
+
+   opj_write_bytes(l_current_res_ptr,l_resc_size,4);                   /* BPCC */
+   l_current_res_ptr += 4;
+    
+   opj_write_bytes(l_current_res_ptr,JP2_RESC,4);                  /* BPCC */
+   l_current_res_ptr += 4;
+
+    opj_res (jp2->resdv, &rcn, &rcd);
+    
+   opj_write_bytes(l_current_res_ptr, rcn, 2);             /* VRcN */
+   l_current_res_ptr += 2;
+
+   opj_write_bytes(l_current_res_ptr, rcn, 2);             /* VRcD */
+   l_current_res_ptr += 2;
+    
+    opj_res (jp2->resdh, &rcn, &rcd);
+
+   opj_write_bytes(l_current_res_ptr, rcn, 2);             /* HRcN */
+   l_current_res_ptr += 2;
+
+   opj_write_bytes(l_current_res_ptr, rcn, 2);             /* HRcD */
+   l_current_res_ptr += 2;
+
+   opj_write_bytes(l_current_res_ptr, rce, 1);             /* VRcE */
+   l_current_res_ptr += 1;
+
+   opj_write_bytes(l_current_res_ptr, rce, 1);             /* HRcE */
+   l_current_res_ptr += 1;
+    
+   *p_nb_bytes_written = l_res_size;
+   
+   return l_res_data;
+}
+
 void opj_jp2_free_pclr(opj_jp2_color_t *color)
 {
     opj_free(color->jp2_pclr->channel_sign);
@@ -1282,6 +1408,57 @@ OPJ_BOOL opj_jp2_read_colr( opj_jp2_t *jp2,
     return OPJ_TRUE;
 }

+OPJ_BOOL opj_jp2_read_res( opj_jp2_t *jp2,
+                           OPJ_BYTE * p_res_header_data,
+                           OPJ_UINT32 p_res_header_size,
+                           opj_event_mgr_t * p_manager) 
+{
+  OPJ_UINT32 size, type;   
+  OPJ_UINT32 vrcn, vrcd, hrcn, hrcd, vrce, hrce;
+  
+  /* preconditions */
+  assert(jp2 != 00);
+  assert(p_res_header_data != 00);
+  assert(p_manager != 00);
+        
+  while (p_res_header_size >= 18) {
+    opj_read_bytes(p_res_header_data,&size ,4);
+    p_res_header_data += 4;
+    
+    opj_read_bytes(p_res_header_data,&type ,4);
+    p_res_header_data += 4;
+    
+    opj_read_bytes(p_res_header_data,&vrcn,2);
+    p_res_header_data += 2;
+    
+    opj_read_bytes(p_res_header_data,&vrcd,2);
+    p_res_header_data += 2;
+    
+    opj_read_bytes(p_res_header_data,&hrcn,2);
+    p_res_header_data += 2;
+    
+    opj_read_bytes(p_res_header_data,&hrcd,2);
+    p_res_header_data += 2;
+    
+    opj_read_bytes(p_res_header_data,&vrce,1);
+    ++p_res_header_data;
+    
+    opj_read_bytes(p_res_header_data,&hrce,1);
+    ++p_res_header_data;
+    
+    jp2->resdh = (OPJ_FLOAT64)(hrcn) / (OPJ_FLOAT64)(hrcd) * pow(10, hrce);
+    jp2->resdv = (OPJ_FLOAT64)(vrcn) / (OPJ_FLOAT64)(vrcd) * pow(10, vrce);
+    
+    if ( JP2_RESD == type)
+      return OPJ_TRUE;
+      
+    p_res_header_size -= size;
+  }
+    
+  return OPJ_TRUE;
+}/* jp2_read_res() */
+
+
 OPJ_BOOL opj_jp2_decode(opj_jp2_t *jp2,
                         opj_stream_private_t *p_stream,
                         opj_image_t* p_image,
@@ -1341,7 +1518,7 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2,
                             opj_event_mgr_t * p_manager
                             )
 {
-   opj_jp2_img_header_writer_handler_t l_writers [3];
+   opj_jp2_img_header_writer_handler_t l_writers [4];
    opj_jp2_img_header_writer_handler_t * l_current_writer;

    OPJ_INT32 i, l_nb_pass;
@@ -1359,16 +1536,19 @@ OPJ_BOOL opj_jp2_write_jp2h(opj_jp2_t *jp2,

    memset(l_writers,0,sizeof(l_writers));

+
    if (jp2->bpc == 255) {
-       l_nb_pass = 3;
+       l_nb_pass = 4;
        l_writers[0].handler = opj_jp2_write_ihdr;
        l_writers[1].handler = opj_jp2_write_bpcc;
        l_writers[2].handler = opj_jp2_write_colr;
+       l_writers[3].handler = opj_jp2_write_res;
    }
    else {
-       l_nb_pass = 2;
+       l_nb_pass = 3;
        l_writers[0].handler = opj_jp2_write_ihdr;
        l_writers[1].handler = opj_jp2_write_colr;
+        l_writers[2].handler = opj_jp2_write_res;
    }

    /* write box header */
diff --git a/src/lib/openjp2/jp2.h b/src/lib/openjp2/jp2.h
index c11d2f3..6b43008 100644
--- a/src/lib/openjp2/jp2.h
+++ b/src/lib/openjp2/jp2.h
@@ -60,6 +60,9 @@
 #define     JP2_BPCC 0x62706363    /**< Bits per component box */
 #define     JP2_JP2  0x6a703220    /**< File type fields */

+#define     JP2_RES  0x72657320    /**< Resolution box (super-box) */
+#define     JP2_RESC 0x72657363    /**< File type fields */
+#define     JP2_RESD 0x72657364    /**< File type fields */
 /* For the future */
 /* #define JP2_RES 0x72657320 */  /**< Resolution box (super-box) */
 /* #define JP2_JP2I 0x6a703269 */  /**< Intellectual property box */
@@ -181,6 +184,8 @@ typedef struct opj_jp2
   OPJ_UINT32 numcl;
   OPJ_UINT32 *cl;
   opj_jp2_comps_t *comps;
+  OPJ_FLOAT64 resdh;
+  OPJ_FLOAT64 resdv;
   /* FIXME: The following two variables are used to save offset
     as we write out a JP2 file to disk. This mecanism is not flexible
     as codec writers will need to extand those fields as new part
diff --git a/src/lib/openjp2/openjpeg.h b/src/lib/openjp2/openjpeg.h
index e4b410e..840e0e8 100644
--- a/src/lib/openjp2/openjpeg.h
+++ b/src/lib/openjp2/openjpeg.h
@@ -701,6 +701,10 @@ typedef struct opj_image {
    OPJ_BYTE *icc_profile_buf;
    /** size of ICC profile */
    OPJ_UINT32 icc_profile_len;
+    /** resolution display vertical */
+    OPJ_FLOAT64 resdv;
+    /** resolution display horizontal */
+    OPJ_FLOAT64 resdh;
 } opj_image_t;
jbaiter commented 5 years ago

This is also included in the grok fork. What's the stance on backporting features from grok?

I'd really like so see support for JP2_RES and JP2_COLR in the mainline library. Both features are implemented in grok, and from what I can tell backporting them shouldn't be all too difficult.

If it's okay, I'd love to give this a try.

rouault commented 5 years ago

If it's okay, I'd love to give this a try.

This isn't OK from a license point of view. Grok uses a more restrictive license, and its code cannot legally be backported to openjpeg.

jbaiter commented 5 years ago

Thanks for getting back so quickly, I wasn't aware of that!

jbaiter commented 5 years ago

Basing a PR on @leguilc's code would be fine, though, right? Given that he submitted his patch for the openjpeg project, can we safely assume that the copyright situation is clear?

rouault commented 5 years ago

can we safely assume that the copyright situation is clear?

yes

leguilc commented 5 years ago

How time flies!! I completely forgotten about writing this code/patch ....