mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 20:15:28 -04:00
CCITT Fax writer: adjust formatting and write finishing bytes on last row instead of on stream closing
This commit is contained in:
parent
585b5faa62
commit
c8621439c0
@ -28,14 +28,14 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.tiff;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
/**
|
||||
* CCITT Modified Huffman RLE, Group 3 (T4) and Group 4 (T6) fax compression.
|
||||
*
|
||||
*
|
||||
* @author <a href="mailto:mail@schmidor.de">Oliver Schmidtmer</a>
|
||||
* @author last modified by $Author$
|
||||
* @version $Id$
|
||||
@ -46,9 +46,11 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
private final byte[] inputBuffer;
|
||||
private final int inputBufferLength;
|
||||
private int columns;
|
||||
private int rows;
|
||||
|
||||
private int[] changesCurrentRow;
|
||||
private int[] changesReferenceRow;
|
||||
private int currentRow = 0;
|
||||
private int changesCurrentRowLength = 0;
|
||||
private int changesReferenceRowLength = 0;
|
||||
private byte outputBuffer = 0;
|
||||
@ -60,26 +62,27 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
private boolean optionUncompressed;
|
||||
private OutputStream stream;
|
||||
|
||||
public CCITTFaxEncoderStream(final OutputStream stream, final int columns, final int type, final int fillOrder,
|
||||
final long options) {
|
||||
public CCITTFaxEncoderStream(final OutputStream stream, final int columns, final int rows, final int type, final int fillOrder,
|
||||
final long options) {
|
||||
|
||||
this.stream = stream;
|
||||
this.type = type;
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
this.fillOrder = fillOrder;
|
||||
|
||||
this.changesReferenceRow = new int[columns];
|
||||
this.changesCurrentRow = new int[columns];
|
||||
|
||||
switch (type) {
|
||||
case TIFFExtension.COMPRESSION_CCITT_T4:
|
||||
optionG32D = (options & TIFFExtension.GROUP3OPT_2DENCODING) != 0;
|
||||
optionG3Fill = (options & TIFFExtension.GROUP3OPT_FILLBITS) != 0;
|
||||
optionUncompressed = (options & TIFFExtension.GROUP3OPT_UNCOMPRESSED) != 0;
|
||||
break;
|
||||
case TIFFExtension.COMPRESSION_CCITT_T6:
|
||||
optionUncompressed = (options & TIFFExtension.GROUP4OPT_UNCOMPRESSED) != 0;
|
||||
break;
|
||||
case TIFFExtension.COMPRESSION_CCITT_T4:
|
||||
optionG32D = (options & TIFFExtension.GROUP3OPT_2DENCODING) != 0;
|
||||
optionG3Fill = (options & TIFFExtension.GROUP3OPT_FILLBITS) != 0;
|
||||
optionUncompressed = (options & TIFFExtension.GROUP3OPT_UNCOMPRESSED) != 0;
|
||||
break;
|
||||
case TIFFExtension.COMPRESSION_CCITT_T6:
|
||||
optionUncompressed = (options & TIFFExtension.GROUP4OPT_UNCOMPRESSED) != 0;
|
||||
break;
|
||||
}
|
||||
|
||||
inputBufferLength = (columns + 7) / 8;
|
||||
@ -107,15 +110,11 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (type == TIFFExtension.COMPRESSION_CCITT_T6) {
|
||||
writeEOL();
|
||||
writeEOL();
|
||||
}
|
||||
fill();
|
||||
stream.close();
|
||||
}
|
||||
|
||||
private void encodeRow() throws IOException {
|
||||
currentRow++;
|
||||
int[] tmp = changesReferenceRow;
|
||||
changesReferenceRow = changesCurrentRow;
|
||||
changesCurrentRow = tmp;
|
||||
@ -127,7 +126,7 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
while (index < columns) {
|
||||
int byteIndex = index / 8;
|
||||
int bit = index % 8;
|
||||
if ((((inputBuffer[byteIndex] >> (7 - bit)) & 1) == 1) != (!white)) {
|
||||
if ((((inputBuffer[byteIndex] >> (7 - bit)) & 1) == 1) == (white)) {
|
||||
changesCurrentRow[changesCurrentRowLength] = index;
|
||||
changesCurrentRowLength++;
|
||||
white = !white;
|
||||
@ -136,15 +135,23 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE:
|
||||
encodeRowType2();
|
||||
break;
|
||||
case TIFFExtension.COMPRESSION_CCITT_T4:
|
||||
encodeRowType4();
|
||||
break;
|
||||
case TIFFExtension.COMPRESSION_CCITT_T6:
|
||||
encodeRowType6();
|
||||
break;
|
||||
case TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE:
|
||||
encodeRowType2();
|
||||
break;
|
||||
case TIFFExtension.COMPRESSION_CCITT_T4:
|
||||
encodeRowType4();
|
||||
break;
|
||||
case TIFFExtension.COMPRESSION_CCITT_T6:
|
||||
encodeRowType6();
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentRow == rows) {
|
||||
if (type == TIFFExtension.COMPRESSION_CCITT_T6) {
|
||||
writeEOL();
|
||||
writeEOL();
|
||||
}
|
||||
fill();
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,11 +168,13 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
if (changesReferenceRowLength == 0) {
|
||||
write(1, 1);
|
||||
encode1D();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
write(0, 1);
|
||||
encode2D();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
encode1D();
|
||||
}
|
||||
if (optionG3Fill) {
|
||||
@ -190,7 +199,7 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
}
|
||||
|
||||
private int[] getNextChanges(int pos) {
|
||||
int[] result = new int[] { columns, columns };
|
||||
int[] result = new int[] {columns, columns};
|
||||
for (int i = 0; i < changesCurrentRowLength; i++) {
|
||||
if (pos < changesCurrentRow[i]) {
|
||||
result[0] = changesCurrentRow[i];
|
||||
@ -211,7 +220,8 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
if (nonterm >= codes.length) {
|
||||
write(codes[codes.length - 1].code, codes[codes.length - 1].length);
|
||||
nonterm -= codes.length - 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
write(codes[nonterm - 1].code, codes[nonterm - 1].length);
|
||||
nonterm = 0;
|
||||
}
|
||||
@ -234,37 +244,39 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
// PMODE
|
||||
write(1, 4);
|
||||
index = nextRefs[1];
|
||||
} else if (difference > 3 || difference < -3) {
|
||||
}
|
||||
else if (difference > 3 || difference < -3) {
|
||||
// HMODE
|
||||
write(1, 3);
|
||||
writeRun(nextChanges[0] - index, white);
|
||||
writeRun(nextChanges[1] - nextChanges[0], !white);
|
||||
index = nextChanges[1];
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// VMODE
|
||||
switch (difference) {
|
||||
case 0:
|
||||
write(1, 1);
|
||||
break;
|
||||
case 1:
|
||||
write(3, 3);
|
||||
break;
|
||||
case 2:
|
||||
write(3, 6);
|
||||
break;
|
||||
case 3:
|
||||
write(3, 7);
|
||||
break;
|
||||
case -1:
|
||||
write(2, 3);
|
||||
break;
|
||||
case -2:
|
||||
write(2, 6);
|
||||
break;
|
||||
case -3:
|
||||
write(2, 7);
|
||||
break;
|
||||
case 0:
|
||||
write(1, 1);
|
||||
break;
|
||||
case 1:
|
||||
write(3, 3);
|
||||
break;
|
||||
case 2:
|
||||
write(3, 6);
|
||||
break;
|
||||
case 3:
|
||||
write(3, 7);
|
||||
break;
|
||||
case -1:
|
||||
write(2, 3);
|
||||
break;
|
||||
case -2:
|
||||
write(2, 6);
|
||||
break;
|
||||
case -3:
|
||||
write(2, 7);
|
||||
break;
|
||||
}
|
||||
white = !white;
|
||||
index = nextRefs[0] + difference;
|
||||
@ -273,7 +285,7 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
}
|
||||
|
||||
private int[] getNextRefChanges(int a0, boolean white) {
|
||||
int[] result = new int[] { columns, columns };
|
||||
int[] result = new int[] {columns, columns};
|
||||
for (int i = (white ? 0 : 1); i < changesReferenceRowLength; i += 2) {
|
||||
if (changesReferenceRow[i] > a0) {
|
||||
result[0] = changesReferenceRow[i];
|
||||
@ -292,7 +304,8 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
boolean codeBit = ((code >> (codeLength - i - 1)) & 1) == 1;
|
||||
if (fillOrder == TIFFBaseline.FILL_LEFT_TO_RIGHT) {
|
||||
outputBuffer |= (codeBit ? 1 << (7 - ((outputBufferBitLength) % 8)) : 0);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
outputBuffer |= (codeBit ? 1 << (((outputBufferBitLength) % 8)) : 0);
|
||||
}
|
||||
outputBufferBitLength++;
|
||||
@ -355,7 +368,8 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
|
||||
if (value < 64) {
|
||||
WHITE_TERMINATING_CODES[value] = new Code(code, bitLength);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
WHITE_NONTERMINATING_CODES[(value / 64) - 1] = new Code(code, bitLength);
|
||||
}
|
||||
}
|
||||
@ -371,7 +385,8 @@ public class CCITTFaxEncoderStream extends OutputStream {
|
||||
|
||||
if (value < 64) {
|
||||
BLACK_TERMINATING_CODES[value] = new Code(code, bitLength);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
BLACK_NONTERMINATING_CODES[(value / 64) - 1] = new Code(code, bitLength);
|
||||
}
|
||||
}
|
||||
|
@ -28,22 +28,15 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.tiff;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.twelvemonkeys.imageio.plugins.tiff.CCITTFaxEncoderStream.Code;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.twelvemonkeys.imageio.plugins.tiff.CCITTFaxEncoderStream.Code;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* CCITTFaxEncoderStreamTest
|
||||
@ -122,7 +115,7 @@ public class CCITTFaxEncoderStreamTest {
|
||||
byte[] imageData = ((DataBufferByte) image.getData().getDataBuffer()).getData();
|
||||
byte[] redecodedData = new byte[imageData.length];
|
||||
ByteArrayOutputStream imageOutput = new ByteArrayOutputStream();
|
||||
OutputStream outputSteam = new CCITTFaxEncoderStream(imageOutput, 6, type, fillOrder, options);
|
||||
OutputStream outputSteam = new CCITTFaxEncoderStream(imageOutput, 6, 4, type, fillOrder, options);
|
||||
outputSteam.write(imageData);
|
||||
outputSteam.close();
|
||||
byte[] encodedData = imageOutput.toByteArray();
|
||||
|
Loading…
x
Reference in New Issue
Block a user