001/* ***** BEGIN LICENSE BLOCK *****
002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003 *
004 * The contents of this file are subject to the Mozilla Public License Version
005 * 1.1 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 * http://www.mozilla.org/MPL/
008 *
009 * Software distributed under the License is distributed on an "AS IS" basis,
010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011 * for the specific language governing rights and limitations under the
012 * License.
013 *
014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in
015 * Java(TM), hosted at https://github.com/gunterze/dcm4che.
016 *
017 * The Initial Developer of the Original Code is
018 * Agfa Healthcare.
019 * Portions created by the Initial Developer are Copyright (C) 2013
020 * the Initial Developer. All Rights Reserved.
021 *
022 * Contributor(s):
023 * See @authors listed below
024 *
025 * Alternatively, the contents of this file may be used under the terms of
026 * either the GNU General Public License Version 2 or later (the "GPL"), or
027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
028 * in which case the provisions of the GPL or the LGPL are applicable instead
029 * of those above. If you wish to allow use of your version of this file only
030 * under the terms of either the GPL or the LGPL, and not to allow others to
031 * use your version of this file under the terms of the MPL, indicate your
032 * decision by deleting the provisions above and replace them with the notice
033 * and other provisions required by the GPL or the LGPL. If you do not delete
034 * the provisions above, a recipient may use your version of this file under
035 * the terms of any one of the MPL, the GPL or the LGPL.
036 *
037 * ***** END LICENSE BLOCK ***** */
038
039package org.dcm4che3.imageio.codec.jpeg;
040
041/**
042 * The JAI-ImageIO JPEG-LS CLibJPEGImageReader/CLibJPEGImageWriter contain a bug that makes them calculate non-default
043 * JPEG-LS coding parameters for images with more than 12 bits per pixel, resulting in two problems:
044 * <ol>
045 * <li>JPEG-LS streams created by CLibJPEGImageWriter are not compliant with the JPEG-LS specification and can
046 * therefore not be decoded using standard-compliant decoders. (Note: Some commercial decoders can automatically detect
047 * such faulty JPEG-LS streams and are able to decode them correctly, e.g. Agfa/Pegasus.)</li>
048 * <li>Reading a correct JPEG-LS stream using default coding parameters (i.e. not containing an LSE segment) with
049 * CLibJPEGImageReader will result in a corrupted image.</li>
050 * </ol>
051 * <p>
052 * This enum contains different options to use with a {@link PatchJPEGLSImageInputStream} or {@link
053 * PatchJPEGLSImageOutputStream} to both patch faulty JPEG-LS streams created by JAI-ImageIO to make them readable
054 * by standard-compliant decoders and to make correct JPEG-LS streams (created by other encoders) readable by
055 * JAI-ImageIO.
056 *
057 * @see <a href="http://www.dcm4che.org/jira/browse/DCMEE-1144">http://www.dcm4che.org/jira/browse/DCMEE-1144</a>
058 * @see <a href="http://dcm4che.org/jira/browse/DCMEEREQ-799">http://dcm4che.org/jira/browse/DCMEEREQ-799</a>
059 * @see <a href="https://java.net/jira/browse/JAI_IMAGEIO_CORE-183">https://java.net/jira/browse/JAI_IMAGEIO_CORE-183</a>
060 * @see <a href="http://charls.codeplex.com/discussions/230307">http://charls.codeplex.com/discussions/230307</a>
061 *
062 * @author Gunter Zeilinger <gunterze@gmail.com>
063 * @author Hermann Czedik-Eysenberg <hermann-agfa@czedik.net>
064 */
065public enum PatchJPEGLS {
066
067    /**
068     * Amend JPEG-LS Coding parameters actually used by JAI-ImageIO.
069     * <p>
070     * Used to patch faulty JPEG-LS streams created by JAI-ImageIO CLibImageWriter, so the resulting JPEG-LS
071     * stream can be decoded by JPEG-LS compliant decoders.
072     * <p>
073     * Warning: Patching a correct JPEG-LS (not created by JAI-ImageIO) with this option is likely to corrupt it (if it
074     * has more than 12 bits per pixel and uses default coding parameters, i.e. doesn't contain an LSE segment). Use
075     * JAI2ISO_IF_NO_APP_OR_COM to prevent this problem in some cases.
076     */
077    JAI2ISO,
078
079    /**
080     * Amend JPEG-LS Coding parameters actually used by JAI-ImageIO, but only if the stream does NOT contain APPn or
081     * COM segments and is therefore more likely to have been actually created by JAI-ImageIO.
082     * <p>
083     * This option can be used, if you are not 100% sure whether the stream has actually been created by JAI-ImageIO
084     * and you want to decrease the likeliness of corrupting a correct stream by incorrectly patching it.
085     * It will prevent patching streams of some correct encoders (e.g. Agfa/Pegasus) that add APPn or COM
086     * segments. But as some correct encoders (e.g. dcmtk in the current version 3.6.0) also do not create APPn or COM
087     * segments, this option might still patch a correct stream and thereby make it corrupt.
088     */
089    JAI2ISO_IF_NO_APP_OR_COM,
090
091    /**
092     * Amend default JPEG-LS Coding parameters (for streams that do not contain them yet).
093     * <p>
094     * Used to patch correct JPEG-LS streams, so they can be decompressed by the faulty JAI-ImageIO
095     * CLibImageReader. The resulting stream will still be correct JPEG-LS and can also be decoded by other decoders.
096     * <p>
097     * Warning: Patching faulty JPEG-LS streams created by JAI-ImageIO with this option will make them corrupt (i.e.
098     * unreadable by both JAI-ImageIO and standard-compliant decoders).
099     */
100    ISO2JAI,
101
102    /**
103     * Amend default JPEG-LS Coding parameters (for streams that do not contain them yet), but only if the stream
104     * contains APPn or COM segments - so it was certainly not created by JAI-ImageIO.
105     * <p>
106     * This option can be used to prevent adding those default parameters to faulty streams created by JAI-ImageIO
107     * which would make them unreadable for both JAI-ImageIO and standard-compliant decoders.
108     * On the other hand some correct encoders (e.g. dcmtk 3.6.0) also do not add APPn or COM segments and will
109     * therefore not be patched, which prevents them from getting decompressed correctly with JAI-ImageIO, if this
110     * option is used. (Use the ISO2JAI option for reading such streams with JAI-ImageIO.)
111     */
112    ISO2JAI_IF_APP_OR_COM;
113
114    public JPEGLSCodingParam createJPEGLSCodingParam(byte[] jpeg) {
115        JPEGHeader jpegHeader = new JPEGHeader(jpeg, JPEG.SOS);
116        int soiOff = jpegHeader.offsetOf(JPEG.SOI);
117        int sof55Off = jpegHeader.offsetOf(JPEG.SOF55);
118        int lseOff = jpegHeader.offsetOf(JPEG.LSE);
119        int sosOff = jpegHeader.offsetOf(JPEG.SOS);
120
121        if (soiOff == -1)
122            return null; // no JPEG
123
124        if (sof55Off == -1)
125            return null; // no JPEG-LS
126
127        if (lseOff != -1)
128            return null; // already patched
129
130        if (sosOff == -1)
131            return null;
132
133        // additional markers (APPn or COM) besides SOI, SOF55 and SOS
134        boolean additionalMarkers = jpegHeader.numberOfMarkers() > 3;
135
136        if (this == ISO2JAI_IF_APP_OR_COM && !additionalMarkers)
137            return null;
138
139        if (this == JAI2ISO_IF_NO_APP_OR_COM && additionalMarkers)
140            return null;
141
142        int p = jpeg[sof55Off+3] & 255;
143        if (p <= 12)
144            return null; // not more than 12 bits per pixel
145
146        JPEGLSCodingParam param = this == JAI2ISO
147                ? JPEGLSCodingParam.getJAIJPEGLSCodingParam(p)
148                : JPEGLSCodingParam.getDefaultJPEGLSCodingParam(p,
149                        jpeg[sosOff+6] & 255);
150        param.setOffset(sosOff-1);
151        return param;
152    }
153}