fixed issue with PHOTO_WHITEISZERO inverted grayscale images, added support for 1-D Group 3 Fax compressed images, added support for fill order 2 for monochrome images

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3176 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Matthew Wilber
2003-05-04 21:47:42 +00:00
parent cb25a0921b
commit 83b8537ccb
5 changed files with 198 additions and 34 deletions
@@ -31,15 +31,9 @@
#include "BitReader.h"
BitReader::BitReader(StreamBuffer *pstreambuf)
BitReader::BitReader(uint16 fillOrder, StreamBuffer *pstreambuf, bool binitialRead)
{
finitStatus = B_BAD_VALUE;
fnbytesRead = 0;
fbitbuf = 0;
fcurrentbit = 0;
fpstreambuf = pstreambuf;
if (fpstreambuf)
finitStatus = ReadByte();
SetTo(fillOrder, pstreambuf, binitialRead);
}
BitReader::~BitReader()
@@ -50,6 +44,25 @@ BitReader::~BitReader()
fcurrentbit = 0;
}
status_t
BitReader::SetTo(uint16 fillOrder, StreamBuffer *pstreambuf, bool binitialRead)
{
finitStatus = B_OK;
fnbytesRead = 0;
fbitbuf = 0;
fcurrentbit = 0;
fpstreambuf = pstreambuf;
ffillOrder = fillOrder;
if (ffillOrder != 1 && ffillOrder != 2)
finitStatus = B_BAD_VALUE;
else if (!fpstreambuf)
finitStatus = B_BAD_VALUE;
else if (binitialRead)
finitStatus = ReadByte();
return finitStatus;
}
status_t
BitReader::NextBit()
{
@@ -68,7 +81,10 @@ BitReader::PeekBit()
if (!fcurrentbit && ReadByte() != B_OK)
return B_ERROR;
return (fbitbuf >> (fcurrentbit - 1)) & 1;
if (ffillOrder == 1)
return (fbitbuf >> (fcurrentbit - 1)) & 1;
else
return (fbitbuf >> (8 - fcurrentbit)) & 1;
}
status_t
@@ -37,9 +37,13 @@
class BitReader {
public:
BitReader(StreamBuffer *pstreambuf);
// Setup the BitReader to read from the given stream with the given fill order
BitReader(uint16 fillOrder, StreamBuffer *pstreambuf, bool binitialRead = true);
~BitReader();
// Change the BitReader to read from given stream with the given fill order
status_t SetTo(uint16 fillOrder, StreamBuffer *pstreambuf, bool binitialRead = true);
status_t InitCheck() const { return finitStatus; };
uint32 BytesRead() const { return fnbytesRead; };
@@ -59,6 +63,7 @@ private:
StreamBuffer *fpstreambuf;
status_t finitStatus;
uint32 fnbytesRead;
uint16 ffillOrder;
uint8 fbitbuf;
uint8 fcurrentbit;
};
@@ -395,10 +395,7 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
// will not be thrown when GetUint is called.
// (If they are not present, that is fine, but if
// they are present and have a non-default value,
// that is a problem)
if (ifd.HasField(TAG_FILL_ORDER) &&
ifd.GetUint(TAG_FILL_ORDER) != 1)
return B_NO_TRANSLATOR;
// that is a problem)
if (ifd.HasField(TAG_ORIENTATION) &&
ifd.GetUint(TAG_ORIENTATION) != 1)
return B_NO_TRANSLATOR;
@@ -420,7 +417,7 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
else
compression = ifd.GetUint(TAG_COMPRESSION);
uint16 imageType = 0, bitsPerPixel = 0;
uint16 imageType = 0, bitsPerPixel = 0, fillOrder = 1;
switch (interpretation) {
// black and white or grayscale images
case PHOTO_WHITEZERO:
@@ -429,6 +426,12 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
if (ifd.HasField(TAG_SAMPLES_PER_PIXEL) &&
ifd.GetUint(TAG_SAMPLES_PER_PIXEL) != 1)
return B_NO_TRANSLATOR;
// Only the default value for T4 Options
// is supported
if (ifd.HasField(TAG_T4_OPTIONS) &&
ifd.GetUint(TAG_T4_OPTIONS) != 0)
return B_NO_TRANSLATOR;
// default value for bits per sample is 1
if (!ifd.HasField(TAG_BITS_PER_SAMPLE) ||
@@ -437,13 +440,23 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
if (compression != COMPRESSION_NONE &&
compression != COMPRESSION_HUFFMAN &&
compression != COMPRESSION_T4 &&
compression != COMPRESSION_PACKBITS)
return B_NO_TRANSLATOR;
if (ifd.HasField(TAG_FILL_ORDER)) {
fillOrder = ifd.GetUint(TAG_FILL_ORDER);
if (fillOrder != 1 && fillOrder != 2)
return B_NO_TRANSLATOR;
}
} else if (ifd.GetUint(TAG_BITS_PER_SAMPLE) == 4 ||
ifd.GetUint(TAG_BITS_PER_SAMPLE) == 8) {
bitsPerPixel = ifd.GetUint(TAG_BITS_PER_SAMPLE);
if (ifd.HasField(TAG_FILL_ORDER) &&
ifd.GetUint(TAG_FILL_ORDER) != 1)
return B_NO_TRANSLATOR;
if (compression != COMPRESSION_NONE &&
compression != COMPRESSION_PACKBITS)
return B_NO_TRANSLATOR;
@@ -456,6 +469,9 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
// Palette color images
case PHOTO_PALETTE:
if (ifd.HasField(TAG_FILL_ORDER) &&
ifd.GetUint(TAG_FILL_ORDER) != 1)
return B_NO_TRANSLATOR;
if (compression != COMPRESSION_NONE &&
compression != COMPRESSION_PACKBITS)
return B_NO_TRANSLATOR;
@@ -478,6 +494,9 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
break;
case PHOTO_RGB:
if (ifd.HasField(TAG_FILL_ORDER) &&
ifd.GetUint(TAG_FILL_ORDER) != 1)
return B_NO_TRANSLATOR;
if (compression != COMPRESSION_NONE &&
compression != COMPRESSION_PACKBITS)
return B_NO_TRANSLATOR;
@@ -494,6 +513,9 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
break;
case PHOTO_SEPARATED:
if (ifd.HasField(TAG_FILL_ORDER) &&
ifd.GetUint(TAG_FILL_ORDER) != 1)
return B_NO_TRANSLATOR;
if (compression != COMPRESSION_NONE &&
compression != COMPRESSION_PACKBITS)
return B_NO_TRANSLATOR;
@@ -525,13 +547,16 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
rowsPerStrip = DEFAULT_ROWS_PER_STRIP;
else
rowsPerStrip = ifd.GetUint(TAG_ROWS_PER_STRIP);
stripsPerImage = (height + rowsPerStrip - 1) / rowsPerStrip;
if (rowsPerStrip == DEFAULT_ROWS_PER_STRIP)
stripsPerImage = 1;
else
stripsPerImage = (height + rowsPerStrip - 1) / rowsPerStrip;
if (ifd.GetCount(TAG_STRIP_OFFSETS) != stripsPerImage ||
ifd.GetCount(TAG_STRIP_BYTE_COUNTS) != stripsPerImage)
return B_NO_TRANSLATOR;
// return read in details if output pointer is supplied
// return read in details
pdetails->width = width;
pdetails->height = height;
pdetails->compression = compression;
@@ -540,6 +565,7 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails, bool bAllocArrays)
pdetails->interpretation = interpretation;
pdetails->bitsPerPixel = bitsPerPixel;
pdetails->imageType = imageType;
pdetails->fillOrder = fillOrder;
if (bAllocArrays) {
ifd.GetUint32Array(TAG_STRIP_OFFSETS,
@@ -823,22 +849,34 @@ tiff_to_bits(uint8 *ptiff, uint32 tifflen, uint8 *pbits, TiffDetails &details)
}
} else {
// grayscale
uint8 invert = 0;
if (details.interpretation == PHOTO_WHITEZERO)
invert = 0xff;
if (details.bitsPerPixel == 8) {
for (uint32 i = 0; i < details.width; i++) {
memset(pbits, invert + ptiff[i], 3);
pbits += 4;
if (details.interpretation == PHOTO_WHITEZERO) {
for (uint32 i = 0; i < details.width; i++) {
memset(pbits, 255 - ptiff[i], 3);
pbits += 4;
}
} else {
for (uint32 i = 0; i < details.width; i++) {
memset(pbits, ptiff[i], 3);
pbits += 4;
}
}
} else if (details.bitsPerPixel == 4) {
const uint8 mask = 0x0f;
for (uint32 i = 0; i < details.width; i++) {
uint8 values = (ptiff + (i / 2))[0];
uint8 value = (values >> (4 * (1 - (i % 2)))) & mask;
memset(pbits, invert + (value * 16), 3);
pbits += 4;
const uint8 mask = 0x0f;
if (details.interpretation == PHOTO_WHITEZERO) {
for (uint32 i = 0; i < details.width; i++) {
uint8 values = (ptiff + (i / 2))[0];
uint8 value = (values >> (4 * (1 - (i % 2)))) & mask;
memset(pbits, 255 - (value * 16), 3);
pbits += 4;
}
} else {
for (uint32 i = 0; i < details.width; i++) {
uint8 values = (ptiff + (i / 2))[0];
uint8 value = (values >> (4 * (1 - (i % 2)))) & mask;
memset(pbits, (value * 16), 3);
pbits += 4;
}
}
}
}
@@ -958,11 +996,81 @@ unpack(StreamBuffer *pstreambuf, uint8 *tiffbuffer, uint32 tiffbufferlen)
return read;
}
ssize_t
TIFFTranslator::decode_t4(BitReader &stream, TiffDetails &details,
uint8 *pbits, bool bfirstLine)
{
if (bfirstLine) {
// read in and verify end-of-line sequence
uint32 nzeros = 11;
while (nzeros--)
{
if (stream.NextBit() != 0) {
debugger("xxx");
return B_ERROR;
}
}
if (stream.NextBit() != 1) {
debugger("xxx");
return B_ERROR;
}
}
const uint8 kblack = 0x00, kwhite = 0xff;
uint8 colors[2];
if (details.interpretation == PHOTO_WHITEZERO) {
colors[0] = kwhite;
colors[1] = kblack;
} else {
colors[0] = kblack;
colors[1] = kwhite;
}
uint32 pixelswrit = 0;
DecodeTree *ptrees[2] = {fpwhiteTree, fpblackTree};
uint8 currentcolor = 0;
uint8 *pcurrentpixel = pbits;
status_t value = 0;
while (pixelswrit < details.width || value >= 64) {
value = ptrees[currentcolor]->GetValue(stream);
if (value < 0) {
debugger("value < 0");
return B_ERROR;
}
if (pixelswrit + value > details.width) {
debugger("gone past end of line");
return B_ERROR;
}
pixelswrit += value;
// covert run length to B_RGB32 pixels
uint32 pixelsleft = value;
while (pixelsleft--) {
memset(pcurrentpixel, colors[currentcolor], 3);
pcurrentpixel += 4;
}
if (value < 64)
currentcolor = 1 - currentcolor;
}
// read in end-of-line sequence
uint32 nzeros = 11;
while (nzeros--)
{
stream.NextBit();
}
stream.NextBit();
return stream.BytesRead();
}
ssize_t
TIFFTranslator::decode_huffman(StreamBuffer *pstreambuf, TiffDetails &details,
uint8 *pbits)
{
BitReader stream(pstreambuf);
BitReader stream(details.fillOrder, pstreambuf);
if (stream.InitCheck() != B_OK) {
debugger("stream init error");
return B_ERROR;
@@ -1028,7 +1136,8 @@ TIFFTranslator::translate_from_tiff(BPositionIO *inSource, ssize_t amtread,
// If TIFF uses Huffman compression, load
// trees for decoding Huffman compression
if (details.compression == COMPRESSION_HUFFMAN) {
if (details.compression == COMPRESSION_HUFFMAN ||
details.compression == COMPRESSION_T4) {
result = LoadHuffmanTrees();
if (result != B_OK)
return result;
@@ -1085,12 +1194,16 @@ TIFFTranslator::translate_from_tiff(BPositionIO *inSource, ssize_t amtread,
// buffer for making reading compressed data
// fast and convenient
StreamBuffer *pstreambuf = NULL;
BitReader bitreader(details.fillOrder, pstreambuf, false);
// this creates an invalid bitreader, but it is
// initialized properly with the SetTo() call
if (details.compression != COMPRESSION_NONE) {
pstreambuf = new StreamBuffer(inSource, 2048, false);
if (pstreambuf->InitCheck() != B_OK)
return B_NO_MEMORY;
}
bool bfirstLine = true;
for (uint32 i = 0; i < details.stripsPerImage; i++) {
uint32 read = 0;
@@ -1100,6 +1213,10 @@ TIFFTranslator::translate_from_tiff(BPositionIO *inSource, ssize_t amtread,
!pstreambuf->Seek(details.pstripOffsets[i]))
return B_NO_TRANSLATOR;
if (details.compression == COMPRESSION_T4 &&
bitreader.SetTo(details.fillOrder, pstreambuf) != B_OK)
return B_NO_TRANSLATOR;
// Read / Write one line at a time for each
// line in the strip
while (read < details.pstripByteCounts[i]) {
@@ -1121,6 +1238,19 @@ TIFFTranslator::translate_from_tiff(BPositionIO *inSource, ssize_t amtread,
ret = -1;
break;
case COMPRESSION_T4:
ret = decode_t4(bitreader, details, outbuffer,
bfirstLine);
if (ret < 1)
// break out of while loop
ret = -1;
else
ret -= read;
// unlike other decoders, decode_t4 retruns
// the total bytes read from the current
// strip
break;
case COMPRESSION_PACKBITS:
ret = unpack(pstreambuf, inbuffer, inbufferlen);
if (ret < 1)
@@ -1132,9 +1262,11 @@ TIFFTranslator::translate_from_tiff(BPositionIO *inSource, ssize_t amtread,
break;
read += ret;
if (details.compression != COMPRESSION_HUFFMAN)
if (details.compression != COMPRESSION_HUFFMAN &&
details.compression != COMPRESSION_T4)
tiff_to_bits(inbuffer, inbufferlen, outbuffer, details);
outDestination->Write(outbuffer, outbufferlen);
bfirstLine = false;
}
// If while loop was broken...
if (read < details.pstripByteCounts[i]) {
@@ -83,6 +83,7 @@ public:
uint16 interpretation;
uint16 bitsPerPixel;
uint16 imageType;
uint16 fillOrder;
};
class TIFFTranslator : public BTranslator {
@@ -137,6 +138,8 @@ private:
ssize_t decode_huffman(StreamBuffer *pstreambuf, TiffDetails &details,
uint8 *pbits);
ssize_t decode_t4(BitReader &stream, TiffDetails &details,
uint8 *pbits, bool bfirstLine);
status_t translate_from_tiff(BPositionIO *inSource, ssize_t amtread,
uint8 *read, swap_action swp, uint32 outType,
@@ -53,6 +53,7 @@
#define COMPRESSION_T4 3
#define COMPRESSION_T6 4
#define COMPRESSION_LZW 5
#define COMPRESSION_JPEG 6
#define COMPRESSION_PACKBITS 32773
#define TAG_PHOTO_INTERPRETATION 262
#define PHOTO_WHITEZERO 0
@@ -69,6 +70,13 @@
#define DEFAULT_ROWS_PER_STRIP 4294967295UL
#define TAG_STRIP_BYTE_COUNTS 279
#define TAG_PLANAR_CONFIGURATION 284
#define TAG_T4_OPTIONS 292
// (Also called Group3Options)
#define T4_2D 1
#define T4_UNCOMPRESSED 2
#define T4_FILL_BYTE_BOUNDARY 4
#define TAG_T6_OPTIONS 293
// (Also called Group4Options)
#define TAG_RESOLUTION_UNIT 296
#define TAG_COLOR_MAP 320
#define TAG_INK_SET 332