Menu

#378 jp2: impossible to create lossless jpeg-2000

v1.0_(example)
closed-fixed
None
5
2016-04-04
2016-04-01
No

Hi,
jasper creates lossless jp2, gm doesn't:

jasper --input gm-snap.jpg --output gm-snap.jp2
gm compare -metric PSNR gm-snap.jpg gm-snap.jp2

Image Difference (PeakSignalToNoiseRatio):
           PSNR
          ======
     Red: inf   
   Green: inf   
    Blue: inf   
   Total: inf   

vs.

gm convert gm-snap.jpg gm-snap.jp2
gm compare -metric PSNR gm-snap.jpg gm-snap.jp2

Image Difference (PeakSignalToNoiseRatio):
           PSNR
          ======
     Red: 43.01 
   Green: 44.13 
    Blue: 42.30 
   Total: 43.08 

Both, jasper and gm convert are supposed to create lossless jp2 by default.
Best regards!

Discussion

  • Bob Friesenhahn

    Bob Friesenhahn - 2016-04-01

    On Fri, 1 Apr 2016, aph1xeiz1ahth aph1xeiz1ahth wrote:

    Both, jasper and gm convert are supposed to create lossless jp2 by default.

    That is not actually the case. GraphicsMagick attempts to produce a
    jp2 file with roughly similar levels of error as IJG JPEG does at
    the default quality level 75.

    Please see the GraphicsMagick documentation regarding -define, and in
    particular '-define jp2:rate=<value>'. Specifying '-define
    jp2:rate=1.0' is supposed to trigger lossless compression.</value>

    Without using the '-define jp2:rate=<value>', the -quality value is
    used to estimate a compression ratio which might produce results
    roughly equivalent to IJG JPEG (based on my own testing).</value>

    Bob

     
  • aph1xeiz1ahth aph1xeiz1ahth

    Hi Bob,
    thanks for your reply. Sorry for mixing things up, but anyway:

    gm convert gm-snap.jpg -define jp2:rate=1.0 gm-snap.jp2
    gm compare -metric PSNR gm-snap.jpg gm-snap.jp2
    
    Image Difference (PeakSignalToNoiseRatio):
               PSNR
              ======
         Red: 105.41
       Green: inf   
        Blue: 105.41
       Total: 107.17
    

    The resulting JP2 image is still just near-lossless.
    Best regards!

     

    Last edit: aph1xeiz1ahth aph1xeiz1ahth 2016-04-01
  • aph1xeiz1ahth aph1xeiz1ahth

    It seems to be a jasper bug: Once you pass a rate to jasper, it becomes lossy:

    jasper --input gm-snap.jpg --output-option rate=1.0 --output gm-snap.jp2
    gm compare -metric PSNR gm-snap.jpg gm-snap.jp2
    
    Image Difference (PeakSignalToNoiseRatio):
               PSNR
              ======
         Red: 105.41
       Green: inf   
        Blue: 105.41
       Total: 107.17
    

    Is there any possibility to prevent that gm is passing the rate option to jasper?

     
    • Bob Friesenhahn

      Bob Friesenhahn - 2016-04-01

      On Fri, 1 Apr 2016, aph1xeiz1ahth aph1xeiz1ahth wrote:

      It seems to be a jasper bug: Once you pass a rate to jasper, it becomes lossy:

      Is there any possibility to prevent that gm is passing the rate option to jasper?

      The GraphicsMagick source code is freely available so anything is
      possible by editing the source code and recompiling.

      Something which is not documented is that all of the Jasper encoding
      option string values (from the Jasper documentation) may be passed to
      the encoder in the same way as 'rate'. For example 'mode' may be
      passed.

      I am at the day job at the moment but it looks like adding '-quality
      100' should block any addition of 'rate' to the options.

      Bob

       
  • aph1xeiz1ahth aph1xeiz1ahth

    Thanks again for the hint. Passing the other jasper options works well, but the gm -quality 100 gives the same results as -define jp2:rate=1.0

    I build my personal gm version without any rate support by compiling jasper with the rate setting commented out and compiling gm against it:

    diff -du src/libjasper/jpc/jpc_enc.c src/libjasper/jpc/jpc_enc.c.bak 
    --- src/libjasper/jpc/jpc_enc.c 2016-04-01 21:07:46.809979366 +0200
    +++ src/libjasper/jpc/jpc_enc.c.bak 2016-04-01 21:31:08.233938936 +0200
    @@ -531,11 +531,11 @@
                cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp));
                break;
            case OPT_RATE:
    -       /*  if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
    +           if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
                  &cp->totalsize)) {
                    jas_eprintf("ignoring bad rate specifier %s\n",
                      jas_tvparser_getval(tvp));
    -           } */
    +           }
                break;
    
    export LDFLAGS="-L/tmp/jasper-1.900.1/src/libjasper"
    ./configure
    make
    
    ./utilities/gm convert gm-snap.jpg gm-snap.jp2
    gm compare -metric PSNR gm-snap.jpg gm-snap.jp2
    
    Image Difference (PeakSignalToNoiseRatio):
               PSNR
              ======
         Red: inf   
       Green: inf   
        Blue: inf   
       Total: inf   
    

    Thanks for your help. This workaround will work for me - as this is a jasper bug, you might want to close this ticket as wont-fix.
    Best regards!

     
  • aph1xeiz1ahth aph1xeiz1ahth

    According do the author of Jasper, it is working as intended - so GM needs to change the way how it calls Jasper.

    On 04.04.2016 15:39, Michael Adams wrote:

    If you specify a rate, you are telling the coder not to do lossless coding.
    So, a rate of 1 should not result in lossless coding.
    This is the design intent.
    If lossless coding is desired, do not specify a rate.

    On 04.04.2016 16:07, Michael Adams wrote:

    A rate of infinity corresponds to lossless compression, to the best of
    my recollection (and infinity cannot be specified on the command line).
    If you use anything other than infinity, the coder may assume that you do
    not want lossless compression. Also, you might want to ensure that real
    mode is not being used. Lossless compression can only be achieved with
    int mode (i.e., when using reversible integer-to-integer transforms).

    Yes, you can post both of my responses if you like.
    Lossless compression does work in JasPer.
    If you are unable to achieve lossless coding, then I suspect that you are
    using the coder incorrectly.

    --Michael

     
  • aph1xeiz1ahth aph1xeiz1ahth

    Possible fix: The automatic quality calculation did set the rate option in case the user didn't. Now it will only set rate option if quality is <99.5, so if you specify -quality 100, you will get a lossless JP2.

    --- coders/jp2.c.bak    2016-04-04 17:30:07.671083372 +0200
    +++ coders/jp2.c    2016-04-04 17:39:08.183067779 +0200
    @@ -1155,11 +1155,11 @@
                 number_components;
               target_size=(current_size*rate)+header_size;
               rate=target_size/current_size;
    -        }
    -      FormatString(option_keyval,"%s=%g ","rate",rate);
    -      ConcatenateString(&options,option_keyval);
    -      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    -        "Compression rate: %g (%3.2f:1)",rate,1.0/rate);
    +          FormatString(option_keyval,"%s=%g ","rate",rate);
    +          ConcatenateString(&options,option_keyval);
    +          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    +            "Compression rate: %g (%3.2f:1)",rate,1.0/rate);
    +   }
         }
       if (options)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    
     
  • Bob Friesenhahn

    Bob Friesenhahn - 2016-04-04
    • status: open --> closed-fixed
    • assigned_to: Bob Friesenhahn
     
  • Bob Friesenhahn

    Bob Friesenhahn - 2016-04-04

    This problem is fixed by Mercurial changeset 14776:5017a9085264. Using '-quality 100' or '-define jp2:rate=1.0' now results in lossless compression.

     
  • aph1xeiz1ahth aph1xeiz1ahth

    It works, thank you Bob! :-)

     

Log in to post a comment.

MongoDB Logo MongoDB