/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is part of dcm4che, an implementation of DICOM(TM) in
* Java(TM), hosted at https://github.com/gunterze/dcm4che.
*
* The Initial Developer of the Original Code is
* Agfa Healthcare.
* Portions created by the Initial Developer are Copyright (C) 2013
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* See @authors listed below
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.dcm4che3.imageio.codec.jpeg;
/**
* The JAI-ImageIO JPEG-LS CLibJPEGImageReader/CLibJPEGImageWriter contain a bug that makes them calculate non-default
* JPEG-LS coding parameters for images with more than 12 bits per pixel, resulting in two problems:
* <ol>
* <li>JPEG-LS streams created by CLibJPEGImageWriter are not compliant with the JPEG-LS specification and can
* therefore not be decoded using standard-compliant decoders. (Note: Some commercial decoders can automatically detect
* such faulty JPEG-LS streams and are able to decode them correctly, e.g. Agfa/Pegasus.)</li>
* <li>Reading a correct JPEG-LS stream using default coding parameters (i.e. not containing an LSE segment) with
* CLibJPEGImageReader will result in a corrupted image.</li>
* </ol>
* <p>
* This enum contains different options to use with a {@link PatchJPEGLSImageInputStream} or {@link
* PatchJPEGLSImageOutputStream} to both patch faulty JPEG-LS streams created by JAI-ImageIO to make them readable
* by standard-compliant decoders and to make correct JPEG-LS streams (created by other encoders) readable by
* JAI-ImageIO.
*
* @see <a href="http://www.dcm4che.org/jira/browse/DCMEE-1144">http://www.dcm4che.org/jira/browse/DCMEE-1144</a>
* @see <a href="http://dcm4che.org/jira/browse/DCMEEREQ-799">http://dcm4che.org/jira/browse/DCMEEREQ-799</a>
* @see <a href="https://java.net/jira/browse/JAI_IMAGEIO_CORE-183">https://java.net/jira/browse/JAI_IMAGEIO_CORE-183</a>
* @see <a href="http://charls.codeplex.com/discussions/230307">http://charls.codeplex.com/discussions/230307</a>
*
* @author Gunter Zeilinger <gunterze@gmail.com>
* @author Hermann Czedik-Eysenberg <hermann-agfa@czedik.net>
*/
public enum PatchJPEGLS {
/**
* Amend JPEG-LS Coding parameters actually used by JAI-ImageIO.
* <p>
* Used to patch faulty JPEG-LS streams created by JAI-ImageIO CLibImageWriter, so the resulting JPEG-LS
* stream can be decoded by JPEG-LS compliant decoders.
* <p>
* Warning: Patching a correct JPEG-LS (not created by JAI-ImageIO) with this option is likely to corrupt it (if it
* has more than 12 bits per pixel and uses default coding parameters, i.e. doesn't contain an LSE segment). Use
* JAI2ISO_IF_NO_APP_OR_COM to prevent this problem in some cases.
*/
JAI2ISO,
/**
* Amend JPEG-LS Coding parameters actually used by JAI-ImageIO, but only if the stream does NOT contain APPn or
* COM segments and is therefore more likely to have been actually created by JAI-ImageIO.
* <p>
* This option can be used, if you are not 100% sure whether the stream has actually been created by JAI-ImageIO
* and you want to decrease the likeliness of corrupting a correct stream by incorrectly patching it.
* It will prevent patching streams of some correct encoders (e.g. Agfa/Pegasus) that add APPn or COM
* segments. But as some correct encoders (e.g. dcmtk in the current version 3.6.0) also do not create APPn or COM
* segments, this option might still patch a correct stream and thereby make it corrupt.
*/
JAI2ISO_IF_NO_APP_OR_COM,
/**
* Amend default JPEG-LS Coding parameters (for streams that do not contain them yet).
* <p>
* Used to patch correct JPEG-LS streams, so they can be decompressed by the faulty JAI-ImageIO
* CLibImageReader. The resulting stream will still be correct JPEG-LS and can also be decoded by other decoders.
* <p>
* Warning: Patching faulty JPEG-LS streams created by JAI-ImageIO with this option will make them corrupt (i.e.
* unreadable by both JAI-ImageIO and standard-compliant decoders).
*/
ISO2JAI,
/**
* Amend default JPEG-LS Coding parameters (for streams that do not contain them yet), but only if the stream
* contains APPn or COM segments - so it was certainly not created by JAI-ImageIO.
* <p>
* This option can be used to prevent adding those default parameters to faulty streams created by JAI-ImageIO
* which would make them unreadable for both JAI-ImageIO and standard-compliant decoders.
* On the other hand some correct encoders (e.g. dcmtk 3.6.0) also do not add APPn or COM segments and will
* therefore not be patched, which prevents them from getting decompressed correctly with JAI-ImageIO, if this
* option is used. (Use the ISO2JAI option for reading such streams with JAI-ImageIO.)
*/
ISO2JAI_IF_APP_OR_COM;
public JPEGLSCodingParam createJPEGLSCodingParam(byte[] jpeg) {
JPEGHeader jpegHeader = new JPEGHeader(jpeg, JPEG.SOS);
int soiOff = jpegHeader.offsetOf(JPEG.SOI);
int sof55Off = jpegHeader.offsetOf(JPEG.SOF55);
int lseOff = jpegHeader.offsetOf(JPEG.LSE);
int sosOff = jpegHeader.offsetOf(JPEG.SOS);
if (soiOff == -1)
return null; // no JPEG
if (sof55Off == -1)
return null; // no JPEG-LS
if (lseOff != -1)
return null; // already patched
if (sosOff == -1)
return null;
// additional markers (APPn or COM) besides SOI, SOF55 and SOS
boolean additionalMarkers = jpegHeader.numberOfMarkers() > 3;
if (this == ISO2JAI_IF_APP_OR_COM && !additionalMarkers)
return null;
if (this == JAI2ISO_IF_NO_APP_OR_COM && additionalMarkers)
return null;
int p = jpeg[sof55Off+3] & 255;
if (p <= 12)
return null; // not more than 12 bits per pixel
JPEGLSCodingParam param = this == JAI2ISO
? JPEGLSCodingParam.getJAIJPEGLSCodingParam(p)
: JPEGLSCodingParam.getDefaultJPEGLSCodingParam(p,
jpeg[sosOff+6] & 255);
param.setOffset(sosOff-1);
return param;
}
}