mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 20:45:29 -04:00
#182 Moved lossless support classes to main package for better encapsulation, sorted out license issues.
This commit is contained in:
parent
673f3e5b53
commit
7d35400595
@ -1,4 +1,6 @@
|
|||||||
Copyright (c) 2013, Harald Kuhr
|
Copyright (c) 2016, Harald Kuhr
|
||||||
|
Copyright (C) 2015, Michael Martinez (JPEG Lossless decoder)
|
||||||
|
Copyright (C) 2004, Helmut Dersch (Java JPEG decoder)
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -40,17 +40,17 @@ import java.io.IOException;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: AdobeDCTSegment.java,v 1.0 23.04.12 16:55 haraldk Exp$
|
* @version $Id: AdobeDCTSegment.java,v 1.0 23.04.12 16:55 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class AdobeDCT extends AppSegment {
|
final class AdobeDCT extends Application {
|
||||||
public static final int Unknown = 0;
|
static final int Unknown = 0;
|
||||||
public static final int YCC = 1;
|
static final int YCC = 1;
|
||||||
public static final int YCCK = 2;
|
static final int YCCK = 2;
|
||||||
|
|
||||||
final int version;
|
final int version;
|
||||||
final int flags0;
|
final int flags0;
|
||||||
final int flags1;
|
final int flags1;
|
||||||
final int transform;
|
final int transform;
|
||||||
|
|
||||||
AdobeDCT(int version, int flags0, int flags1, int transform) {
|
private AdobeDCT(int version, int flags0, int flags1, int transform) {
|
||||||
super(JPEG.APP14, "Adobe", new byte[]{'A', 'd', 'o', 'b', 'e', 0, (byte) version, (byte) (flags0 >> 8), (byte) (flags0 & 0xff), (byte) (flags1 >> 8), (byte) (flags1 & 0xff), (byte) transform});
|
super(JPEG.APP14, "Adobe", new byte[]{'A', 'd', 'o', 'b', 'e', 0, (byte) version, (byte) (flags0 >> 8), (byte) (flags0 & 0xff), (byte) (flags1 >> 8), (byte) (flags1 & 0xff), (byte) transform});
|
||||||
|
|
||||||
this.version = version; // 100 or 101
|
this.version = version; // 100 or 101
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
|
||||||
import com.twelvemonkeys.lang.Validate;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.DataInput;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AppSegment.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: harald.kuhr$
|
|
||||||
* @version $Id: AppSegment.java,v 1.0 22/08/16 harald.kuhr Exp$
|
|
||||||
*/
|
|
||||||
class AppSegment extends Segment {
|
|
||||||
|
|
||||||
final String identifier;
|
|
||||||
final byte[] data;
|
|
||||||
|
|
||||||
AppSegment(int marker, final String identifier, final byte[] data) {
|
|
||||||
super(marker);
|
|
||||||
|
|
||||||
this.identifier = Validate.notEmpty(identifier, "identifier");
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AppSegment(int marker, final String identifier) {
|
|
||||||
this(marker, identifier, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream data() {
|
|
||||||
int offset = identifier.length() + 1;
|
|
||||||
return new ByteArrayInputStream(data, offset, data.length - offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AppSegment read(final int marker, final String identifier, final DataInput data, final int length) throws IOException {
|
|
||||||
switch (marker) {
|
|
||||||
case JPEG.APP0:
|
|
||||||
// JFIF
|
|
||||||
if ("JFIF".equals(identifier)) {
|
|
||||||
return JFIF.read(data, length);
|
|
||||||
}
|
|
||||||
case JPEG.APP1:
|
|
||||||
// JFXX
|
|
||||||
if ("JFXX".equals(identifier)) {
|
|
||||||
return JFXX.read(data, length);
|
|
||||||
}
|
|
||||||
// TODO: Exif?
|
|
||||||
case JPEG.APP2:
|
|
||||||
// ICC_PROFILE
|
|
||||||
if ("ICC_PROFILE".equals(identifier)) {
|
|
||||||
return ICCProfile.read(data, length);
|
|
||||||
}
|
|
||||||
case JPEG.APP14:
|
|
||||||
// Adobe
|
|
||||||
if ("Adobe".equals(identifier)) {
|
|
||||||
return AdobeDCT.read(data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Generic APPn segment
|
|
||||||
byte[] bytes = new byte[length - 2];
|
|
||||||
data.readFully(bytes);
|
|
||||||
return new AppSegment(marker, identifier, bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: harald.kuhr$
|
||||||
|
* @version $Id: Application.java,v 1.0 22/08/16 harald.kuhr Exp$
|
||||||
|
*/
|
||||||
|
class Application extends Segment {
|
||||||
|
|
||||||
|
final String identifier;
|
||||||
|
final byte[] data;
|
||||||
|
|
||||||
|
Application(int marker, final String identifier, final byte[] data) {
|
||||||
|
super(marker);
|
||||||
|
|
||||||
|
this.identifier = Validate.notEmpty(identifier, "identifier");
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream data() {
|
||||||
|
int offset = identifier.length() + 1;
|
||||||
|
return new ByteArrayInputStream(data, offset, data.length - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "APP" + (marker & 0x0f) + "/" + identifier + "[length: " + data.length + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Application read(final int marker, final String identifier, final DataInput data, final int length) throws IOException {
|
||||||
|
switch (marker) {
|
||||||
|
case JPEG.APP0:
|
||||||
|
// JFIF
|
||||||
|
if ("JFIF".equals(identifier)) {
|
||||||
|
return JFIF.read(data, length);
|
||||||
|
}
|
||||||
|
case JPEG.APP1:
|
||||||
|
// JFXX
|
||||||
|
if ("JFXX".equals(identifier)) {
|
||||||
|
return JFXX.read(data, length);
|
||||||
|
}
|
||||||
|
// TODO: Exif?
|
||||||
|
case JPEG.APP2:
|
||||||
|
// ICC_PROFILE
|
||||||
|
if ("ICC_PROFILE".equals(identifier)) {
|
||||||
|
return ICCProfile.read(data, length);
|
||||||
|
}
|
||||||
|
case JPEG.APP14:
|
||||||
|
// Adobe
|
||||||
|
if ("Adobe".equals(identifier)) {
|
||||||
|
return AdobeDCT.read(data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Generic APPn segment
|
||||||
|
byte[] bytes = new byte[length - 2];
|
||||||
|
data.readFully(bytes);
|
||||||
|
return new Application(marker, identifier, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
@ -21,10 +49,15 @@ class Comment extends Segment {
|
|||||||
this.comment = comment;
|
this.comment = comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "COM[" + comment + "]";
|
||||||
|
}
|
||||||
|
|
||||||
public static Segment read(final DataInput data, final int length) throws IOException {
|
public static Segment read(final DataInput data, final int length) throws IOException {
|
||||||
byte[] ascii = new byte[length];
|
byte[] ascii = new byte[length - 2];
|
||||||
data.readFully(ascii);
|
data.readFully(ascii);
|
||||||
|
|
||||||
return new Comment(new String(ascii, StandardCharsets.UTF_8));
|
return new Comment(new String(ascii, StandardCharsets.UTF_8)); // Strictly, it is ASCII, but UTF-8 is compatible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ final class Frame extends Segment {
|
|||||||
|
|
||||||
final Component[] components; // Components specifications
|
final Component[] components; // Components specifications
|
||||||
|
|
||||||
Frame(final int marker, final int samplePrecision, final int lines, final int samplesPerLine, final Component[] components) {
|
private Frame(final int marker, final int samplePrecision, final int lines, final int samplesPerLine, final Component[] components) {
|
||||||
super(marker);
|
super(marker);
|
||||||
|
|
||||||
this.samplePrecision = samplePrecision;
|
this.samplePrecision = samplePrecision;
|
||||||
@ -116,7 +116,7 @@ final class Frame extends Segment {
|
|||||||
return read(marker, new SubImageInputStream(data, length), length);
|
return read(marker, new SubImageInputStream(data, length), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class Component {
|
public static final class Component {
|
||||||
final int id;
|
final int id;
|
||||||
final int hSub; // Horizontal sampling factor
|
final int hSub; // Horizontal sampling factor
|
||||||
final int vSub; // Vertical sampling factor
|
final int vSub; // Vertical sampling factor
|
||||||
|
@ -1,37 +1,38 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Michael Martinez
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
* Copyright (C) 2015, Michael Martinez
|
||||||
* warnings, split into multiple class files, and general clean up.
|
* Copyright (C) 2004, Helmut Dersch
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
* Redistribution and use in source and binary forms, with or without
|
||||||
*/
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
/*
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* Copyright (C) Helmut Dersch
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* in the Software without restriction, including without limitation the rights
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* furnished to do so, subject to the following conditions:
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* all copies or substantial portions of the Software.
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -45,7 +46,7 @@ final class HuffmanTable extends Segment {
|
|||||||
|
|
||||||
public static final int MSB = 0x80000000;
|
public static final int MSB = 0x80000000;
|
||||||
|
|
||||||
public HuffmanTable() {
|
private HuffmanTable() {
|
||||||
super(JPEG.DHT);
|
super(JPEG.DHT);
|
||||||
|
|
||||||
tc[0][0] = 0;
|
tc[0][0] = 0;
|
||||||
@ -109,7 +110,7 @@ final class HuffmanTable extends Segment {
|
|||||||
}
|
}
|
||||||
if (k >= 256) {
|
if (k >= 256) {
|
||||||
if (k > 256) {
|
if (k > 256) {
|
||||||
throw new IOException("Huffman table error");
|
throw new IIOException("JPEG Huffman Table error");
|
||||||
}
|
}
|
||||||
|
|
||||||
k = 0;
|
k = 0;
|
||||||
@ -119,9 +120,14 @@ final class HuffmanTable extends Segment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Segment read(DataInput data, int length) throws IOException {
|
@Override
|
||||||
int count = 0;
|
public String toString() {
|
||||||
count += 2;
|
// TODO: Id and class for tables
|
||||||
|
return "DHT[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Segment read(final DataInput data, final int length) throws IOException {
|
||||||
|
int count = 2;
|
||||||
|
|
||||||
HuffmanTable table = new HuffmanTable();
|
HuffmanTable table = new HuffmanTable();
|
||||||
|
|
||||||
@ -130,12 +136,12 @@ final class HuffmanTable extends Segment {
|
|||||||
count++;
|
count++;
|
||||||
int t = temp & 0x0F;
|
int t = temp & 0x0F;
|
||||||
if (t > 3) {
|
if (t > 3) {
|
||||||
throw new IOException("Huffman table Id > 3:" + t);
|
throw new IIOException("Unexpected JPEG Huffman Table Id (> 3):" + t);
|
||||||
}
|
}
|
||||||
|
|
||||||
int c = temp >> 4;
|
int c = temp >> 4;
|
||||||
if (c > 2) {
|
if (c > 2) {
|
||||||
throw new IOException("Huffman table class > 2: " + c);
|
throw new IIOException("Unexpected JPEG Huffman Table class (> 2): " + c);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.th[t] = 1;
|
table.th[t] = 1;
|
||||||
@ -149,7 +155,7 @@ final class HuffmanTable extends Segment {
|
|||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
for (int j = 0; j < table.l[t][c][i]; j++) {
|
for (int j = 0; j < table.l[t][c][i]; j++) {
|
||||||
if (count > length) {
|
if (count > length) {
|
||||||
throw new IOException("Huffman table format error [count>Lh]");
|
throw new IIOException("JPEG Huffman Table format error");
|
||||||
}
|
}
|
||||||
table.v[t][c][i][j] = data.readUnsignedByte();
|
table.v[t][c][i][j] = data.readUnsignedByte();
|
||||||
count++;
|
count++;
|
||||||
@ -158,18 +164,9 @@ final class HuffmanTable extends Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (count != length) {
|
if (count != length) {
|
||||||
throw new IOException("Huffman table format error [count!=Lf]");
|
throw new IIOException("JPEG Huffman Table format error, bad segment length: " + length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (int i = 0; i < 4; i++) {
|
|
||||||
// for (int j = 0; j < 2; j++) {
|
|
||||||
// if (tc[i][j] != 0) {
|
|
||||||
// buildHuffTable(HuffTab[i][j], l[i][j], v[i][j]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return 1;
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
@ -12,12 +40,18 @@ import java.io.IOException;
|
|||||||
* @author last modified by $Author: harald.kuhr$
|
* @author last modified by $Author: harald.kuhr$
|
||||||
* @version $Id: ICCProfile.java,v 1.0 22/08/16 harald.kuhr Exp$
|
* @version $Id: ICCProfile.java,v 1.0 22/08/16 harald.kuhr Exp$
|
||||||
*/
|
*/
|
||||||
final class ICCProfile extends AppSegment {
|
final class ICCProfile extends Application {
|
||||||
protected ICCProfile(final byte[] data) {
|
private ICCProfile(final byte[] data) {
|
||||||
super(JPEG.APP2, "ICC_PROFILE", data);
|
super(JPEG.APP2, "ICC_PROFILE", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Create util method to concat all ICC segments to one and return ICC_Profile (move from JPEGImageReader)
|
// TODO: Create util method to concat all ICC segments to one and return ICC_Profile (move from JPEGImageReader)
|
||||||
|
// If so, how to deal with warnings from the original code? Throw exceptions instead?
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ICC_PROFILE[" + data[0] + "/" + data[1] + " length: " + data.length + "]";
|
||||||
|
}
|
||||||
|
|
||||||
public static ICCProfile read(DataInput data, int length) throws IOException {
|
public static ICCProfile read(DataInput data, int length) throws IOException {
|
||||||
byte[] bytes = new byte[length - 2];
|
byte[] bytes = new byte[length - 2];
|
||||||
|
@ -32,7 +32,6 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JFIFSegment
|
* JFIFSegment
|
||||||
@ -41,7 +40,7 @@ import java.util.Arrays;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: JFIFSegment.java,v 1.0 23.04.12 16:52 haraldk Exp$
|
* @version $Id: JFIFSegment.java,v 1.0 23.04.12 16:52 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class JFIF extends AppSegment {
|
final class JFIF extends Application {
|
||||||
final int majorVersion;
|
final int majorVersion;
|
||||||
final int minorVersion;
|
final int minorVersion;
|
||||||
final int units;
|
final int units;
|
||||||
|
@ -29,9 +29,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +39,7 @@ import java.util.Arrays;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: JFXXSegment.java,v 1.0 23.04.12 16:54 haraldk Exp$
|
* @version $Id: JFXXSegment.java,v 1.0 23.04.12 16:54 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class JFXX extends AppSegment {
|
final class JFXX extends Application {
|
||||||
public static final int JPEG = 0x10;
|
public static final int JPEG = 0x10;
|
||||||
public static final int INDEXED = 0x11;
|
public static final int INDEXED = 0x11;
|
||||||
public static final int RGB = 0x13;
|
public static final int RGB = 0x13;
|
||||||
|
@ -2,13 +2,9 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
|
|
||||||
import com.twelvemonkeys.imageio.AbstractMetadata;
|
import com.twelvemonkeys.imageio.AbstractMetadata;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,10 +91,10 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
Scan scan = (Scan) segment;
|
Scan scan = (Scan) segment;
|
||||||
IIOMetadataNode sos = new IIOMetadataNode("sos");
|
IIOMetadataNode sos = new IIOMetadataNode("sos");
|
||||||
sos.setAttribute("numScanComponents", String.valueOf(scan.components.length));
|
sos.setAttribute("numScanComponents", String.valueOf(scan.components.length));
|
||||||
sos.setAttribute("startSpectralSelection", String.valueOf(scan.selection));
|
sos.setAttribute("startSpectralSelection", String.valueOf(scan.spectralSelStart));
|
||||||
sos.setAttribute("endSpectralSelection", String.valueOf(scan.spectralEnd));
|
sos.setAttribute("endSpectralSelection", String.valueOf(scan.spectralSelEnd));
|
||||||
sos.setAttribute("approxHigh", String.valueOf(scan.ah));
|
sos.setAttribute("approxHigh", String.valueOf(scan.approxHigh));
|
||||||
sos.setAttribute("approxLow", String.valueOf(scan.al));
|
sos.setAttribute("approxLow", String.valueOf(scan.approxLow));
|
||||||
|
|
||||||
for (Scan.Component component : scan.components) {
|
for (Scan.Component component : scan.components) {
|
||||||
IIOMetadataNode spec = new IIOMetadataNode("scanComponentSpec");
|
IIOMetadataNode spec = new IIOMetadataNode("scanComponentSpec");
|
||||||
@ -135,7 +131,7 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
default:
|
default:
|
||||||
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
|
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
|
||||||
unknown.setAttribute("MarkerTag", String.valueOf(segment.marker & 0xFF));
|
unknown.setAttribute("MarkerTag", String.valueOf(segment.marker & 0xFF));
|
||||||
unknown.setUserObject(((AppSegment) segment).data);
|
unknown.setUserObject(((Application) segment).data);
|
||||||
markerSequence.appendChild(unknown);
|
markerSequence.appendChild(unknown);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -10,10 +10,7 @@ import javax.imageio.metadata.IIOInvalidTreeException;
|
|||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,7 +36,7 @@ final class JPEGImage10MetadataCleaner {
|
|||||||
IIOMetadata cleanMetadata(final IIOMetadata imageMetadata) throws IOException {
|
IIOMetadata cleanMetadata(final IIOMetadata imageMetadata) throws IOException {
|
||||||
// We filter out pretty much everything from the stream..
|
// We filter out pretty much everything from the stream..
|
||||||
// Meaning we have to read get *all APP segments* and re-insert into metadata.
|
// Meaning we have to read get *all APP segments* and re-insert into metadata.
|
||||||
List<AppSegment> appSegments = reader.getAppSegments(JPEGImageReader.ALL_APP_MARKERS, null);
|
List<Application> appSegments = reader.getAppSegments(JPEGImageReader.ALL_APP_MARKERS, null);
|
||||||
|
|
||||||
// NOTE: There's a bug in the merging code in JPEGMetadata mergeUnknownNode that makes sure all "unknown" nodes are added twice in certain conditions.... ARGHBL...
|
// NOTE: There's a bug in the merging code in JPEGMetadata mergeUnknownNode that makes sure all "unknown" nodes are added twice in certain conditions.... ARGHBL...
|
||||||
// DONE: 1: Work around
|
// DONE: 1: Work around
|
||||||
@ -176,7 +173,7 @@ final class JPEGImage10MetadataCleaner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node next = null;
|
Node next = null;
|
||||||
for (AppSegment segment : appSegments) {
|
for (Application segment : appSegments) {
|
||||||
// Except real app0JFIF, app0JFXX, app2ICC and app14Adobe, add all the app segments that we filtered away as "unknown" markers
|
// Except real app0JFIF, app0JFXX, app2ICC and app14Adobe, add all the app segments that we filtered away as "unknown" markers
|
||||||
if (segment.marker == JPEG.APP0 && "JFIF".equals(segment.identifier) && hasRealJFIF) {
|
if (segment.marker == JPEG.APP0 && "JFIF".equals(segment.identifier) && hasRealJFIF) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -39,7 +39,6 @@ import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
|||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.lossless.JPEGLosslessDecoderWrapper;
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
@ -110,7 +109,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
static final int ALL_APP_MARKERS = -1;
|
static final int ALL_APP_MARKERS = -1;
|
||||||
|
|
||||||
/** Segment identifiers for the JPEG segments we care about reading. */
|
/** Segment identifiers for the JPEG segments we care about reading. */
|
||||||
private static final Map<Integer, List<String>> SEGMENT_IDENTIFIERS = createSegmentIds();
|
private static final Map<Integer, List<String>> SEGMENT_IDENTIFIERS = JPEGSegmentUtil.ALL_SEGMENTS; //createSegmentIds();
|
||||||
|
|
||||||
private static Map<Integer, List<String>> createSegmentIds() {
|
private static Map<Integer, List<String>> createSegmentIds() {
|
||||||
Map<Integer, List<String>> map = new LinkedHashMap<>();
|
Map<Integer, List<String>> map = new LinkedHashMap<>();
|
||||||
@ -386,7 +385,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// TODO: What about stream position?
|
// TODO: What about stream position?
|
||||||
// TODO: Param handling: Source region, offset, subsampling, destination, destination type, etc....
|
// TODO: Param handling: Source region, offset, subsampling, destination, destination type, etc....
|
||||||
// Read image as lossless
|
// Read image as lossless
|
||||||
return new JPEGLosslessDecoderWrapper().readImage(imageInput);
|
return new JPEGLosslessDecoderWrapper().readImage(segments, imageInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
||||||
@ -592,25 +591,25 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
if (adobeDCT != null) {
|
if (adobeDCT != null) {
|
||||||
switch (adobeDCT.transform) {
|
switch (adobeDCT.transform) {
|
||||||
case AdobeDCT.YCC:
|
case AdobeDCT.YCC:
|
||||||
if (startOfFrame.components.length != 3) {
|
if (startOfFrame.componentsInFrame() != 3) {
|
||||||
// This probably means the Adobe marker is bogus
|
// This probably means the Adobe marker is bogus
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return JPEGColorSpace.YCbCr;
|
return JPEGColorSpace.YCbCr;
|
||||||
case AdobeDCT.YCCK:
|
case AdobeDCT.YCCK:
|
||||||
if (startOfFrame.components.length != 4) {
|
if (startOfFrame.componentsInFrame() != 4) {
|
||||||
// This probably means the Adobe marker is bogus
|
// This probably means the Adobe marker is bogus
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return JPEGColorSpace.YCCK;
|
return JPEGColorSpace.YCCK;
|
||||||
case AdobeDCT.Unknown:
|
case AdobeDCT.Unknown:
|
||||||
if (startOfFrame.components.length == 1) {
|
if (startOfFrame.componentsInFrame() == 1) {
|
||||||
return JPEGColorSpace.Gray;
|
return JPEGColorSpace.Gray;
|
||||||
}
|
}
|
||||||
else if (startOfFrame.components.length == 3) {
|
else if (startOfFrame.componentsInFrame() == 3) {
|
||||||
return JPEGColorSpace.RGB;
|
return JPEGColorSpace.RGB;
|
||||||
}
|
}
|
||||||
else if (startOfFrame.components.length == 4) {
|
else if (startOfFrame.componentsInFrame() == 4) {
|
||||||
return JPEGColorSpace.CMYK;
|
return JPEGColorSpace.CMYK;
|
||||||
}
|
}
|
||||||
// Else fall through
|
// Else fall through
|
||||||
@ -619,7 +618,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We should probably allow component ids out of order (ie. BGR or KMCY)...
|
// TODO: We should probably allow component ids out of order (ie. BGR or KMCY)...
|
||||||
switch (startOfFrame.components.length) {
|
switch (startOfFrame.componentsInFrame()) {
|
||||||
case 1:
|
case 1:
|
||||||
return JPEGColorSpace.Gray;
|
return JPEGColorSpace.Gray;
|
||||||
case 2:
|
case 2:
|
||||||
@ -712,7 +711,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
if (segments == null) {
|
if (segments == null) {
|
||||||
long start = DEBUG ? System.currentTimeMillis() : 0;
|
long start = DEBUG ? System.currentTimeMillis() : 0;
|
||||||
|
|
||||||
// TODO: Consider just reading the segments here, for better performance...
|
// TODO: Consider just reading the segments directly, for better performance...
|
||||||
List<JPEGSegment> jpegSegments = readSegments();
|
List<JPEGSegment> jpegSegments = readSegments();
|
||||||
|
|
||||||
List<Segment> segments = new ArrayList<>(jpegSegments.size());
|
List<Segment> segments = new ArrayList<>(jpegSegments.size());
|
||||||
@ -761,20 +760,20 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AppSegment> getAppSegments(final int marker, final String identifier) throws IOException {
|
List<Application> getAppSegments(final int marker, final String identifier) throws IOException {
|
||||||
initHeader();
|
initHeader();
|
||||||
|
|
||||||
List<AppSegment> appSegments = Collections.emptyList();
|
List<Application> appSegments = Collections.emptyList();
|
||||||
|
|
||||||
for (Segment segment : segments) {
|
for (Segment segment : segments) {
|
||||||
if (segment instanceof AppSegment
|
if (segment instanceof Application
|
||||||
&& (marker == ALL_APP_MARKERS || marker == segment.marker)
|
&& (marker == ALL_APP_MARKERS || marker == segment.marker)
|
||||||
&& (identifier == null || identifier.equals(((AppSegment) segment).identifier))) {
|
&& (identifier == null || identifier.equals(((Application) segment).identifier))) {
|
||||||
if (appSegments == Collections.EMPTY_LIST) {
|
if (appSegments == Collections.EMPTY_LIST) {
|
||||||
appSegments = new ArrayList<>(segments.size());
|
appSegments = new ArrayList<>(segments.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
appSegments.add((AppSegment) segment);
|
appSegments.add((Application) segment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,26 +793,26 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AdobeDCT getAdobeDCT() throws IOException {
|
AdobeDCT getAdobeDCT() throws IOException {
|
||||||
List<AppSegment> adobe = getAppSegments(JPEG.APP14, "Adobe");
|
List<Application> adobe = getAppSegments(JPEG.APP14, "Adobe");
|
||||||
return adobe.isEmpty() ? null : (AdobeDCT) adobe.get(0);
|
return adobe.isEmpty() ? null : (AdobeDCT) adobe.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
JFIF getJFIF() throws IOException{
|
JFIF getJFIF() throws IOException{
|
||||||
List<AppSegment> jfif = getAppSegments(JPEG.APP0, "JFIF");
|
List<Application> jfif = getAppSegments(JPEG.APP0, "JFIF");
|
||||||
return jfif.isEmpty() ? null : (JFIF) jfif.get(0);
|
return jfif.isEmpty() ? null : (JFIF) jfif.get(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JFXX getJFXX() throws IOException {
|
JFXX getJFXX() throws IOException {
|
||||||
List<AppSegment> jfxx = getAppSegments(JPEG.APP0, "JFXX");
|
List<Application> jfxx = getAppSegments(JPEG.APP0, "JFXX");
|
||||||
return jfxx.isEmpty() ? null : (JFXX) jfxx.get(0);
|
return jfxx.isEmpty() ? null : (JFXX) jfxx.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompoundDirectory getExif() throws IOException {
|
private CompoundDirectory getExif() throws IOException {
|
||||||
List<AppSegment> exifSegments = getAppSegments(JPEG.APP1, "Exif");
|
List<Application> exifSegments = getAppSegments(JPEG.APP1, "Exif");
|
||||||
|
|
||||||
if (!exifSegments.isEmpty()) {
|
if (!exifSegments.isEmpty()) {
|
||||||
AppSegment exif = exifSegments.get(0);
|
Application exif = exifSegments.get(0);
|
||||||
InputStream data = exif.data();
|
InputStream data = exif.data();
|
||||||
|
|
||||||
if (data.read() == -1) { // Read pad
|
if (data.read() == -1) { // Read pad
|
||||||
@ -849,13 +848,13 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// TODO: Allow metadata to contain the wrongly indexed profiles, if readable
|
// TODO: Allow metadata to contain the wrongly indexed profiles, if readable
|
||||||
// NOTE: We ignore any profile with wrong index for reading and image types, just to be on the safe side
|
// NOTE: We ignore any profile with wrong index for reading and image types, just to be on the safe side
|
||||||
|
|
||||||
List<AppSegment> segments = getAppSegments(JPEG.APP2, "ICC_PROFILE");
|
List<Application> segments = getAppSegments(JPEG.APP2, "ICC_PROFILE");
|
||||||
|
|
||||||
// TODO: Possibly move this logic to the ICCProfile class...
|
// TODO: Possibly move this logic to the ICCProfile class...
|
||||||
|
|
||||||
if (segments.size() == 1) {
|
if (segments.size() == 1) {
|
||||||
// Faster code for the common case
|
// Faster code for the common case
|
||||||
AppSegment segment = segments.get(0);
|
Application segment = segments.get(0);
|
||||||
DataInputStream stream = new DataInputStream(segment.data());
|
DataInputStream stream = new DataInputStream(segment.data());
|
||||||
int chunkNumber = stream.readUnsignedByte();
|
int chunkNumber = stream.readUnsignedByte();
|
||||||
int chunkCount = stream.readUnsignedByte();
|
int chunkCount = stream.readUnsignedByte();
|
||||||
@ -945,7 +944,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
if (isLossless()) {
|
if (isLossless()) {
|
||||||
// TODO: What about stream position?
|
// TODO: What about stream position?
|
||||||
// TODO: Param handling: Reading as raster should support source region, subsampling etc.
|
// TODO: Param handling: Reading as raster should support source region, subsampling etc.
|
||||||
return new JPEGLosslessDecoderWrapper().readRaster(imageInput);
|
return new JPEGLosslessDecoderWrapper().readRaster(segments, imageInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
return delegate.readRaster(imageIndex, param);
|
return delegate.readRaster(imageIndex, param);
|
||||||
@ -1001,9 +1000,9 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read Exif thumbnails if present
|
// Read Exif thumbnails if present
|
||||||
List<AppSegment> exifSegments = getAppSegments(JPEG.APP1, "Exif");
|
List<Application> exifSegments = getAppSegments(JPEG.APP1, "Exif");
|
||||||
if (!exifSegments.isEmpty()) {
|
if (!exifSegments.isEmpty()) {
|
||||||
AppSegment exif = exifSegments.get(0);
|
Application exif = exifSegments.get(0);
|
||||||
InputStream data = exif.data();
|
InputStream data = exif.data();
|
||||||
|
|
||||||
if (data.read() == -1) {
|
if (data.read() == -1) {
|
||||||
|
@ -1,50 +1,51 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Michael Martinez
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
* Copyright (C) 2015, Michael Martinez
|
||||||
* warnings, split into multiple class files, and general clean up.
|
* Copyright (C) 2004, Helmut Dersch
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
* Copyright (C) Helmut Dersch
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class JPEGLosslessDecoder {
|
final class JPEGLosslessDecoder {
|
||||||
|
|
||||||
private final ImageInputStream input;
|
private final ImageInputStream input;
|
||||||
|
|
||||||
// TODO: Merge these classes with similar classes from the main package
|
private final Frame frame;
|
||||||
// (FrameHeader == Frame, ComponentSpec == Frame.Component, ScanHeader == Scan etc)
|
|
||||||
private final FrameHeader frame;
|
|
||||||
private final HuffmanTable huffTable;
|
private final HuffmanTable huffTable;
|
||||||
private final QuantizationTable quantTable;
|
private final QuantizationTable quantTable;
|
||||||
private final ScanHeader scan;
|
private Scan scan;
|
||||||
|
|
||||||
private final int HuffTab[][][] = new int[4][2][MAX_HUFFMAN_SUBTREE * 256];
|
private final int HuffTab[][][] = new int[4][2][MAX_HUFFMAN_SUBTREE * 256];
|
||||||
private final int IDCT_Source[] = new int[64];
|
private final int IDCT_Source[] = new int[64];
|
||||||
@ -69,36 +70,65 @@ public class JPEGLosslessDecoder {
|
|||||||
private int[] outputBlueData;
|
private int[] outputBlueData;
|
||||||
|
|
||||||
private static final int IDCT_P[] = {
|
private static final int IDCT_P[] = {
|
||||||
0, 5, 40, 16, 45, 2, 7, 42, 21, 56, 8, 61, 18, 47, 1, 4, 41, 23, 58, 13, 32, 24, 37, 10, 63, 17, 44, 3, 6, 43, 20,
|
0, 5, 40, 16, 45, 2, 7, 42,
|
||||||
57, 15, 34, 29, 48, 53, 26, 39, 9, 60, 19, 46, 22, 59, 12, 33, 31, 50, 55, 25, 36, 11, 62, 14, 35, 28, 49, 52, 27, 38, 30, 51, 54
|
21, 56, 8, 61, 18, 47, 1, 4,
|
||||||
|
41, 23, 58, 13, 32, 24, 37, 10,
|
||||||
|
63, 17, 44, 3, 6, 43, 20, 57,
|
||||||
|
15, 34, 29, 48, 53, 26, 39, 9,
|
||||||
|
60, 19, 46, 22, 59, 12, 33, 31,
|
||||||
|
50, 55, 25, 36, 11, 62, 14, 35,
|
||||||
|
28, 49, 52, 27, 38, 30, 51, 54
|
||||||
};
|
};
|
||||||
private static final int TABLE[] = {
|
private static final int TABLE[] = {
|
||||||
0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53,
|
0, 1, 5, 6, 14, 15, 27, 28,
|
||||||
10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63
|
2, 4, 7, 13, 16, 26, 29, 42,
|
||||||
|
3, 8, 12, 17, 25, 30, 41, 43,
|
||||||
|
9, 11, 18, 24, 31, 40, 44, 53,
|
||||||
|
10, 19, 23, 32, 39, 45, 52, 54,
|
||||||
|
20, 22, 33, 38, 46, 51, 55, 60,
|
||||||
|
21, 34, 37, 47, 50, 56, 59, 61,
|
||||||
|
35, 36, 48, 49, 57, 58, 62, 63
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final int RESTART_MARKER_BEGIN = 0xFFD0;
|
private static final int RESTART_MARKER_BEGIN = 0xFFD0;
|
||||||
public static final int RESTART_MARKER_END = 0xFFD7;
|
private static final int RESTART_MARKER_END = 0xFFD7;
|
||||||
public static final int MAX_HUFFMAN_SUBTREE = 50;
|
private static final int MAX_HUFFMAN_SUBTREE = 50;
|
||||||
public static final int MSB = 0x80000000;
|
private static final int MSB = 0x80000000;
|
||||||
|
|
||||||
public int getDimX() {
|
int getDimX() {
|
||||||
return xDim;
|
return xDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDimY() {
|
int getDimY() {
|
||||||
return yDim;
|
return yDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JPEGLosslessDecoder(final ImageInputStream data) {
|
JPEGLosslessDecoder(final List<Segment> segments, final ImageInputStream data) {
|
||||||
|
Validate.notNull(segments);
|
||||||
|
|
||||||
|
frame = get(segments, Frame.class);
|
||||||
|
scan = get(segments, Scan.class);
|
||||||
|
|
||||||
|
QuantizationTable qt = get(segments, QuantizationTable.class);
|
||||||
|
quantTable = qt != null ? qt : new QuantizationTable(); // For lossless there are no DQTs
|
||||||
|
huffTable = get(segments, HuffmanTable.class); // For non-lossless there can be multiple of DHTs
|
||||||
|
RestartInterval dri = get(segments, RestartInterval.class);
|
||||||
|
restartInterval = dri != null ? dri.interval : 0;
|
||||||
|
|
||||||
input = data;
|
input = data;
|
||||||
frame = new FrameHeader();
|
|
||||||
scan = new ScanHeader();
|
|
||||||
quantTable = new QuantizationTable();
|
|
||||||
huffTable = new HuffmanTable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[][] decode() throws IOException {
|
private <T> T get(final List<Segment> segments, final Class<T> type) {
|
||||||
|
for (Segment segment : segments) {
|
||||||
|
if (type.isInstance(segment)) {
|
||||||
|
return type.cast(segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[][] decode() throws IOException {
|
||||||
int current, scanNum = 0;
|
int current, scanNum = 0;
|
||||||
final int pred[] = new int[10];
|
final int pred[] = new int[10];
|
||||||
int[][] outputRef;
|
int[][] outputRef;
|
||||||
@ -108,108 +138,22 @@ public class JPEGLosslessDecoder {
|
|||||||
current = input.readUnsignedShort();
|
current = input.readUnsignedShort();
|
||||||
|
|
||||||
if (current != JPEG.SOI) { // SOI
|
if (current != JPEG.SOI) { // SOI
|
||||||
throw new IOException("Not a JPEG file");
|
throw new IIOException("Not a JPEG file");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Why the two loops?!
|
huffTable.buildHuffTables(HuffTab);
|
||||||
|
quantTable.enhanceTables(TABLE);
|
||||||
|
|
||||||
current = input.readUnsignedShort();
|
current = input.readUnsignedShort();
|
||||||
|
|
||||||
while (((current >> 4) != 0x0FFC) || (current == JPEG.DHT)) { // SOF 0~15
|
|
||||||
switch (current) {
|
|
||||||
case JPEG.DHT: // DHT
|
|
||||||
huffTable.read(input, HuffTab);
|
|
||||||
break;
|
|
||||||
case JPEG.DAC: // DAC
|
|
||||||
throw new IOException("Program doesn't support arithmetic coding.");
|
|
||||||
case JPEG.DQT:
|
|
||||||
quantTable.read(input, TABLE);
|
|
||||||
break;
|
|
||||||
case JPEG.DRI:
|
|
||||||
restartInterval = readNumber();
|
|
||||||
break;
|
|
||||||
case JPEG.APP0:
|
|
||||||
case JPEG.APP1:
|
|
||||||
case JPEG.APP2:
|
|
||||||
case JPEG.APP3:
|
|
||||||
case JPEG.APP4:
|
|
||||||
case JPEG.APP5:
|
|
||||||
case JPEG.APP6:
|
|
||||||
case JPEG.APP7:
|
|
||||||
case JPEG.APP8:
|
|
||||||
case JPEG.APP9:
|
|
||||||
case JPEG.APP10:
|
|
||||||
case JPEG.APP11:
|
|
||||||
case JPEG.APP12:
|
|
||||||
case JPEG.APP13:
|
|
||||||
case JPEG.APP14:
|
|
||||||
case JPEG.APP15:
|
|
||||||
readApp();
|
|
||||||
break;
|
|
||||||
case JPEG.COM:
|
|
||||||
readComment();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ((current >> 8) != 0xFF) {
|
|
||||||
throw new IOException("JPEG Segment marker expected.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current = input.readUnsignedShort();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((current < 0xFFC0) || (current > 0xFFC7)) {
|
|
||||||
throw new IOException("ERROR: could not handle arithmetic code!");
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.read(input);
|
|
||||||
current = input.readUnsignedShort();
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
while (current != 0x0FFDA) { //SOS
|
// Skip until first SOS
|
||||||
switch (current) {
|
while (current != JPEG.SOS) {
|
||||||
case 0xFFC4: //DHT
|
input.skipBytes(input.readUnsignedShort() - 2);
|
||||||
huffTable.read(input, HuffTab);
|
|
||||||
break;
|
|
||||||
case 0xFFCC: //DAC
|
|
||||||
throw new IOException("Program doesn't support arithmetic coding. (format throw new IOException)");
|
|
||||||
case 0xFFDB:
|
|
||||||
quantTable.read(input, TABLE);
|
|
||||||
break;
|
|
||||||
case 0xFFDD:
|
|
||||||
restartInterval = readNumber();
|
|
||||||
break;
|
|
||||||
case 0xFFE0:
|
|
||||||
case 0xFFE1:
|
|
||||||
case 0xFFE2:
|
|
||||||
case 0xFFE3:
|
|
||||||
case 0xFFE4:
|
|
||||||
case 0xFFE5:
|
|
||||||
case 0xFFE6:
|
|
||||||
case 0xFFE7:
|
|
||||||
case 0xFFE8:
|
|
||||||
case 0xFFE9:
|
|
||||||
case 0xFFEA:
|
|
||||||
case 0xFFEB:
|
|
||||||
case 0xFFEC:
|
|
||||||
case 0xFFED:
|
|
||||||
case 0xFFEE:
|
|
||||||
case 0xFFEF:
|
|
||||||
readApp();
|
|
||||||
break;
|
|
||||||
case 0xFFFE:
|
|
||||||
readComment();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ((current >> 8) != 0xFF) {
|
|
||||||
throw new IOException("ERROR: format throw new IOException! (Parser.decode)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current = input.readUnsignedShort();
|
current = input.readUnsignedShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
final int precision = frame.getPrecision();
|
int precision = frame.samplePrecision;
|
||||||
|
|
||||||
if (precision == 8) {
|
if (precision == 8) {
|
||||||
mask = 0xFF;
|
mask = 0xFF;
|
||||||
@ -218,28 +162,29 @@ public class JPEGLosslessDecoder {
|
|||||||
mask = 0xFFFF;
|
mask = 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ComponentSpec[] components = frame.getComponents();
|
Frame.Component[] components = frame.components;
|
||||||
|
|
||||||
readScan();
|
scan = readScan();
|
||||||
numComp = scan.getNumComponents();
|
numComp = scan.components.length;
|
||||||
selection = scan.getSelection();
|
selection = scan.spectralSelStart;
|
||||||
|
|
||||||
final ScanComponent[] scanComps = scan.components;
|
final Scan.Component[] scanComps = scan.components;
|
||||||
final int[][] quantTables = quantTable.quantTables;
|
final int[][] quantTables = quantTable.quantTables;
|
||||||
|
|
||||||
for (int i = 0; i < numComp; i++) {
|
for (int i = 0; i < numComp; i++) {
|
||||||
ComponentSpec component = getComponentSpec(components, scanComps[i].getScanCompSel());
|
Frame.Component component = getComponentSpec(components, scanComps[i].scanCompSel);
|
||||||
qTab[i] = quantTables[component.quantTableSel];
|
qTab[i] = quantTables[component.qtSel];
|
||||||
nBlock[i] = component.vSamp * component.hSamp;
|
nBlock[i] = component.vSub * component.hSub;
|
||||||
dcTab[i] = HuffTab[scanComps[i].getDcTabSel()][0];
|
dcTab[i] = HuffTab[scanComps[i].dcTabSel][0];
|
||||||
acTab[i] = HuffTab[scanComps[i].getAcTabSel()][1];
|
acTab[i] = HuffTab[scanComps[i].acTabSel][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
xDim = frame.getDimX();
|
xDim = frame.samplesPerLine;
|
||||||
yDim = frame.getDimY();
|
yDim = frame.lines;
|
||||||
|
|
||||||
outputRef = new int[numComp][];
|
outputRef = new int[numComp][];
|
||||||
|
|
||||||
|
// TODO: Support 4 components (RGBA/YCCA/CMYK/YCCK), others?
|
||||||
if (numComp == 1) {
|
if (numComp == 1) {
|
||||||
outputData = new int[xDim * yDim];
|
outputData = new int[xDim * yDim];
|
||||||
outputRef[0] = outputData;
|
outputRef[0] = outputData;
|
||||||
@ -314,8 +259,8 @@ public class JPEGLosslessDecoder {
|
|||||||
return outputRef;
|
return outputRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ComponentSpec getComponentSpec(ComponentSpec[] components, int sel) {
|
private Frame.Component getComponentSpec(Frame.Component[] components, int sel) {
|
||||||
for (ComponentSpec component : components) {
|
for (Frame.Component component : components) {
|
||||||
if (component.id == sel) {
|
if (component.id == sel) {
|
||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
@ -324,8 +269,9 @@ public class JPEGLosslessDecoder {
|
|||||||
throw new IllegalArgumentException("No such component id: " + sel);
|
throw new IllegalArgumentException("No such component id: " + sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readScan() throws IOException {
|
private Scan readScan() throws IOException {
|
||||||
return scan.read(input);
|
int length = input.readUnsignedShort();
|
||||||
|
return Scan.read(input, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int decode(final int prev[], final int temp[], final int index[]) throws IOException {
|
private int decode(final int prev[], final int temp[], final int index[]) throws IOException {
|
||||||
@ -341,11 +287,11 @@ public class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int decodeSingle(final int prev[], final int temp[], final int index[]) throws IOException {
|
private int decodeSingle(final int prev[], final int temp[], final int index[]) throws IOException {
|
||||||
// At the beginning of the first line and
|
// At the beginning of the first line and
|
||||||
// at the beginning of each restart interval the prediction value of 2P – 1 is used, where P is the input precision.
|
// at the beginning of each restart interval the prediction value of 2P – 1 is used, where P is the input precision.
|
||||||
if (restarting) {
|
if (restarting) {
|
||||||
restarting = false;
|
restarting = false;
|
||||||
prev[0] = (1 << (frame.getPrecision() - 1));
|
prev[0] = (1 << (frame.samplePrecision - 1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch (selection) {
|
switch (selection) {
|
||||||
@ -554,7 +500,7 @@ public class JPEGLosslessDecoder {
|
|||||||
index[0] += 8 - (code >> 8);
|
index[0] += 8 - (code >> 8);
|
||||||
|
|
||||||
if (index[0] < 0) {
|
if (index[0] < 0) {
|
||||||
throw new IOException("index=" + index[0] + " temp=" + temp[0] + " code=" + code + " in HuffmanValue()");
|
throw new IIOException("index=" + index[0] + " temp=" + temp[0] + " code=" + code + " in HuffmanValue()");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index[0] < markerIndex) {
|
if (index[0] < markerIndex) {
|
||||||
@ -566,7 +512,7 @@ public class JPEGLosslessDecoder {
|
|||||||
return code & 0xFF;
|
return code & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getn(final int[] PRED, final int n, final int temp[], final int index[]) throws IOException {
|
private int getn(final int[] pred, final int n, final int temp[], final int index[]) throws IOException {
|
||||||
int result;
|
int result;
|
||||||
final int one = 1;
|
final int one = 1;
|
||||||
final int n_one = -1;
|
final int n_one = -1;
|
||||||
@ -578,7 +524,7 @@ public class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (n == 16) {
|
if (n == 16) {
|
||||||
if (PRED[0] >= 0) {
|
if (pred[0] >= 0) {
|
||||||
return -32768;
|
return -32768;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -659,7 +605,7 @@ public class JPEGLosslessDecoder {
|
|||||||
return getPreviousY(data);
|
return getPreviousY(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (1 << (frame.getPrecision() - 1));
|
return (1 << (frame.samplePrecision - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,18 +631,18 @@ public class JPEGLosslessDecoder {
|
|||||||
return (xLoc == (xDim - 1)) && (yLoc == (yDim - 1));
|
return (xLoc == (xDim - 1)) && (yLoc == (yDim - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void output(final int PRED[]) {
|
private void output(final int pred[]) {
|
||||||
if (numComp == 1) {
|
if (numComp == 1) {
|
||||||
outputSingle(PRED);
|
outputSingle(pred);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outputRGB(PRED);
|
outputRGB(pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputSingle(final int PRED[]) {
|
private void outputSingle(final int pred[]) {
|
||||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||||
outputData[(yLoc * xDim) + xLoc] = mask & PRED[0];
|
outputData[(yLoc * xDim) + xLoc] = mask & pred[0];
|
||||||
xLoc++;
|
xLoc++;
|
||||||
|
|
||||||
if (xLoc >= xDim) {
|
if (xLoc >= xDim) {
|
||||||
@ -706,11 +652,11 @@ public class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputRGB(final int PRED[]) {
|
private void outputRGB(final int pred[]) {
|
||||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||||
outputRedData[(yLoc * xDim) + xLoc] = PRED[0];
|
outputRedData[(yLoc * xDim) + xLoc] = pred[0];
|
||||||
outputGreenData[(yLoc * xDim) + xLoc] = PRED[1];
|
outputGreenData[(yLoc * xDim) + xLoc] = pred[1];
|
||||||
outputBlueData[(yLoc * xDim) + xLoc] = PRED[2];
|
outputBlueData[(yLoc * xDim) + xLoc] = pred[2];
|
||||||
xLoc++;
|
xLoc++;
|
||||||
|
|
||||||
if (xLoc >= xDim) {
|
if (xLoc >= xDim) {
|
||||||
@ -720,34 +666,6 @@ public class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readApp() throws IOException {
|
|
||||||
int count = 0;
|
|
||||||
final int length = input.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
while (count < length) {
|
|
||||||
input.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readComment() throws IOException {
|
|
||||||
final StringBuffer sb = new StringBuffer();
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
final int length = input.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
while (count < length) {
|
|
||||||
sb.append((char) input.readUnsignedByte());
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readNumber() throws IOException {
|
private int readNumber() throws IOException {
|
||||||
final int Ld = input.readUnsignedShort();
|
final int Ld = input.readUnsignedShort();
|
||||||
|
|
||||||
@ -758,11 +676,11 @@ public class JPEGLosslessDecoder {
|
|||||||
return input.readUnsignedShort();
|
return input.readUnsignedShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumComponents() {
|
int getNumComponents() {
|
||||||
return numComp;
|
return numComp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPrecision() {
|
int getPrecision() {
|
||||||
return frame.getPrecision();
|
return frame.samplePrecision;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,33 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
/*
|
||||||
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
|
* Copyright (c) 2016, Herman Kroll
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@ -6,6 +35,7 @@ import java.awt.image.DataBufferByte;
|
|||||||
import java.awt.image.DataBufferUShort;
|
import java.awt.image.DataBufferUShort;
|
||||||
import java.awt.image.Raster;
|
import java.awt.image.Raster;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides the conversion of input data
|
* This class provides the conversion of input data
|
||||||
@ -22,7 +52,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Hermann Kroll
|
* @author Hermann Kroll
|
||||||
*/
|
*/
|
||||||
public class JPEGLosslessDecoderWrapper {
|
final class JPEGLosslessDecoderWrapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes a JPEG Lossless stream to a {@code BufferedImage}.
|
* Decodes a JPEG Lossless stream to a {@code BufferedImage}.
|
||||||
@ -31,17 +61,19 @@ public class JPEGLosslessDecoderWrapper {
|
|||||||
* - 8Bit, Grayscale -> BufferedImage.TYPE_BYTE_GRAY
|
* - 8Bit, Grayscale -> BufferedImage.TYPE_BYTE_GRAY
|
||||||
* - 16Bit, Grayscale -> BufferedImage.TYPE_USHORT_GRAY
|
* - 16Bit, Grayscale -> BufferedImage.TYPE_USHORT_GRAY
|
||||||
*
|
*
|
||||||
|
* @param segments
|
||||||
* @param input input stream which contains a jpeg lossless data
|
* @param input input stream which contains a jpeg lossless data
|
||||||
* @return if successfully a BufferedImage is returned
|
* @return if successfully a BufferedImage is returned
|
||||||
* @throws IOException is thrown if the decoder failed or a conversion is not supported
|
* @throws IOException is thrown if the decoder failed or a conversion is not supported
|
||||||
*/
|
*/
|
||||||
public BufferedImage readImage(final ImageInputStream input) throws IOException {
|
BufferedImage readImage(final List<Segment> segments, final ImageInputStream input) throws IOException {
|
||||||
JPEGLosslessDecoder decoder = new JPEGLosslessDecoder(input);
|
JPEGLosslessDecoder decoder = new JPEGLosslessDecoder(segments, input);
|
||||||
|
|
||||||
int[][] decoded = decoder.decode();
|
int[][] decoded = decoder.decode();
|
||||||
int width = decoder.getDimX();
|
int width = decoder.getDimX();
|
||||||
int height = decoder.getDimY();
|
int height = decoder.getDimY();
|
||||||
|
|
||||||
|
// Single component, assumed to be Gray
|
||||||
if (decoder.getNumComponents() == 1) {
|
if (decoder.getNumComponents() == 1) {
|
||||||
switch (decoder.getPrecision()) {
|
switch (decoder.getPrecision()) {
|
||||||
case 8:
|
case 8:
|
||||||
@ -52,7 +84,8 @@ public class JPEGLosslessDecoderWrapper {
|
|||||||
throw new IOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and 1 component cannot be decoded");
|
throw new IOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and 1 component cannot be decoded");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//rgb
|
|
||||||
|
// 3 components, assumed to be RGB
|
||||||
if (decoder.getNumComponents() == 3) {
|
if (decoder.getNumComponents() == 3) {
|
||||||
switch (decoder.getPrecision()) {
|
switch (decoder.getPrecision()) {
|
||||||
case 8:
|
case 8:
|
||||||
@ -66,9 +99,9 @@ public class JPEGLosslessDecoderWrapper {
|
|||||||
throw new IOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and " + decoder.getNumComponents() + " component(s) cannot be decoded");
|
throw new IOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and " + decoder.getNumComponents() + " component(s) cannot be decoded");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Raster readRaster(final ImageInputStream input) throws IOException {
|
Raster readRaster(final List<Segment> segments, final ImageInputStream input) throws IOException {
|
||||||
// TODO: Can perhaps be implemented faster
|
// TODO: Can perhaps be implemented faster
|
||||||
return readImage(input).getRaster();
|
return readImage(segments, input).getRaster();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -38,7 +38,7 @@ import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
|
|||||||
* @version $Id: JPEGProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
|
* @version $Id: JPEGProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
|
||||||
*/
|
*/
|
||||||
final class JPEGProviderInfo extends ReaderWriterProviderInfo {
|
final class JPEGProviderInfo extends ReaderWriterProviderInfo {
|
||||||
protected JPEGProviderInfo() {
|
JPEGProviderInfo() {
|
||||||
super(
|
super(
|
||||||
JPEGProviderInfo.class,
|
JPEGProviderInfo.class,
|
||||||
new String[] {"JPEG", "jpeg", "JPG", "jpg"},
|
new String[] {"JPEG", "jpeg", "JPG", "jpg"},
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Michael Martinez
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
* Copyright (C) 2015, Michael Martinez
|
||||||
* warnings, split into multiple class files, and general clean up.
|
* Copyright (C) 2004, Helmut Dersch
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
* Redistribution and use in source and binary forms, with or without
|
||||||
*/
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
/*
|
* notice, this list of conditions and the following disclaimer.
|
||||||
* Copyright (C) Helmut Dersch
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
* in the Software without restriction, including without limitation the rights
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
* furnished to do so, subject to the following conditions:
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
* all copies or substantial portions of the Software.
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.IIOException;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ final class QuantizationTable extends Segment {
|
|||||||
private final int precision[] = new int[4]; // Quantization precision 8 or 16
|
private final int precision[] = new int[4]; // Quantization precision 8 or 16
|
||||||
private final int[] tq = new int[4]; // 1: this table is presented
|
private final int[] tq = new int[4]; // 1: this table is presented
|
||||||
|
|
||||||
protected final int quantTables[][] = new int[4][64]; // Tables
|
final int quantTables[][] = new int[4][64]; // Tables
|
||||||
|
|
||||||
QuantizationTable() {
|
QuantizationTable() {
|
||||||
super(JPEG.DQT);
|
super(JPEG.DQT);
|
||||||
@ -53,7 +53,7 @@ final class QuantizationTable extends Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Get rid of table param, make it a member?
|
// TODO: Get rid of table param, make it a member?
|
||||||
protected void enhanceTables(final int[] table) throws IOException {
|
void enhanceTables(final int[] table) throws IOException {
|
||||||
for (int t = 0; t < 4; t++) {
|
for (int t = 0; t < 4; t++) {
|
||||||
if (tq[t] != 0) {
|
if (tq[t] != 0) {
|
||||||
enhanceQuantizationTable(quantTables[t], table);
|
enhanceQuantizationTable(quantTables[t], table);
|
||||||
@ -63,24 +63,24 @@ final class QuantizationTable extends Segment {
|
|||||||
|
|
||||||
private void enhanceQuantizationTable(final int qtab[], final int[] table) {
|
private void enhanceQuantizationTable(final int qtab[], final int[] table) {
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
qtab[table[(0 * 8) + i]] *= 90;
|
qtab[table[ i]] *= 90;
|
||||||
qtab[table[(4 * 8) + i]] *= 90;
|
qtab[table[(4 * 8) + i]] *= 90;
|
||||||
qtab[table[(2 * 8) + i]] *= 118;
|
qtab[table[(2 * 8) + i]] *= 118;
|
||||||
qtab[table[(6 * 8) + i]] *= 49;
|
qtab[table[(6 * 8) + i]] *= 49;
|
||||||
qtab[table[(5 * 8) + i]] *= 71;
|
qtab[table[(5 * 8) + i]] *= 71;
|
||||||
qtab[table[(1 * 8) + i]] *= 126;
|
qtab[table[( 8) + i]] *= 126;
|
||||||
qtab[table[(7 * 8) + i]] *= 25;
|
qtab[table[(7 * 8) + i]] *= 25;
|
||||||
qtab[table[(3 * 8) + i]] *= 106;
|
qtab[table[(3 * 8) + i]] *= 106;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
qtab[table[0 + (8 * i)]] *= 90;
|
qtab[table[( 8 * i)]] *= 90;
|
||||||
qtab[table[4 + (8 * i)]] *= 90;
|
qtab[table[4 + (8 * i)]] *= 90;
|
||||||
qtab[table[2 + (8 * i)]] *= 118;
|
qtab[table[2 + (8 * i)]] *= 118;
|
||||||
qtab[table[6 + (8 * i)]] *= 49;
|
qtab[table[6 + (8 * i)]] *= 49;
|
||||||
qtab[table[5 + (8 * i)]] *= 71;
|
qtab[table[5 + (8 * i)]] *= 71;
|
||||||
qtab[table[1 + (8 * i)]] *= 126;
|
qtab[table[1 + (8 * i)]] *= 126;
|
||||||
qtab[table[7 + (8 * i)]] *= 25;
|
qtab[table[7 + (8 * i)]] *= 25;
|
||||||
qtab[table[3 + (8 * i)]] *= 106;
|
qtab[table[3 + (8 * i)]] *= 106;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,8 +89,14 @@ final class QuantizationTable extends Segment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
// TODO: Tables...
|
||||||
|
return "DQT[]";
|
||||||
|
}
|
||||||
|
|
||||||
public static QuantizationTable read(final DataInput data, final int length) throws IOException {
|
public static QuantizationTable read(final DataInput data, final int length) throws IOException {
|
||||||
int count = 0; // TODO: Could probably use data.getPosition for this
|
int count = 2;
|
||||||
|
|
||||||
QuantizationTable table = new QuantizationTable();
|
QuantizationTable table = new QuantizationTable();
|
||||||
while (count < length) {
|
while (count < length) {
|
||||||
@ -99,7 +105,7 @@ final class QuantizationTable extends Segment {
|
|||||||
final int t = temp & 0x0F;
|
final int t = temp & 0x0F;
|
||||||
|
|
||||||
if (t > 3) {
|
if (t > 3) {
|
||||||
throw new IOException("ERROR: Quantization table ID > 3");
|
throw new IIOException("Unexpected JPEG Quantization Table Id (> 3): " + t);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.precision[t] = temp >> 4;
|
table.precision[t] = temp >> 4;
|
||||||
@ -111,7 +117,7 @@ final class QuantizationTable extends Segment {
|
|||||||
table.precision[t] = 16;
|
table.precision[t] = 16;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IOException("ERROR: Quantization table precision error");
|
throw new IIOException("Unexpected JPEG Quantization Table precision: " + table.precision[t]);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tq[t] = 1;
|
table.tq[t] = 1;
|
||||||
@ -119,31 +125,27 @@ final class QuantizationTable extends Segment {
|
|||||||
if (table.precision[t] == 8) {
|
if (table.precision[t] == 8) {
|
||||||
for (int i = 0; i < 64; i++) {
|
for (int i = 0; i < 64; i++) {
|
||||||
if (count > length) {
|
if (count > length) {
|
||||||
throw new IOException("ERROR: Quantization table format error");
|
throw new IIOException("JPEG Quantization Table format error");
|
||||||
}
|
}
|
||||||
|
|
||||||
table.quantTables[t][i] = data.readUnsignedByte();
|
table.quantTables[t][i] = data.readUnsignedByte();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// table.enhanceQuantizationTable(table.quantTables[t], table);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < 64; i++) {
|
for (int i = 0; i < 64; i++) {
|
||||||
if (count > length) {
|
if (count > length) {
|
||||||
throw new IOException("ERROR: Quantization table format error");
|
throw new IIOException("JPEG Quantization Table format error");
|
||||||
}
|
}
|
||||||
|
|
||||||
table.quantTables[t][i] = data.readUnsignedShort();
|
table.quantTables[t][i] = data.readUnsignedShort();
|
||||||
count += 2;
|
count += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// table.enhanceQuantizationTable(table.quantTables[t], table);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count != length) {
|
if (count != length) {
|
||||||
throw new IOException("ERROR: Quantization table error [count!=Lq]");
|
throw new IIOException("JPEG Quantization Table error, bad segment length: " + length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RestartInterval.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: harald.kuhr$
|
||||||
|
* @version $Id: RestartInterval.java,v 1.0 24/08/16 harald.kuhr Exp$
|
||||||
|
*/
|
||||||
|
class RestartInterval extends Segment {
|
||||||
|
final int interval;
|
||||||
|
|
||||||
|
private RestartInterval(int interval) {
|
||||||
|
super(JPEG.DRI);
|
||||||
|
this.interval = interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DRI[" + interval + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RestartInterval read(final DataInput data, final int length) throws IOException {
|
||||||
|
if (length != 4) {
|
||||||
|
throw new IIOException("Unexpected length of DRI segment: " + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RestartInterval(data.readUnsignedShort());
|
||||||
|
}
|
||||||
|
}
|
@ -38,28 +38,28 @@ import java.io.IOException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
final class Scan extends Segment {
|
final class Scan extends Segment {
|
||||||
final int selection; // Start of spectral or predictor selection
|
final int spectralSelStart; // Start of spectral or predictor selection
|
||||||
final int spectralEnd; // End of spectral selection
|
final int spectralSelEnd; // End of spectral selection
|
||||||
final int ah;
|
final int approxHigh;
|
||||||
final int al;
|
final int approxLow;
|
||||||
|
|
||||||
final Component[] components;
|
final Component[] components;
|
||||||
|
|
||||||
Scan(final Component[] components, final int selection, final int spectralEnd, final int ah, final int al) {
|
Scan(final Component[] components, final int spectralStart, final int spectralSelEnd, final int approxHigh, final int approxLow) {
|
||||||
super(JPEG.SOS);
|
super(JPEG.SOS);
|
||||||
|
|
||||||
this.components = components;
|
this.components = components;
|
||||||
this.selection = selection;
|
this.spectralSelStart = spectralStart;
|
||||||
this.spectralEnd = spectralEnd;
|
this.spectralSelEnd = spectralSelEnd;
|
||||||
this.ah = ah;
|
this.approxHigh = approxHigh;
|
||||||
this.al = al;
|
this.approxLow = approxLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"SOS[selection: %d, spectralEnd: %d, ah: %d, al: %d, components: %s]",
|
"SOS[spectralSelStart: %d, spectralSelEnd: %d, approxHigh: %d, approxLow: %d, components: %s]",
|
||||||
selection, spectralEnd, ah, al, Arrays.toString(components)
|
spectralSelStart, spectralSelEnd, approxHigh, approxLow, Arrays.toString(components)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ final class Scan extends Segment {
|
|||||||
return new Scan(components, selection, spectralEnd, temp >> 4, temp & 0x0F);
|
return new Scan(components, selection, spectralEnd, temp >> 4, temp & 0x0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
final static class Component {
|
public final static class Component {
|
||||||
final int scanCompSel; // Scan component selector
|
final int scanCompSel; // Scan component selector
|
||||||
final int acTabSel; // AC table selector
|
final int acTabSel; // AC table selector
|
||||||
final int dcTabSel; // DC table selector
|
final int dcTabSel; // DC table selector
|
||||||
|
@ -1,3 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
@ -20,15 +48,12 @@ abstract class Segment {
|
|||||||
this.marker = Validate.isTrue(marker >> 8 == 0xFF, marker, "Unknown JPEG marker: 0x%04x");
|
this.marker = Validate.isTrue(marker >> 8 == 0xFF, marker, "Unknown JPEG marker: 0x%04x");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Segment read(int marker, String identifier, int length, DataInput data) throws IOException {
|
static Segment read(int marker, String identifier, int length, DataInput data) throws IOException {
|
||||||
// TODO: Fix length inconsistencies...
|
|
||||||
// System.err.print("marker: " + marker);
|
|
||||||
// System.err.println(" length: " + length);
|
|
||||||
switch (marker) {
|
switch (marker) {
|
||||||
case JPEG.DHT:
|
case JPEG.DHT:
|
||||||
return HuffmanTable.read(data, length);
|
return HuffmanTable.read(data, length);
|
||||||
case JPEG.DQT:
|
case JPEG.DQT:
|
||||||
return QuantizationTable.read(data, length - 2);
|
return QuantizationTable.read(data, length);
|
||||||
case JPEG.SOF0:
|
case JPEG.SOF0:
|
||||||
case JPEG.SOF1:
|
case JPEG.SOF1:
|
||||||
case JPEG.SOF2:
|
case JPEG.SOF2:
|
||||||
@ -47,6 +72,9 @@ abstract class Segment {
|
|||||||
return Scan.read(data, length);
|
return Scan.read(data, length);
|
||||||
case JPEG.COM:
|
case JPEG.COM:
|
||||||
return Comment.read(data, length);
|
return Comment.read(data, length);
|
||||||
|
// TODO: JPEG.DAC
|
||||||
|
case JPEG.DRI:
|
||||||
|
return RestartInterval.read(data, length);
|
||||||
case JPEG.APP0:
|
case JPEG.APP0:
|
||||||
case JPEG.APP1:
|
case JPEG.APP1:
|
||||||
case JPEG.APP2:
|
case JPEG.APP2:
|
||||||
@ -63,8 +91,7 @@ abstract class Segment {
|
|||||||
case JPEG.APP13:
|
case JPEG.APP13:
|
||||||
case JPEG.APP14:
|
case JPEG.APP14:
|
||||||
case JPEG.APP15:
|
case JPEG.APP15:
|
||||||
return AppSegment.read(marker, identifier, data, length);
|
return Application.read(marker, identifier, data, length);
|
||||||
// TODO: JPEG.DRI?
|
|
||||||
default:
|
default:
|
||||||
return Unknown.read(marker, length, data);
|
return Unknown.read(marker, length, data);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * 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.
|
||||||
|
* * Neither the name "TwelveMonkeys" nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unknown.
|
* Represents an unknown segment in the JPEG stream.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: harald.kuhr$
|
* @author last modified by $Author: harald.kuhr$
|
||||||
@ -19,9 +47,15 @@ final class Unknown extends Segment {
|
|||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Unknown[%04x, length: %d]", marker, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
public static Segment read(int marker, int length, DataInput data) throws IOException {
|
public static Segment read(int marker, int length, DataInput data) throws IOException {
|
||||||
byte[] bytes = new byte[length - 2];
|
byte[] bytes = new byte[length - 2];
|
||||||
data.readFully(bytes);
|
data.readFully(bytes);
|
||||||
|
|
||||||
return new Unknown(marker, bytes);
|
return new Unknown(marker, bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Michael Martinez
|
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
|
||||||
* warnings, split into multiple class files, and general clean up.
|
|
||||||
*
|
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) Helmut Dersch
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
|
||||||
|
|
||||||
public class ComponentSpec {
|
|
||||||
|
|
||||||
protected int id;
|
|
||||||
protected int hSamp; // Horizontal sampling factor
|
|
||||||
protected int quantTableSel; // Quantization table destination selector
|
|
||||||
protected int vSamp; // Vertical
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Michael Martinez
|
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
|
||||||
* warnings, split into multiple class files, and general clean up.
|
|
||||||
*
|
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) Helmut Dersch
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class FrameHeader {
|
|
||||||
|
|
||||||
private ComponentSpec components[]; // Components
|
|
||||||
private int dimX; // Number of samples per line
|
|
||||||
private int dimY; // Number of lines
|
|
||||||
private int numComp; // Number of component in the frame
|
|
||||||
private int precision; // Sample Precision (from the original image)
|
|
||||||
|
|
||||||
public ComponentSpec[] getComponents() {
|
|
||||||
return components.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDimX() {
|
|
||||||
return dimX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDimY() {
|
|
||||||
return dimY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumComponents() {
|
|
||||||
return numComp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPrecision() {
|
|
||||||
return precision;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int read(final ImageInputStream data) throws IOException {
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
int length = data.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
precision = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
|
|
||||||
dimY = data.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
dimX = data.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
numComp = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
|
|
||||||
components = new ComponentSpec[numComp];
|
|
||||||
|
|
||||||
for (int i = 0; i < numComp; i++) {
|
|
||||||
if (count > length) {
|
|
||||||
throw new IOException("ERROR: frame format error");
|
|
||||||
}
|
|
||||||
|
|
||||||
int cid = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count >= length) {
|
|
||||||
throw new IOException("ERROR: frame format error [c>=Lf]");
|
|
||||||
}
|
|
||||||
|
|
||||||
int temp = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (components[i] == null) {
|
|
||||||
components[i] = new ComponentSpec();
|
|
||||||
}
|
|
||||||
|
|
||||||
components[i].id = cid;
|
|
||||||
components[i].hSamp = temp >> 4;
|
|
||||||
components[i].vSamp = temp & 0x0F;
|
|
||||||
components[i].quantTableSel = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count != length) {
|
|
||||||
throw new IOException("ERROR: frame format error [Lf!=count]");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,157 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Michael Martinez
|
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
|
||||||
* warnings, split into multiple class files, and general clean up.
|
|
||||||
*
|
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) Helmut Dersch
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class HuffmanTable {
|
|
||||||
|
|
||||||
private final int l[][][] = new int[4][2][16];
|
|
||||||
private final int th[] = new int[4]; // 1: this table is presented
|
|
||||||
private final int v[][][][] = new int[4][2][16][200]; // tables
|
|
||||||
private final int[][] tc = new int[4][2]; // 1: this table is presented
|
|
||||||
|
|
||||||
public static final int MSB = 0x80000000;
|
|
||||||
|
|
||||||
public HuffmanTable() {
|
|
||||||
tc[0][0] = 0;
|
|
||||||
tc[1][0] = 0;
|
|
||||||
tc[2][0] = 0;
|
|
||||||
tc[3][0] = 0;
|
|
||||||
tc[0][1] = 0;
|
|
||||||
tc[1][1] = 0;
|
|
||||||
tc[2][1] = 0;
|
|
||||||
tc[3][1] = 0;
|
|
||||||
th[0] = 0;
|
|
||||||
th[1] = 0;
|
|
||||||
th[2] = 0;
|
|
||||||
th[3] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int read(final ImageInputStream data, final int[][][] HuffTab) throws IOException {
|
|
||||||
int count = 0;
|
|
||||||
final int length = data.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
while (count < length) {
|
|
||||||
final int temp = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
final int t = temp & 0x0F;
|
|
||||||
if (t > 3) {
|
|
||||||
throw new IOException("ERROR: Huffman table ID > 3");
|
|
||||||
}
|
|
||||||
|
|
||||||
final int c = temp >> 4;
|
|
||||||
if (c > 2) {
|
|
||||||
throw new IOException("ERROR: Huffman table [Table class > 2 ]");
|
|
||||||
}
|
|
||||||
|
|
||||||
th[t] = 1;
|
|
||||||
tc[t][c] = 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
l[t][c][i] = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
for (int j = 0; j < l[t][c][i]; j++) {
|
|
||||||
if (count > length) {
|
|
||||||
throw new IOException("ERROR: Huffman table format error [count>Lh]");
|
|
||||||
}
|
|
||||||
v[t][c][i][j] = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count != length) {
|
|
||||||
throw new IOException("ERROR: Huffman table format error [count!=Lf]");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
for (int j = 0; j < 2; j++) {
|
|
||||||
if (tc[i][j] != 0) {
|
|
||||||
buildHuffTable(HuffTab[i][j], l[i][j], v[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build_HuffTab()
|
|
||||||
// Parameter: t table ID
|
|
||||||
// c table class ( 0 for DC, 1 for AC )
|
|
||||||
// L[i] # of codewords which length is i
|
|
||||||
// V[i][j] Huffman Value (length=i)
|
|
||||||
// Effect:
|
|
||||||
// build up HuffTab[t][c] using L and V.
|
|
||||||
private void buildHuffTable(final int tab[], final int L[], final int V[][]) throws IOException {
|
|
||||||
int currentTable, temp;
|
|
||||||
int k;
|
|
||||||
temp = 256;
|
|
||||||
k = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) { // i+1 is Code length
|
|
||||||
for (int j = 0; j < L[i]; j++) {
|
|
||||||
for (int n = 0; n < (temp >> (i + 1)); n++) {
|
|
||||||
tab[k] = V[i][j] | ((i + 1) << 8);
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; k < 256; i++, k++) {
|
|
||||||
tab[k] = i | MSB;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTable = 1;
|
|
||||||
k = 0;
|
|
||||||
|
|
||||||
for (int i = 8; i < 16; i++) { // i+1 is Code length
|
|
||||||
for (int j = 0; j < L[i]; j++) {
|
|
||||||
for (int n = 0; n < (temp >> (i - 7)); n++) {
|
|
||||||
tab[(currentTable * 256) + k] = V[i][j] | ((i + 1) << 8);
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
if (k >= 256) {
|
|
||||||
if (k > 256) {
|
|
||||||
throw new IOException("ERROR: Huffman table error(1)!");
|
|
||||||
}
|
|
||||||
k = 0;
|
|
||||||
currentTable++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Michael Martinez
|
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
|
||||||
* warnings, split into multiple class files, and general clean up.
|
|
||||||
*
|
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) Helmut Dersch
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class QuantizationTable {
|
|
||||||
|
|
||||||
private final int precision[] = new int[4]; // Quantization precision 8 or 16
|
|
||||||
private final int[] tq = new int[4]; // 1: this table is presented
|
|
||||||
|
|
||||||
protected final int quantTables[][] = new int[4][64]; // Tables
|
|
||||||
|
|
||||||
public QuantizationTable() {
|
|
||||||
tq[0] = 0;
|
|
||||||
tq[1] = 0;
|
|
||||||
tq[2] = 0;
|
|
||||||
tq[3] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int read(final ImageInputStream data, final int[] table) throws IOException {
|
|
||||||
int count = 0;
|
|
||||||
final int length = data.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
while (count < length) {
|
|
||||||
final int temp = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
final int t = temp & 0x0F;
|
|
||||||
|
|
||||||
if (t > 3) {
|
|
||||||
throw new IOException("ERROR: Quantization table ID > 3");
|
|
||||||
}
|
|
||||||
|
|
||||||
precision[t] = temp >> 4;
|
|
||||||
|
|
||||||
if (precision[t] == 0) {
|
|
||||||
precision[t] = 8;
|
|
||||||
}
|
|
||||||
else if (precision[t] == 1) {
|
|
||||||
precision[t] = 16;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IOException("ERROR: Quantization table precision error");
|
|
||||||
}
|
|
||||||
|
|
||||||
tq[t] = 1;
|
|
||||||
|
|
||||||
if (precision[t] == 8) {
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
if (count > length) {
|
|
||||||
throw new IOException("ERROR: Quantization table format error");
|
|
||||||
}
|
|
||||||
|
|
||||||
quantTables[t][i] = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
enhanceQuantizationTable(quantTables[t], table);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
if (count > length) {
|
|
||||||
throw new IOException("ERROR: Quantization table format error");
|
|
||||||
}
|
|
||||||
|
|
||||||
quantTables[t][i] = data.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
enhanceQuantizationTable(quantTables[t], table);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count != length) {
|
|
||||||
throw new IOException("ERROR: Quantization table error [count!=Lq]");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enhanceQuantizationTable(final int qtab[], final int[] table) {
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
qtab[table[(0 * 8) + i]] *= 90;
|
|
||||||
qtab[table[(4 * 8) + i]] *= 90;
|
|
||||||
qtab[table[(2 * 8) + i]] *= 118;
|
|
||||||
qtab[table[(6 * 8) + i]] *= 49;
|
|
||||||
qtab[table[(5 * 8) + i]] *= 71;
|
|
||||||
qtab[table[(1 * 8) + i]] *= 126;
|
|
||||||
qtab[table[(7 * 8) + i]] *= 25;
|
|
||||||
qtab[table[(3 * 8) + i]] *= 106;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
qtab[table[0 + (8 * i)]] *= 90;
|
|
||||||
qtab[table[4 + (8 * i)]] *= 90;
|
|
||||||
qtab[table[2 + (8 * i)]] *= 118;
|
|
||||||
qtab[table[6 + (8 * i)]] *= 49;
|
|
||||||
qtab[table[5 + (8 * i)]] *= 71;
|
|
||||||
qtab[table[1 + (8 * i)]] *= 126;
|
|
||||||
qtab[table[7 + (8 * i)]] *= 25;
|
|
||||||
qtab[table[3 + (8 * i)]] *= 106;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
qtab[i] >>= 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Michael Martinez
|
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
|
||||||
* warnings, split into multiple class files, and general clean up.
|
|
||||||
*
|
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) Helmut Dersch
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
|
||||||
|
|
||||||
public class ScanComponent {
|
|
||||||
|
|
||||||
private int acTabSel; // AC table selector
|
|
||||||
private int dcTabSel; // DC table selector
|
|
||||||
private int scanCompSel; // Scan component selector
|
|
||||||
|
|
||||||
public int getAcTabSel() {
|
|
||||||
return acTabSel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDcTabSel() {
|
|
||||||
return dcTabSel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getScanCompSel() {
|
|
||||||
return scanCompSel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAcTabSel(final int acTabSel) {
|
|
||||||
this.acTabSel = acTabSel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDcTabSel(final int dcTabSel) {
|
|
||||||
this.dcTabSel = dcTabSel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScanCompSel(final int scanCompSel) {
|
|
||||||
this.scanCompSel = scanCompSel;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 Michael Martinez
|
|
||||||
* Changes: Added support for selection values 2-7, fixed minor bugs &
|
|
||||||
* warnings, split into multiple class files, and general clean up.
|
|
||||||
*
|
|
||||||
* 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) Helmut Dersch
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class ScanHeader {
|
|
||||||
|
|
||||||
private int ah;
|
|
||||||
private int al;
|
|
||||||
private int numComp; // Number of components in the scan
|
|
||||||
private int selection; // Start of spectral or predictor selection
|
|
||||||
private int spectralEnd; // End of spectral selection
|
|
||||||
|
|
||||||
protected ScanComponent components[];
|
|
||||||
|
|
||||||
public int getAh() {
|
|
||||||
return ah;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAl() {
|
|
||||||
return al;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumComponents() {
|
|
||||||
return numComp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSelection() {
|
|
||||||
return selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSpectralEnd() {
|
|
||||||
return spectralEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAh(final int ah) {
|
|
||||||
this.ah = ah;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAl(final int al) {
|
|
||||||
this.al = al;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSelection(final int selection) {
|
|
||||||
this.selection = selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSpectralEnd(final int spectralEnd) {
|
|
||||||
this.spectralEnd = spectralEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int read(final ImageInputStream data) throws IOException {
|
|
||||||
int count = 0;
|
|
||||||
final int length = data.readUnsignedShort();
|
|
||||||
count += 2;
|
|
||||||
|
|
||||||
numComp = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
|
|
||||||
components = new ScanComponent[numComp];
|
|
||||||
|
|
||||||
for (int i = 0; i < numComp; i++) {
|
|
||||||
components[i] = new ScanComponent();
|
|
||||||
|
|
||||||
if (count > length) {
|
|
||||||
throw new IOException("ERROR: scan header format error");
|
|
||||||
}
|
|
||||||
|
|
||||||
components[i].setScanCompSel(data.readUnsignedByte());
|
|
||||||
count++;
|
|
||||||
|
|
||||||
final int temp = data.readUnsignedByte();
|
|
||||||
count++;
|
|
||||||
|
|
||||||
components[i].setDcTabSel(temp >> 4);
|
|
||||||
components[i].setAcTabSel(temp & 0x0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelection(data.readUnsignedByte());
|
|
||||||
count++;
|
|
||||||
|
|
||||||
setSpectralEnd(data.readUnsignedByte());
|
|
||||||
count++;
|
|
||||||
|
|
||||||
final int temp = data.readUnsignedByte();
|
|
||||||
setAh(temp >> 4);
|
|
||||||
setAl(temp & 0x0F);
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count != length) {
|
|
||||||
throw new IOException("ERROR: scan header format error [count!=Ns]");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user