diff --git a/src/add-ons/translators/tifftranslator/BitReader.cpp b/src/add-ons/translators/tifftranslator/BitReader.cpp new file mode 100644 index 0000000000..0610d484e1 --- /dev/null +++ b/src/add-ons/translators/tifftranslator/BitReader.cpp @@ -0,0 +1,83 @@ +/*****************************************************************************/ +// BitReader +// Written by Michael Wilber, OBOS Translation Kit Team +// +// BitReader.cpp +// +// Wrapper class for StreamBuffer to make it convenient to read 1 bit at +// a time +// +// +// Copyright (c) 2003 OpenBeOS Project +// +// 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. +/*****************************************************************************/ + +#include "BitReader.h" + +BitReader::BitReader(StreamBuffer *pstreambuf) +{ + finitStatus = B_BAD_VALUE; + fnbytesRead = 0; + fbitbuf = 0; + fcurrentbit = 0; + fpstreambuf = pstreambuf; + if (fpstreambuf) + finitStatus = ReadByte(); +} + +BitReader::~BitReader() +{ + finitStatus = B_ERROR; + fpstreambuf = NULL; + fbitbuf = 0; + fcurrentbit = 0; +} + +status_t +BitReader::NextBit() +{ + status_t result; + result = PeekBit(); + if (result >= 0) + fcurrentbit--; + + return result; +} + +status_t +BitReader::PeekBit() +{ + // if fcurrentbit is zero, read in next byte + if (!fcurrentbit && ReadByte() != B_OK) + return B_ERROR; + + return (fbitbuf >> (fcurrentbit - 1)) & 1; +} + +status_t +BitReader::ReadByte() +{ + if (fpstreambuf->Read(&fbitbuf, 1) != 1) + return B_ERROR; + + fnbytesRead++; + fcurrentbit = 8; + return B_OK; +} diff --git a/src/add-ons/translators/tifftranslator/BitReader.h b/src/add-ons/translators/tifftranslator/BitReader.h new file mode 100644 index 0000000000..36c93932dd --- /dev/null +++ b/src/add-ons/translators/tifftranslator/BitReader.h @@ -0,0 +1,66 @@ +/*****************************************************************************/ +// BitReader +// Written by Michael Wilber, OBOS Translation Kit Team +// +// BitReader.h +// +// Wrapper class for StreamBuffer to make it convenient to read 1 bit at +// a time +// +// +// Copyright (c) 2003 OpenBeOS Project +// +// 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. +/*****************************************************************************/ + + +#ifndef BIT_READER_H +#define BIT_READER_H + +#include "StreamBuffer.h" + +class BitReader { +public: + BitReader(StreamBuffer *pstreambuf); + ~BitReader(); + + status_t InitCheck() const { return finitStatus; }; + + uint32 BytesRead() const { return fnbytesRead; }; + + // return the current bit and increment the position + // If the result is negative, an error occured + status_t NextBit(); + + // return the current bit without incrementing the position + // (if buffer is empty, will read next byte in StreamBuffer) + // If the result is negative, an error occured + status_t PeekBit(); + +private: + status_t ReadByte(); + + StreamBuffer *fpstreambuf; + status_t finitStatus; + uint32 fnbytesRead; + uint8 fbitbuf; + uint8 fcurrentbit; +}; + +#endif diff --git a/src/add-ons/translators/tifftranslator/DecodeTree.cpp b/src/add-ons/translators/tifftranslator/DecodeTree.cpp index 6fb4053fec..833c8c1477 100644 --- a/src/add-ons/translators/tifftranslator/DecodeTree.cpp +++ b/src/add-ons/translators/tifftranslator/DecodeTree.cpp @@ -30,14 +30,234 @@ #include "DecodeTree.h" -DecodeTree::DecodeTree() +// Encodings used to populate +// the decode trees +const HuffmanEncoding g_encWhiteTerm[] = { + {0, 0x35, 8}, // "00110101" + {1, 0x07, 6}, // "000111" + {2, 0x07, 4}, // "0111" + {3, 0x08, 4}, // "1000" + {4, 0x0b, 4}, // "1011" + {5, 0x0c, 4}, // "1100" + {6, 0x0e, 4}, // "1110" + {7, 0x0f, 4}, // "1111" + {8, 0x13, 5}, // "10011" + {9, 0x14, 5}, // "10100" + {10, 0x07, 5}, // "00111" + {11, 0x08, 5}, // "01000" + {12, 0x08, 6}, // "001000" + {13, 0x03, 6}, // "000011" + {14, 0x34, 6}, // "110100" + {15, 0x35, 6}, // "110101" + {16, 0x2a, 6}, // "101010" + {17, 0x2b, 6}, // "101011" + {18, 0x27, 7}, // "0100111" + {19, 0x0c, 7}, // "0001100" + {20, 0x08, 7}, // "0001000" + {21, 0x17, 7}, // "0010111" + {22, 0x03, 7}, // "0000011" + {23, 0x04, 7}, // "0000100" + {24, 0x28, 7}, // "0101000" + {25, 0x2b, 7}, // "0101011" + {26, 0x13, 7}, // "0010011" + {27, 0x24, 7}, // "0100100" + {28, 0x18, 7}, // "0011000" + {29, 0x02, 8}, // "00000010" + {30, 0x03, 8}, // "00000011" + {31, 0x1a, 8}, // "00011010" + {32, 0x1b, 8}, // "00011011" + {33, 0x12, 8}, // "00010010" + {34, 0x13, 8}, // "00010011" + {35, 0x14, 8}, // "00010100" + {36, 0x15, 8}, // "00010101" + {37, 0x16, 8}, // "00010110" + {38, 0x17, 8}, // "00010111" + {39, 0x28, 8}, // "00101000" + {40, 0x29, 8}, // "00101001" + {41, 0x2a, 8}, // "00101010" + {42, 0x2b, 8}, // "00101011" + {43, 0x2c, 8}, // "00101100" + {44, 0x2d, 8}, // "00101101" + {45, 0x04, 8}, // "00000100" + {46, 0x05, 8}, // "00000101" + {47, 0x0a, 8}, // "00001010" + {48, 0x0b, 8}, // "00001011" + {49, 0x52, 8}, // "01010010" + {50, 0x53, 8}, // "01010011" + {51, 0x54, 8}, // "01010100" + {52, 0x55, 8}, // "01010101" + {53, 0x24, 8}, // "00100100" + {54, 0x25, 8}, // "00100101" + {55, 0x58, 8}, // "01011000" + {56, 0x59, 8}, // "01011001" + {57, 0x5a, 8}, // "01011010" + {58, 0x5b, 8}, // "01011011" + {59, 0x4a, 8}, // "01001010" + {60, 0x4b, 8}, // "01001011" + {61, 0x32, 8}, // "00110010" + {62, 0x33, 8}, // "00110011" + {63, 0x34, 8}, // "00110100" +}; // g_encWhiteTerm + +const HuffmanEncoding g_encWhiteMakeup[] = { + {64, 0x1b, 5}, // "11011" + {128, 0x12, 5}, // "10010" + {192, 0x17, 6}, // "010111" + {256, 0x37, 7}, // "0110111" + {320, 0x36, 8}, // "00110110" + {384, 0x37, 8}, // "00110111" + {448, 0x64, 8}, // "01100100" + {512, 0x65, 8}, // "01100101" + {576, 0x68, 8}, // "01101000" + {640, 0x67, 8}, // "01100111" + {704, 0xcc, 9}, // "011001100" + {768, 0xcd, 9}, // "011001101" + {832, 0xd2, 9}, // "011010010" + {896, 0xd3, 9}, // "011010011" + {960, 0xd4, 9}, // "011010100" + {1024, 0xd5, 9}, // "011010101" + {1088, 0xd6, 9}, // "011010110" + {1152, 0xd7, 9}, // "011010111" + {1216, 0xd8, 9}, // "011011000" + {1280, 0xd9, 9}, // "011011001" + {1344, 0xda, 9}, // "011011010" + {1408, 0xdb, 9}, // "011011011" + {1472, 0x98, 9}, // "010011000" + {1536, 0x99, 9}, // "010011001" + {1600, 0x9a, 9}, // "010011010" + {1664, 0x18, 6}, // "011000" + {1728, 0x9b, 9}, // "010011011" +}; // g_encWhiteMakeup + +const HuffmanEncoding g_encBlackTerm[] = { + {0, 0x37, 10}, // "0000110111" + {1, 0x02, 3}, // "010" + {2, 0x03, 2}, // "11" + {3, 0x02, 2}, // "10" + {4, 0x03, 3}, // "011" + {5, 0x03, 4}, // "0011" + {6, 0x02, 4}, // "0010" + {7, 0x03, 5}, // "00011" + {8, 0x05, 6}, // "000101" + {9, 0x04, 6}, // "000100" + {10, 0x04, 7}, // "0000100" + {11, 0x05, 7}, // "0000101" + {12, 0x07, 7}, // "0000111" + {13, 0x04, 8}, // "00000100" + {14, 0x07, 8}, // "00000111" + {15, 0x18, 9}, // "000011000" + {16, 0x17, 10}, // "0000010111" + {17, 0x18, 10}, // "0000011000" + {18, 0x08, 10}, // "0000001000" + {19, 0x67, 11}, // "00001100111" + {20, 0x68, 11}, // "00001101000" + {21, 0x6c, 11}, // "00001101100" + {22, 0x37, 11}, // "00000110111" + {23, 0x28, 11}, // "00000101000" + {24, 0x17, 11}, // "00000010111" + {25, 0x18, 11}, // "00000011000" + {26, 0xca, 12}, // "000011001010" + {27, 0xcb, 12}, // "000011001011" + {28, 0xcc, 12}, // "000011001100" + {29, 0xcd, 12}, // "000011001101" + {30, 0x68, 12}, // "000001101000" + {31, 0x69, 12}, // "000001101001" + {32, 0x6a, 12}, // "000001101010" + {33, 0x6b, 12}, // "000001101011" + {34, 0xd2, 12}, // "000011010010" + {35, 0xd3, 12}, // "000011010011" + {36, 0xd4, 12}, // "000011010100" + {37, 0xd5, 12}, // "000011010101" + {38, 0xd6, 12}, // "000011010110" + {39, 0xd7, 12}, // "000011010111" + {40, 0x6c, 12}, // "000001101100" + {41, 0x6d, 12}, // "000001101101" + {42, 0xda, 12}, // "000011011010" + {43, 0xdb, 12}, // "000011011011" + {44, 0x54, 12}, // "000001010100" + {45, 0x55, 12}, // "000001010101" + {46, 0x56, 12}, // "000001010110" + {47, 0x57, 12}, // "000001010111" + {48, 0x64, 12}, // "000001100100" + {49, 0x65, 12}, // "000001100101" + {50, 0x52, 12}, // "000001010010" + {51, 0x53, 12}, // "000001010011" + {52, 0x24, 12}, // "000000100100" + {53, 0x37, 12}, // "000000110111" + {54, 0x38, 12}, // "000000111000" + {55, 0x27, 12}, // "000000100111" + {56, 0x28, 12}, // "000000101000" + {57, 0x58, 12}, // "000001011000" + {58, 0x59, 12}, // "000001011001" + {59, 0x2b, 12}, // "000000101011" + {60, 0x2c, 12}, // "000000101100" + {61, 0x5a, 12}, // "000001011010" + {62, 0x66, 12}, // "000001100110" + {63, 0x67, 12}, // "000001100111" +}; // g_encBlackTerm + +const HuffmanEncoding g_encBlackMakeup[] = { + {64, 0x0f, 10}, // "0000001111" + {128, 0xc8, 12}, // "000011001000" + {192, 0xc9, 12}, // "000011001001" + {256, 0x5b, 12}, // "000001011011" + {320, 0x33, 12}, // "000000110011" + {384, 0x34, 12}, // "000000110100" + {448, 0x35, 12}, // "000000110101" + {512, 0x6c, 13}, // "0000001101100" + {576, 0x6d, 13}, // "0000001101101" + {640, 0x4a, 13}, // "0000001001010" + {704, 0x4b, 13}, // "0000001001011" + {768, 0x4c, 13}, // "0000001001100" + {832, 0x4d, 13}, // "0000001001101" + {896, 0x72, 13}, // "0000001110010" + {960, 0x73, 13}, // "0000001110011" + {1024, 0x74, 13}, // "0000001110100" + {1088, 0x75, 13}, // "0000001110101" + {1152, 0x76, 13}, // "0000001110110" + {1216, 0x77, 13}, // "0000001110111" + {1280, 0x52, 13}, // "0000001010010" + {1344, 0x53, 13}, // "0000001010011" + {1408, 0x54, 13}, // "0000001010100" + {1472, 0x55, 13}, // "0000001010101" + {1536, 0x5a, 13}, // "0000001011010" + {1600, 0x5b, 13}, // "0000001011011" + {1664, 0x64, 13}, // "0000001100100" + {1728, 0x65, 13}, // "0000001100101" +}; // g_encBlackMakeup + +const HuffmanEncoding g_encBothMakeup[] = { + {1792, 0x08, 11}, // "00000001000" + {1856, 0x0c, 11}, // "00000001100" + {1920, 0x0d, 11}, // "00000001101" + {1984, 0x12, 12}, // "000000010010" + {2048, 0x13, 12}, // "000000010011" + {2112, 0x14, 12}, // "000000010100" + {2176, 0x15, 12}, // "000000010101" + {2240, 0x16, 12}, // "000000010110" + {2304, 0x17, 12}, // "000000010111" + {2368, 0x1c, 12}, // "000000011100" + {2432, 0x1d, 12}, // "000000011101" + {2496, 0x1e, 12}, // "000000011110" + {2560, 0x1f, 12}, // "000000011111" +}; // g_encBothMakeup + + +DecodeTree::DecodeTree(bool bwhite) { + finitStatus = B_ERROR; fptop = new DecodeNode; if (fptop) { fptop->value = -1; fptop->branches[0] = NULL; fptop->branches[1] = NULL; - } + + if (bwhite) + finitStatus = LoadWhiteEncodings(); + else + finitStatus = LoadBlackEncodings(); + } else + finitStatus = B_NO_MEMORY; } void @@ -58,11 +278,65 @@ DecodeTree::~DecodeTree() } } +status_t +DecodeTree::LoadBlackEncodings() +{ + status_t result = B_ERROR; + + result = AddEncodings(g_encBlackTerm, + sizeof(g_encBlackTerm) / sizeof(HuffmanEncoding)); + if (result != B_OK) + return result; + + result = AddEncodings(g_encBlackMakeup, + sizeof(g_encBlackMakeup) / sizeof(HuffmanEncoding)); + if (result != B_OK) + return result; + + result = AddEncodings(g_encBothMakeup, + sizeof(g_encBothMakeup) / sizeof(HuffmanEncoding)); + + return result; +} + +status_t +DecodeTree::LoadWhiteEncodings() +{ + status_t result = B_ERROR; + + result = AddEncodings(g_encWhiteTerm, + sizeof(g_encWhiteTerm) / sizeof(HuffmanEncoding)); + if (result != B_OK) + return result; + + result = AddEncodings(g_encWhiteMakeup, + sizeof(g_encWhiteMakeup) / sizeof(HuffmanEncoding)); + if (result != B_OK) + return result; + + result = AddEncodings(g_encBothMakeup, + sizeof(g_encBothMakeup) / sizeof(HuffmanEncoding)); + + return result; +} + +status_t +DecodeTree::AddEncodings(const HuffmanEncoding *pencs, uint32 length) +{ + status_t result = B_ERROR; + for (uint32 i = 0; i < length; i++) { + result = AddEncoding(pencs[i].encoding, pencs[i].length, + pencs[i].value); + if (result != B_OK) + break; + } + + return result; +} + status_t DecodeTree::AddEncoding(uint16 encoding, uint8 length, uint16 value) { - if (!fptop) - return B_NO_MEMORY; if (!length || length > 16) return B_BAD_VALUE; @@ -101,32 +375,24 @@ DecodeTree::AddEncoding(uint16 encoding, uint8 length, uint16 value) } status_t -DecodeTree::GetValue(uint16 encdata, uint8 nbits, uint8 &bitsread) const +DecodeTree::GetValue(BitReader &stream) const { - if (!fptop) - return B_NO_MEMORY; - if (!nbits || nbits > 16) - return B_BAD_VALUE; + if (InitCheck() != B_OK) + return InitCheck(); - uint32 branch; + status_t branch; DecodeNode *pnode = fptop; - bitsread = 0; - while (bitsread < nbits) { - - branch = (encdata >> (16 - (bitsread + 1))) & 1; - if (!pnode->branches[branch]) - // if I can't go any further, I've either successfully - // decoded some bits or I'm returning -1 + while (pnode) { + branch = stream.NextBit(); + if (branch < 0) + return branch; + + pnode = pnode->branches[branch]; + if (!pnode) + return B_ERROR; + else if (pnode->value > -1) return pnode->value; - else { - pnode = pnode->branches[branch]; - bitsread++; - if (bitsread == nbits) - return pnode->value; - } } return B_ERROR; } - - diff --git a/src/add-ons/translators/tifftranslator/DecodeTree.h b/src/add-ons/translators/tifftranslator/DecodeTree.h index 38d9dd204b..6cdf7bf949 100644 --- a/src/add-ons/translators/tifftranslator/DecodeTree.h +++ b/src/add-ons/translators/tifftranslator/DecodeTree.h @@ -32,7 +32,17 @@ #define DECODE_TREE_H #include +#include "BitReader.h" +// structure used to populate +// the decode trees +struct HuffmanEncoding { + uint16 value; + uint8 encoding; + uint8 length; +}; + +// node used by the decode tree struct DecodeNode { int16 value; DecodeNode *branches[2]; @@ -40,13 +50,27 @@ struct DecodeNode { class DecodeTree { public: - DecodeTree(); + DecodeTree(bool bwhite); ~DecodeTree(); - status_t AddEncoding(uint16 encoding, uint8 length, uint16 value); - status_t GetValue(uint16 encdata, uint8 nbits, uint8 &bitsread) const; + // returns B_OK if the tree was initialized without error, + // returns B_ERROR or B_NO_MEMORY if unable to initialize + status_t InitCheck() const { return finitStatus; }; + + // Decodes nbits bits from encdata, starting with the + // highest order bit. If successful, returns the corresponding + // value for the encdata and bitsread contains the + // number of bits from encdata that were decoded. If not successful, + // B_ERROR, B_NO_MEMORY or B_BAD_VALUE is returned + status_t GetValue(BitReader &stream) const; -private: +private: + status_t LoadBlackEncodings(); + status_t LoadWhiteEncodings(); + status_t AddEncodings(const HuffmanEncoding *pencs, uint32 length); + status_t AddEncoding(uint16 encoding, uint8 length, uint16 value); + + status_t finitStatus; DecodeNode *fptop; }; diff --git a/src/add-ons/translators/tifftranslator/Jamfile b/src/add-ons/translators/tifftranslator/Jamfile index d93a3e00ff..e3a285350d 100755 --- a/src/add-ons/translators/tifftranslator/Jamfile +++ b/src/add-ons/translators/tifftranslator/Jamfile @@ -5,6 +5,8 @@ SEARCH_SOURCE += [ FDirName $(OBOS_TOP) src add-ons translators tgatranslator ] Translator TIFFTranslator : StreamBuffer.cpp + BitReader.cpp + DecodeTree.cpp TiffField.cpp TiffUintField.cpp TiffUnknownField.cpp diff --git a/src/add-ons/translators/tifftranslator/TIFFTranslator.cpp b/src/add-ons/translators/tifftranslator/TIFFTranslator.cpp index 6aa0a0fc8b..0dd6251ae3 100755 --- a/src/add-ons/translators/tifftranslator/TIFFTranslator.cpp +++ b/src/add-ons/translators/tifftranslator/TIFFTranslator.cpp @@ -35,6 +35,7 @@ #include "TIFFView.h" #include "TiffIfd.h" #include "StreamBuffer.h" +#include "BitReader.h" // The input formats that this translator supports. translation_format gInputFormats[] = { @@ -124,6 +125,9 @@ make_nth_translator(int32 n, image_id you, uint32 flags, ...) TIFFTranslator::TIFFTranslator() : BTranslator() { + fpblackTree = NULL; + fpwhiteTree = NULL; + strcpy(fName, "TIFF Images"); sprintf(fInfo, "TIFF image translator v%d.%d.%d %s", TIFF_TRANSLATOR_VERSION / 100, (TIFF_TRANSLATOR_VERSION / 10) % 10, @@ -401,6 +405,7 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails) else dtls.compression = ifd.GetUint(TAG_COMPRESSION); if (dtls.compression != COMPRESSION_NONE && + dtls.compression != COMPRESSION_HUFFMAN && dtls.compression != COMPRESSION_PACKBITS) return B_NO_TRANSLATOR; @@ -498,7 +503,8 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails) status_t identify_tiff_header(BPositionIO *inSource, translator_info *outInfo, - ssize_t amtread, uint8 *read, swap_action swp, TiffDetails *pdetails = NULL) + ssize_t amtread, uint8 *read, swap_action swp, + TiffDetails *pdetails = NULL) { if (amtread != 4) return B_ERROR; @@ -509,7 +515,8 @@ identify_tiff_header(BPositionIO *inSource, translator_info *outInfo, printf("Unable to read first IFD offset\n"); return B_NO_TRANSLATOR; } - if (swap_data(B_UINT32_TYPE, &firstIFDOffset, sizeof(uint32), swp) != B_OK) { + if (swap_data(B_UINT32_TYPE, &firstIFDOffset, + sizeof(uint32), swp) != B_OK) { printf("swap_data() error\n"); return B_ERROR; } @@ -765,9 +772,60 @@ unpack(StreamBuffer *pstreambuf, uint8 *tiffbuffer, uint32 tiffbufferlen) return read; } +ssize_t +TIFFTranslator::decode_huffman(StreamBuffer *pstreambuf, TiffDetails &details, + uint8 *pbits) +{ + BitReader stream(pstreambuf); + if (stream.InitCheck() != B_OK) { + debugger("stream init error"); + 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; + while (pixelswrit < details.width) { + status_t 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; + } + + return stream.BytesRead(); +} + status_t -translate_from_tiff(BPositionIO *inSource, ssize_t amtread, uint8 *read, - swap_action swp, uint32 outType, BPositionIO *outDestination) +TIFFTranslator::translate_from_tiff(BPositionIO *inSource, ssize_t amtread, + uint8 *read, swap_action swp, uint32 outType, BPositionIO *outDestination) { // Can only output to bits for now if (outType != B_TRANSLATOR_BITMAP) @@ -781,6 +839,14 @@ translate_from_tiff(BPositionIO *inSource, ssize_t amtread, uint8 *read, if (result == B_OK) { // If the TIFF is supported by this translator + // If TIFF uses Huffman compression, load + // trees for decoding Huffman compression + if (details.compression == COMPRESSION_HUFFMAN) { + result = LoadHuffmanTrees(); + if (result != B_OK) + return result; + } + TranslatorBitmap bitsHeader; bitsHeader.magic = B_TRANSLATOR_BITMAP; bitsHeader.bounds.left = 0; @@ -828,18 +894,18 @@ translate_from_tiff(BPositionIO *inSource, ssize_t amtread, uint8 *read, // buffer for making reading compressed data // fast and convenient StreamBuffer *pstreambuf = NULL; - if (details.compression == COMPRESSION_PACKBITS) { + if (details.compression != COMPRESSION_NONE) { pstreambuf = new StreamBuffer(inSource, 2048, false); if (pstreambuf->InitCheck() != B_OK) - return B_NO_MEMORY; + return B_NO_MEMORY; } for (uint32 i = 0; i < details.stripsPerImage; i++) { uint32 read = 0; - // If Packbits compression, prepare streambuffer + // If using compression, prepare streambuffer // for reading - if (details.compression == COMPRESSION_PACKBITS && + if (details.compression != COMPRESSION_NONE && !pstreambuf->Seek(details.pstripOffsets[i])) return B_NO_TRANSLATOR; @@ -848,25 +914,47 @@ translate_from_tiff(BPositionIO *inSource, ssize_t amtread, uint8 *read, while (read < details.pstripByteCounts[i]) { ssize_t ret = 0; - if (details.compression == COMPRESSION_NONE) { - ret = inSource->ReadAt(details.pstripOffsets[i] + read, - inbuffer, inbufferlen); - if (ret != static_cast(inbufferlen)) + switch (details.compression) { + case COMPRESSION_NONE: + ret = inSource->ReadAt(details.pstripOffsets[i] + read, + inbuffer, inbufferlen); + if (ret != static_cast(inbufferlen)) + // break out of while loop + ret = -1; + break; + + case COMPRESSION_HUFFMAN: + ret = decode_huffman(pstreambuf, details, outbuffer); + if (ret < 1) + // break out of while loop + ret = -1; break; - } else if (details.compression == COMPRESSION_PACKBITS) { - ret = unpack(pstreambuf, inbuffer, inbufferlen); - if (ret < 1) + case COMPRESSION_PACKBITS: + ret = unpack(pstreambuf, inbuffer, inbufferlen); + if (ret < 1) + // break out of while loop + ret = -1; break; } + if (ret < 0) + break; read += ret; - tiff_to_bits(inbuffer, inbufferlen, outbuffer, details); + if (details.compression != COMPRESSION_HUFFMAN) + tiff_to_bits(inbuffer, inbufferlen, outbuffer, details); outDestination->Write(outbuffer, outbufferlen); } // If while loop was broken... - if (read < details.pstripByteCounts[i]) + if (read < details.pstripByteCounts[i]) { + printf("-- WHILE LOOP BROKEN!!\n"); + printf("i: %d\n", i); + printf("ByteCount: %d\n", + details.pstripByteCounts[i]); + printf("read: %d\n", read); + debugger("while loop broken"); break; + } } // Clean up @@ -1034,3 +1122,26 @@ TIFFTranslator::MakeConfigurationView(BMessage *ioExtension, BView **outView, return B_OK; } + +// Initialize the Huffman decoding trees and +// verify that there were no initialization errors +status_t +TIFFTranslator::LoadHuffmanTrees() +{ + if (!fpblackTree) { + fpblackTree = new DecodeTree(false); + if (!fpblackTree) + return B_NO_MEMORY; + } + if (!fpwhiteTree) { + fpwhiteTree = new DecodeTree(true); + if (!fpwhiteTree) + return B_NO_MEMORY; + } + + if (fpblackTree->InitCheck() != B_OK) + return fpblackTree->InitCheck(); + + return fpwhiteTree->InitCheck(); +} + diff --git a/src/add-ons/translators/tifftranslator/TIFFTranslator.h b/src/add-ons/translators/tifftranslator/TIFFTranslator.h index 74bd7f6afd..c44188b5c6 100755 --- a/src/add-ons/translators/tifftranslator/TIFFTranslator.h +++ b/src/add-ons/translators/tifftranslator/TIFFTranslator.h @@ -41,6 +41,7 @@ #include #include #include +#include "DecodeTree.h" #define TIFF_TRANSLATOR_VERSION 100 @@ -122,6 +123,18 @@ protected: // the user private: + status_t LoadHuffmanTrees(); + + ssize_t decode_huffman(StreamBuffer *pstreambuf, TiffDetails &details, + uint8 *pbits); + + status_t translate_from_tiff(BPositionIO *inSource, ssize_t amtread, + uint8 *read, swap_action swp, uint32 outType, + BPositionIO *outDestination); + + DecodeTree *fpblackTree; + DecodeTree *fpwhiteTree; + char fName[30]; char fInfo[100]; }; diff --git a/src/add-ons/translators/tifftranslator/TiffField.h b/src/add-ons/translators/tifftranslator/TiffField.h index 4e1b78d0e4..0b7d8305f7 100755 --- a/src/add-ons/translators/tifftranslator/TiffField.h +++ b/src/add-ons/translators/tifftranslator/TiffField.h @@ -66,7 +66,7 @@ #define TAG_ORIENTATION 274 #define TAG_SAMPLES_PER_PIXEL 277 #define TAG_ROWS_PER_STRIP 278 - #define DEFAULT_ROWS_PER_STRIP 4294967295L + #define DEFAULT_ROWS_PER_STRIP 4294967295UL #define TAG_STRIP_BYTE_COUNTS 279 #define TAG_PLANAR_CONFIGURATION 284 #define TAG_RESOLUTION_UNIT 296