238 lines
8.0 KiB
Java
238 lines
8.0 KiB
Java
/**
|
|
* JPGImage.java
|
|
*
|
|
* The authors make NO WARRANTY or representation, either express or implied,
|
|
* with respect to this software, its quality, accuracy, merchantability, or
|
|
* fitness for a particular purpose. This software is provided "AS IS", and you,
|
|
* its user, assume the entire risk as to its quality and accuracy.
|
|
*
|
|
* This software is copyright (C) 1991-1998, Thomas G. Lane.
|
|
* All Rights Reserved except as specified below.
|
|
*
|
|
* Permission is hereby granted to use, copy, modify, and distribute this
|
|
* software (or portions thereof) for any purpose, without fee, subject to these
|
|
* conditions:
|
|
* (1) If any part of the source code for this software is distributed, then this
|
|
* README file must be included, with this copyright and no-warranty notice
|
|
* unaltered; and any additions, deletions, or changes to the original files
|
|
* must be clearly indicated in accompanying documentation.
|
|
* (2) If only executable code is distributed, then the accompanying
|
|
* documentation must state that "this software is based in part on the work of
|
|
* the Independent JPEG Group".
|
|
* (3) Permission for use of this software is granted only if the user accepts
|
|
* full responsibility for any undesirable consequences; the authors accept
|
|
* NO LIABILITY for damages of any kind.
|
|
*
|
|
* These conditions apply to any software derived from or based on the IJG code,
|
|
* not just to the unmodified library. If you use our work, you ought to
|
|
* acknowledge us.
|
|
*
|
|
* Permission is NOT granted for the use of any IJG author's name or company name
|
|
* in advertising or publicity relating to this software or products derived from
|
|
* it. This software may be referred to only as "the Independent JPEG Group's
|
|
* software".
|
|
*
|
|
* We specifically permit and encourage the use of this software as the basis of
|
|
* commercial products, provided that all warranty or liability claims are
|
|
* assumed by the product vendor.
|
|
*/
|
|
|
|
package com.pdfjet;
|
|
|
|
import java.io.*;
|
|
|
|
|
|
/**
|
|
* Used to embed JPG images in the PDF document.
|
|
*
|
|
*/
|
|
class JPGImage {
|
|
|
|
static final char M_SOF0 = (char) 0x00C0; // Start Of Frame N
|
|
static final char M_SOF1 = (char) 0x00C1; // N indicates which compression process
|
|
static final char M_SOF2 = (char) 0x00C2; // Only SOF0-SOF2 are now in common use
|
|
static final char M_SOF3 = (char) 0x00C3;
|
|
static final char M_SOF5 = (char) 0x00C5; // NB: codes C4 and CC are NOT SOF markers
|
|
static final char M_SOF6 = (char) 0x00C6;
|
|
static final char M_SOF7 = (char) 0x00C7;
|
|
static final char M_SOF9 = (char) 0x00C9;
|
|
static final char M_SOF10 = (char) 0x00CA;
|
|
static final char M_SOF11 = (char) 0x00CB;
|
|
static final char M_SOF13 = (char) 0x00CD;
|
|
static final char M_SOF14 = (char) 0x00CE;
|
|
static final char M_SOF15 = (char) 0x00CF;
|
|
|
|
int width;
|
|
int height;
|
|
long size;
|
|
int colorComponents;
|
|
byte[] data;
|
|
|
|
|
|
public JPGImage(InputStream inputStream) throws Exception {
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
byte[] buf = new byte[2048];
|
|
int count;
|
|
while ((count = inputStream.read(buf, 0, buf.length)) > 0) {
|
|
baos.write(buf, 0, count);
|
|
}
|
|
inputStream.close();
|
|
data = baos.toByteArray();
|
|
readJPGImage(new ByteArrayInputStream(data));
|
|
}
|
|
|
|
|
|
protected int getWidth() {
|
|
return this.width;
|
|
}
|
|
|
|
|
|
protected int getHeight() {
|
|
return this.height;
|
|
}
|
|
|
|
|
|
protected long getFileSize() {
|
|
return this.size;
|
|
}
|
|
|
|
|
|
protected int getColorComponents() {
|
|
return this.colorComponents;
|
|
}
|
|
|
|
|
|
protected byte[] getData() {
|
|
return this.data;
|
|
}
|
|
|
|
|
|
private void readJPGImage(InputStream is) throws Exception {
|
|
char ch1 = (char) is.read();
|
|
char ch2 = (char) is.read();
|
|
size += 2;
|
|
if (ch1 == 0x00FF && ch2 == 0x00D8) {
|
|
boolean foundSOFn = false;
|
|
while (true) {
|
|
char ch = nextMarker(is);
|
|
switch (ch) {
|
|
// Note that marker codes 0xC4, 0xC8, 0xCC are not,
|
|
// and must not be treated as SOFn. C4 in particular
|
|
// is actually DHT.
|
|
case M_SOF0: // Baseline
|
|
case M_SOF1: // Extended sequential, Huffman
|
|
case M_SOF2: // Progressive, Huffman
|
|
case M_SOF3: // Lossless, Huffman
|
|
case M_SOF5: // Differential sequential, Huffman
|
|
case M_SOF6: // Differential progressive, Huffman
|
|
case M_SOF7: // Differential lossless, Huffman
|
|
case M_SOF9: // Extended sequential, arithmetic
|
|
case M_SOF10: // Progressive, arithmetic
|
|
case M_SOF11: // Lossless, arithmetic
|
|
case M_SOF13: // Differential sequential, arithmetic
|
|
case M_SOF14: // Differential progressive, arithmetic
|
|
case M_SOF15: // Differential lossless, arithmetic
|
|
// Skip 3 bytes to get to the image height and width
|
|
is.read();
|
|
is.read();
|
|
is.read();
|
|
size += 3;
|
|
height = readTwoBytes(is);
|
|
width = readTwoBytes(is);
|
|
colorComponents = is.read();
|
|
size++;
|
|
foundSOFn = true;
|
|
break;
|
|
|
|
default:
|
|
skipVariable(is);
|
|
break;
|
|
}
|
|
|
|
if (foundSOFn) {
|
|
while (is.read() != -1) {
|
|
size++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
throw new Exception();
|
|
}
|
|
// System.out.println("size == " + size);
|
|
}
|
|
|
|
|
|
private int readTwoBytes(InputStream is) throws Exception {
|
|
int value = is.read();
|
|
value <<= 8;
|
|
value |= is.read();
|
|
size += 2;
|
|
return value;
|
|
}
|
|
|
|
|
|
// Find the next JPEG marker and return its marker code.
|
|
// We expect at least one FF byte, possibly more if the compressor
|
|
// used FFs to pad the file.
|
|
// There could also be non-FF garbage between markers. The treatment
|
|
// of such garbage is unspecified; we choose to skip over it but
|
|
// emit a warning msg.
|
|
// NB: this routine must not be used after seeing SOS marker, since
|
|
// it will not deal correctly with FF/00 sequences in the compressed
|
|
// image data...
|
|
private char nextMarker(InputStream is) throws Exception {
|
|
int discarded_bytes = 0;
|
|
char ch = ' ';
|
|
|
|
// Find 0xFF byte; count and skip any non-FFs.
|
|
ch = (char) is.read();
|
|
size++;
|
|
while (ch != 0x00FF) {
|
|
discarded_bytes++;
|
|
ch = (char) is.read();
|
|
size++;
|
|
}
|
|
|
|
// Get marker code byte, swallowing any duplicate FF bytes.
|
|
// Extra FFs are legal as pad bytes, so don't count them in discarded_bytes.
|
|
do {
|
|
ch = (char) is.read();
|
|
size++;
|
|
} while (ch == 0x00FF);
|
|
|
|
if (discarded_bytes != 0) {
|
|
throw new Exception();
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
|
|
// Most types of marker are followed by a variable-length parameter
|
|
// segment. This routine skips over the parameters for any marker we
|
|
// don't otherwise want to process.
|
|
// Note that we MUST skip the parameter segment explicitly in order
|
|
// not to be fooled by 0xFF bytes that might appear within the
|
|
// parameter segment such bytes do NOT introduce new markers.
|
|
private void skipVariable(InputStream is) throws Exception {
|
|
// Get the marker parameter length count
|
|
int length = readTwoBytes(is);
|
|
|
|
// Length includes itself, so must be at least 2
|
|
if (length < 2) {
|
|
throw new Exception();
|
|
}
|
|
length -= 2;
|
|
|
|
// Skip over the remaining bytes
|
|
while (length > 0) {
|
|
is.read();
|
|
size++;
|
|
length--;
|
|
}
|
|
}
|
|
|
|
} // End of JPGImage.java
|