Added code for converting uncompressed / packbits compressed RGB and CMYK TIFF images to the Be Bitmap format
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3055 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
1847fb9c71
commit
028368527a
@ -1,6 +1,7 @@
|
||||
SubDir OBOS_TOP src add-ons translators tifftranslator ;
|
||||
|
||||
Translator TIFFTranslator :
|
||||
StreamBuffer.cpp
|
||||
TiffField.cpp
|
||||
TiffUintField.cpp
|
||||
TiffUnknownField.cpp
|
||||
|
223
src/add-ons/translators/tifftranslator/StreamBuffer.cpp
Executable file
223
src/add-ons/translators/tifftranslator/StreamBuffer.cpp
Executable file
@ -0,0 +1,223 @@
|
||||
/*****************************************************************************/
|
||||
// StreamBuffer
|
||||
// Written by Michael Wilber, OBOS Translation Kit Team
|
||||
//
|
||||
// StreamBuffer.cpp
|
||||
//
|
||||
// This class is for buffering data from a BPositionIO object in order to
|
||||
// improve performance for cases when small amounts of data are frequently
|
||||
// read from a BPositionIO object.
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2002 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
#define min(x,y) (((x) < (y)) ? (x) : (y))
|
||||
#define max(x,y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Constructor
|
||||
//
|
||||
// Initializes the StreamBuffer to read from pstream, buffering
|
||||
// nbuffersize bytes of data at a time. Note that if nbuffersize
|
||||
// is smaller than MIN_BUFFER_SIZE, MIN_BUFFER_SIZE is used
|
||||
// as the buffer size.
|
||||
//
|
||||
// Preconditions:
|
||||
//
|
||||
// Parameters: pstream, the stream to be buffered
|
||||
//
|
||||
// nbuffersize, number of bytes to be read from
|
||||
// pstream at a time
|
||||
//
|
||||
// Postconditions:
|
||||
//
|
||||
// Returns:
|
||||
// ---------------------------------------------------------------
|
||||
StreamBuffer::StreamBuffer(BPositionIO *pstream, size_t nbuffersize,
|
||||
bool binitialread)
|
||||
{
|
||||
fpStream = pstream;
|
||||
fpBuffer = NULL;
|
||||
fnBufferSize = 0;
|
||||
fnLen = 0;
|
||||
fnPos = 0;
|
||||
|
||||
if (!pstream)
|
||||
return;
|
||||
|
||||
fnBufferSize = max(nbuffersize, MIN_BUFFER_SIZE);
|
||||
fpBuffer = new uint8[fnBufferSize];
|
||||
if (fpBuffer && binitialread)
|
||||
ReadStream();
|
||||
// Fill the buffer with data so that
|
||||
// object is prepared for first call to
|
||||
// Read()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Destructor
|
||||
//
|
||||
// Destroys data allocated for this object
|
||||
//
|
||||
// Preconditions:
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// Postconditions:
|
||||
//
|
||||
// Returns:
|
||||
// ---------------------------------------------------------------
|
||||
StreamBuffer::~StreamBuffer()
|
||||
{
|
||||
fnBufferSize = 0;
|
||||
fnLen = 0;
|
||||
fnPos = 0;
|
||||
fpStream = NULL;
|
||||
|
||||
delete[] fpBuffer;
|
||||
fpBuffer = NULL;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// InitCheck
|
||||
//
|
||||
// Determines whether the constructor failed or not
|
||||
//
|
||||
// Preconditions:
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// Postconditions:
|
||||
//
|
||||
// Returns: B_OK if object has been initialized successfully,
|
||||
// B_ERROR if not
|
||||
// ---------------------------------------------------------------
|
||||
status_t StreamBuffer::InitCheck()
|
||||
{
|
||||
if (fpStream && fpBuffer)
|
||||
return B_OK;
|
||||
else
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Read
|
||||
//
|
||||
// Copies up to nbytes of data from the stream into pinto
|
||||
//
|
||||
// Preconditions: ReadStream() must be called once before this
|
||||
// function is called (the constructor does this)
|
||||
//
|
||||
// Parameters: pinto, the buffer to be copied to
|
||||
//
|
||||
// nbytes, the maximum number of bytes to copy
|
||||
//
|
||||
// Postconditions:
|
||||
//
|
||||
// Returns: the number of bytes successfully read or an
|
||||
// error code returned by BPositionIO::Read()
|
||||
// ---------------------------------------------------------------
|
||||
ssize_t StreamBuffer::Read(uint8 *pinto, size_t nbytes)
|
||||
{
|
||||
ssize_t result = B_ERROR;
|
||||
size_t rd1 = 0, rd2 = 0;
|
||||
|
||||
rd1 = min(nbytes, fnLen - fnPos);
|
||||
memcpy(pinto, fpBuffer + fnPos, rd1);
|
||||
fnPos += rd1;
|
||||
|
||||
if (rd1 < nbytes) {
|
||||
pinto += rd1;
|
||||
result = ReadStream();
|
||||
if (result > 0) {
|
||||
rd2 = min(nbytes - rd1, fnLen);
|
||||
memcpy(pinto, fpBuffer, rd2);
|
||||
fnPos += rd2;
|
||||
} else
|
||||
// return error code or zero
|
||||
return result;
|
||||
}
|
||||
|
||||
return rd1 + rd2;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Seek
|
||||
//
|
||||
// Seeks the stream to the given position and refreshes the
|
||||
// read buffer. If the seek operation fails, the read buffer
|
||||
// will be reset.
|
||||
//
|
||||
// Preconditions: fpBuffer must be allocated and fnBufferSize
|
||||
// must be valid
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// Postconditions:
|
||||
//
|
||||
// Returns: true if the seek was successful,
|
||||
// false if the seek operation failed
|
||||
// ---------------------------------------------------------------
|
||||
bool StreamBuffer::Seek(off_t position)
|
||||
{
|
||||
fnLen = 0;
|
||||
fnPos = 0;
|
||||
|
||||
if (fpStream->Seek(position, SEEK_SET) == position) {
|
||||
ReadStream();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// ReadStream
|
||||
//
|
||||
// Fills the stream buffer with data read in from the stream
|
||||
//
|
||||
// Preconditions: fpBuffer must be allocated and fnBufferSize
|
||||
// must be valid
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// Postconditions:
|
||||
//
|
||||
// Returns: the number of bytes successfully read or an
|
||||
// error code returned by BPositionIO::Read()
|
||||
// ---------------------------------------------------------------
|
||||
ssize_t StreamBuffer::ReadStream()
|
||||
{
|
||||
ssize_t rd;
|
||||
rd = fpStream->Read(fpBuffer, fnBufferSize);
|
||||
if (rd >= 0) {
|
||||
fnLen = rd;
|
||||
fnPos = 0;
|
||||
}
|
||||
return rd;
|
||||
}
|
||||
|
||||
|
70
src/add-ons/translators/tifftranslator/StreamBuffer.h
Executable file
70
src/add-ons/translators/tifftranslator/StreamBuffer.h
Executable file
@ -0,0 +1,70 @@
|
||||
/*****************************************************************************/
|
||||
// StreamBuffer
|
||||
// Written by Michael Wilber, OBOS Translation Kit Team
|
||||
//
|
||||
// StreamBuffer.h
|
||||
//
|
||||
// This class is for buffering data from a BPositionIO object in order to
|
||||
// improve performance for cases when small amounts of data are frequently
|
||||
// read from a BPositionIO object.
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2002 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 STREAM_BUFFER_H
|
||||
#define STREAM_BUFFER_H
|
||||
|
||||
#include <DataIO.h>
|
||||
|
||||
#define MIN_BUFFER_SIZE 512
|
||||
|
||||
class StreamBuffer {
|
||||
public:
|
||||
StreamBuffer(BPositionIO *pstream, size_t nbuffersize, bool binitialread);
|
||||
~StreamBuffer();
|
||||
|
||||
status_t InitCheck();
|
||||
// Determines whether the constructor failed or not
|
||||
|
||||
ssize_t Read(uint8 *pinto, size_t nbytes);
|
||||
// copy nbytes from the stream into pinto
|
||||
|
||||
bool Seek(off_t position);
|
||||
// seek the stream to the given position
|
||||
|
||||
private:
|
||||
ssize_t ReadStream();
|
||||
// Load the stream buffer from the stream
|
||||
|
||||
BPositionIO *fpStream;
|
||||
// stream object this object is buffering
|
||||
uint8 *fpBuffer;
|
||||
// buffered data from fpStream
|
||||
size_t fnBufferSize;
|
||||
// number of bytes of memory allocated for fpBuffer
|
||||
size_t fnLen;
|
||||
// number of bytes of actual data in fpBuffer
|
||||
size_t fnPos;
|
||||
// current position in the buffer
|
||||
};
|
||||
|
||||
#endif
|
@ -34,6 +34,7 @@
|
||||
#include "TIFFTranslator.h"
|
||||
#include "TIFFView.h"
|
||||
#include "TiffIfd.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
// The input formats that this translator supports.
|
||||
translation_format gInputFormats[] = {
|
||||
@ -341,7 +342,7 @@ identify_bits_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
outInfo->group = B_TRANSLATOR_BITMAP;
|
||||
outInfo->quality = BBT_IN_QUALITY;
|
||||
outInfo->capability = BBT_IN_CAPABILITY;
|
||||
strcpy(outInfo->name, "Be Bitmap Format (TGATranslator)");
|
||||
strcpy(outInfo->name, "Be Bitmap Format (TIFFTranslator)");
|
||||
strcpy(outInfo->MIME, "image/x-be-bitmap");
|
||||
}
|
||||
|
||||
@ -362,10 +363,14 @@ identify_bits_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
status_t
|
||||
check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails)
|
||||
{
|
||||
TiffDetails details;
|
||||
memset(&details, 0, sizeof(TiffDetails));
|
||||
TiffDetails dtls;
|
||||
memset(&dtls, 0, sizeof(TiffDetails));
|
||||
|
||||
try {
|
||||
try {
|
||||
// Extra Samples are not yet supported
|
||||
if (ifd.HasField(TAG_EXTRA_SAMPLES))
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// Only the default values are supported for the
|
||||
// following fields. HasField is called so that
|
||||
// if a field is not present, a TiffIfdFieldNotFoundException
|
||||
@ -387,29 +392,82 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// Copy fields useful to TIFFTranslator
|
||||
details.width = ifd.GetUint(TAG_IMAGE_WIDTH);
|
||||
details.height = ifd.GetUint(TAG_IMAGE_HEIGHT);
|
||||
details.compression = ifd.GetUint(TAG_COMPRESSION);
|
||||
details.interpretation = ifd.GetUint(TAG_PHOTO_INTERPRETATION);
|
||||
dtls.width = ifd.GetUint(TAG_IMAGE_WIDTH);
|
||||
dtls.height = ifd.GetUint(TAG_IMAGE_HEIGHT);
|
||||
dtls.compression = ifd.GetUint(TAG_COMPRESSION);
|
||||
dtls.interpretation = ifd.GetUint(TAG_PHOTO_INTERPRETATION);
|
||||
|
||||
if (dtls.compression != COMPRESSION_NONE &&
|
||||
dtls.compression != COMPRESSION_PACKBITS)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// Currently, only uncompressed
|
||||
// RGB or CMYK images are supported
|
||||
if (dtls.interpretation == PHOTO_RGB) {
|
||||
if (ifd.GetUint(TAG_SAMPLES_PER_PIXEL) != 3)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (ifd.GetCount(TAG_BITS_PER_SAMPLE) != 3 ||
|
||||
ifd.GetUint(TAG_BITS_PER_SAMPLE, 1) != 8 ||
|
||||
ifd.GetUint(TAG_BITS_PER_SAMPLE, 2) != 8 ||
|
||||
ifd.GetUint(TAG_BITS_PER_SAMPLE, 3) != 8)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
dtls.imageType = TIFF_RGB;
|
||||
|
||||
} else if (dtls.interpretation == PHOTO_SEPARATED) {
|
||||
// CMYK (default ink set)
|
||||
// is the only ink set supported
|
||||
if (ifd.HasField(TAG_INK_SET) &&
|
||||
ifd.GetUint(TAG_INK_SET) != INK_SET_CMYK)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
if (ifd.GetUint(TAG_SAMPLES_PER_PIXEL) != 4)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (ifd.GetCount(TAG_BITS_PER_SAMPLE) != 4 ||
|
||||
ifd.GetUint(TAG_BITS_PER_SAMPLE, 1) != 8 ||
|
||||
ifd.GetUint(TAG_BITS_PER_SAMPLE, 2) != 8 ||
|
||||
ifd.GetUint(TAG_BITS_PER_SAMPLE, 3) != 8 ||
|
||||
ifd.GetUint(TAG_BITS_PER_SAMPLE, 4) != 8)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
dtls.imageType = TIFF_CMYK;
|
||||
|
||||
} else
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
if (!ifd.HasField(TAG_ROWS_PER_STRIP))
|
||||
dtls.rowsPerStrip = DEFAULT_ROWS_PER_STRIP;
|
||||
else
|
||||
dtls.rowsPerStrip = ifd.GetUint(TAG_ROWS_PER_STRIP);
|
||||
dtls.stripsPerImage =
|
||||
(dtls.height + dtls.rowsPerStrip - 1) / dtls.rowsPerStrip;
|
||||
|
||||
if (ifd.GetCount(TAG_STRIP_OFFSETS) != dtls.stripsPerImage ||
|
||||
ifd.GetCount(TAG_STRIP_BYTE_COUNTS) != dtls.stripsPerImage)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
printf("width: %d\nheight: %d\ncompression: %d\ninterpretation: %d\n",
|
||||
details.width, details.height, details.compression,
|
||||
details.interpretation);
|
||||
|
||||
// Currently, only uncompressed, non-tile RGB
|
||||
// images are supported
|
||||
if (details.compression != COMPRESSION_NONE)
|
||||
return B_NO_TRANSLATOR;
|
||||
if (details.interpretation != PHOTO_RGB)
|
||||
return B_NO_TRANSLATOR;
|
||||
dtls.width, dtls.height, dtls.compression,
|
||||
dtls.interpretation);
|
||||
|
||||
// return read in details if output
|
||||
// pointer is supplied
|
||||
if (pdetails)
|
||||
memcpy(pdetails, &details, sizeof(TiffDetails));
|
||||
if (pdetails) {
|
||||
ifd.GetUintArray(TAG_STRIP_OFFSETS, &dtls.pstripOffsets);
|
||||
ifd.GetUintArray(TAG_STRIP_BYTE_COUNTS, &dtls.pstripByteCounts);
|
||||
|
||||
memcpy(pdetails, &dtls, sizeof(TiffDetails));
|
||||
}
|
||||
|
||||
} catch (TiffIfdException) {
|
||||
|
||||
printf("-- Caught TiffIfdException --\n");
|
||||
|
||||
delete[] dtls.pstripOffsets;
|
||||
dtls.pstripOffsets = NULL;
|
||||
delete[] dtls.pstripByteCounts;
|
||||
dtls.pstripByteCounts = NULL;
|
||||
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
@ -445,14 +503,24 @@ identify_tiff_header(BPositionIO *inSource, translator_info *outInfo,
|
||||
// this particular TIFF image is supported by this translator
|
||||
|
||||
// Check the required fields
|
||||
if (initcheck == B_OK)
|
||||
return check_tiff_fields(ifd, pdetails);
|
||||
if (initcheck == B_OK) {
|
||||
if (outInfo) {
|
||||
outInfo->type = B_TIFF_FORMAT;
|
||||
outInfo->group = B_TRANSLATOR_BITMAP;
|
||||
outInfo->quality = TIFF_IN_QUALITY;
|
||||
outInfo->capability = TIFF_IN_CAPABILITY;
|
||||
strcpy(outInfo->MIME, "image/tiff");
|
||||
strcpy(outInfo->name, "TIFF Image");
|
||||
}
|
||||
|
||||
if (initcheck != B_OK && initcheck != B_ERROR && initcheck != B_NO_MEMORY)
|
||||
return check_tiff_fields(ifd, pdetails);
|
||||
}
|
||||
|
||||
if (initcheck != B_ERROR && initcheck != B_NO_MEMORY)
|
||||
// return B_NO_TRANSLATOR if unexpected data was encountered
|
||||
return B_NO_TRANSLATOR;
|
||||
else
|
||||
// return B_OK, B_ERROR or B_NO_MEMORY
|
||||
// return B_ERROR or B_NO_MEMORY
|
||||
return initcheck;
|
||||
}
|
||||
|
||||
@ -516,7 +584,6 @@ TIFFTranslator::Identify(BPositionIO *inSource,
|
||||
// Read in the magic number and determine if it
|
||||
// is a supported type
|
||||
uint8 ch[4];
|
||||
inSource->Seek(0, SEEK_SET);
|
||||
if (inSource->Read(ch, 4) != 4)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
@ -565,6 +632,216 @@ TIFFTranslator::Identify(BPositionIO *inSource,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tiff_to_bits(uint8 *ptiff, uint32 tifflen, uint8 *pbits, uint16 type)
|
||||
{
|
||||
uint8 *ptiffend = ptiff + tifflen;
|
||||
|
||||
switch (type) {
|
||||
case TIFF_RGB:
|
||||
while (ptiff < ptiffend) {
|
||||
pbits[2] = ptiff[0];
|
||||
pbits[1] = ptiff[1];
|
||||
pbits[0] = ptiff[2];
|
||||
|
||||
ptiff += 3;
|
||||
pbits += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case TIFF_CMYK:
|
||||
{
|
||||
while (ptiff < ptiffend) {
|
||||
int32 comp;
|
||||
comp = 255 - ptiff[0] - ptiff[3];
|
||||
pbits[2] = (comp < 0) ? 0 : comp;
|
||||
|
||||
comp = 255 - ptiff[1] - ptiff[3];
|
||||
pbits[1] = (comp < 0) ? 0 : comp;
|
||||
|
||||
comp = 255 - ptiff[2] - ptiff[3];
|
||||
pbits[0] = (comp < 0) ? 0 : comp;
|
||||
|
||||
ptiff += 4;
|
||||
pbits += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unpack the Packbits compressed data from
|
||||
// pstreambuf and put it into tiffbuffer
|
||||
ssize_t
|
||||
unpack(StreamBuffer *pstreambuf, uint8 *tiffbuffer, uint32 tiffbufferlen)
|
||||
{
|
||||
uint32 tiffwrit = 0, read = 0, len;
|
||||
while (tiffwrit < tiffbufferlen) {
|
||||
|
||||
uint8 uctrl;
|
||||
if (pstreambuf->Read(&uctrl, 1) != 1)
|
||||
return B_ERROR;
|
||||
read++;
|
||||
|
||||
int32 control;
|
||||
control = static_cast<signed char>(uctrl);
|
||||
|
||||
// copy control + 1 bytes literally
|
||||
if (control >= 0 && control <= 127) {
|
||||
|
||||
len = control + 1;
|
||||
if (tiffwrit + len > tiffbufferlen)
|
||||
return B_ERROR;
|
||||
if (pstreambuf->Read(tiffbuffer + tiffwrit, len) !=
|
||||
static_cast<ssize_t>(len))
|
||||
return B_ERROR;
|
||||
read += len;
|
||||
|
||||
tiffwrit += len;
|
||||
|
||||
// copy the next byte (-control) + 1 times
|
||||
} else if (control >= -127 && control <= -1) {
|
||||
|
||||
uint8 byt;
|
||||
if (pstreambuf->Read(&byt, 1) != 1)
|
||||
return B_ERROR;
|
||||
read++;
|
||||
|
||||
len = (-control) + 1;
|
||||
if (tiffwrit + len > tiffbufferlen)
|
||||
return B_ERROR;
|
||||
memset(tiffbuffer + tiffwrit, byt, len);
|
||||
|
||||
tiffwrit += len;
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
status_t
|
||||
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)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
status_t result;
|
||||
|
||||
TiffDetails details;
|
||||
result = identify_tiff_header(inSource, NULL,
|
||||
amtread, read, swp, &details);
|
||||
if (result == B_OK) {
|
||||
// If the TIFF is supported by this translator
|
||||
|
||||
TranslatorBitmap bitsHeader;
|
||||
bitsHeader.magic = B_TRANSLATOR_BITMAP;
|
||||
bitsHeader.bounds.left = 0;
|
||||
bitsHeader.bounds.top = 0;
|
||||
bitsHeader.bounds.right = details.width - 1;
|
||||
bitsHeader.bounds.bottom = details.height - 1;
|
||||
bitsHeader.rowBytes = 4 * details.width;
|
||||
bitsHeader.colors = B_RGB32;
|
||||
bitsHeader.dataSize = bitsHeader.rowBytes * details.height;
|
||||
|
||||
// write out Be's Bitmap header
|
||||
if (swap_data(B_UINT32_TYPE, &bitsHeader,
|
||||
sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
||||
return B_ERROR;
|
||||
outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
|
||||
|
||||
uint32 inbufferlen, outbufferlen;
|
||||
outbufferlen = 4 * details.width;
|
||||
switch (details.imageType) {
|
||||
case TIFF_RGB:
|
||||
inbufferlen = 3 * details.width;
|
||||
break;
|
||||
|
||||
case TIFF_CMYK:
|
||||
inbufferlen = 4 * details.width;
|
||||
break;
|
||||
|
||||
default:
|
||||
// just to be safe
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
uint8 *inbuffer = new uint8[inbufferlen],
|
||||
*outbuffer = new uint8[outbufferlen];
|
||||
if (!inbuffer || !outbuffer)
|
||||
return B_NO_MEMORY;
|
||||
// set all channels to 0xff so that I won't have
|
||||
// to set the alpha byte to 0xff every time
|
||||
memset(outbuffer, 0xff, outbufferlen);
|
||||
|
||||
// buffer for making reading compressed data
|
||||
// fast and convenient
|
||||
StreamBuffer *pstreambuf = NULL;
|
||||
if (details.compression == COMPRESSION_PACKBITS) {
|
||||
pstreambuf = new StreamBuffer(inSource, 2048, false);
|
||||
if (pstreambuf->InitCheck() != B_OK)
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < details.stripsPerImage; i++) {
|
||||
uint32 read = 0;
|
||||
|
||||
// If Packbits compression, prepare streambuffer
|
||||
// for reading
|
||||
if (details.compression == COMPRESSION_PACKBITS &&
|
||||
!pstreambuf->Seek(details.pstripOffsets[i]))
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// Read / Write one line at a time for each
|
||||
// line in the strip
|
||||
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<ssize_t>(inbufferlen))
|
||||
break;
|
||||
|
||||
} else if (details.compression == COMPRESSION_PACKBITS) {
|
||||
ret = unpack(pstreambuf, inbuffer, inbufferlen);
|
||||
if (ret < 1)
|
||||
break;
|
||||
}
|
||||
|
||||
read += ret;
|
||||
tiff_to_bits(inbuffer, inbufferlen, outbuffer,
|
||||
details.imageType);
|
||||
outDestination->Write(outbuffer, outbufferlen);
|
||||
}
|
||||
// If while loop was broken...
|
||||
if (read < details.pstripByteCounts[i])
|
||||
break;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
if (pstreambuf) {
|
||||
delete pstreambuf;
|
||||
pstreambuf = NULL;
|
||||
}
|
||||
|
||||
delete[] inbuffer;
|
||||
inbuffer = NULL;
|
||||
delete[] outbuffer;
|
||||
outbuffer = NULL;
|
||||
|
||||
delete[] details.pstripOffsets;
|
||||
details.pstripOffsets = NULL;
|
||||
delete[] details.pstripByteCounts;
|
||||
details.pstripByteCounts = NULL;
|
||||
|
||||
return B_OK;
|
||||
|
||||
} else
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Translate
|
||||
//
|
||||
@ -605,9 +882,67 @@ TIFFTranslator::Translate(BPositionIO *inSource,
|
||||
outType = B_TRANSLATOR_BITMAP;
|
||||
if (outType != B_TRANSLATOR_BITMAP && outType != B_TIFF_FORMAT)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// Convert the magic numbers to the various byte orders so that
|
||||
// I won't have to convert the data read in to see whether or not
|
||||
// it is a supported type
|
||||
uint32 nbits = B_TRANSLATOR_BITMAP;
|
||||
if (swap_data(B_UINT32_TYPE, &nbits, sizeof(uint32),
|
||||
B_SWAP_HOST_TO_BENDIAN) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// Read in the magic number and determine if it
|
||||
// is a supported type
|
||||
uint8 ch[4];
|
||||
inSource->Seek(0, SEEK_SET);
|
||||
if (inSource->Read(ch, 4) != 4)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
return B_NO_TRANSLATOR;
|
||||
// translator isn't implemented yet
|
||||
// Read settings from ioExtension
|
||||
bool bheaderonly = false, bdataonly = false;
|
||||
if (ioExtension) {
|
||||
if (ioExtension->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY, &bheaderonly))
|
||||
// if failed, make sure bool is default value
|
||||
bheaderonly = false;
|
||||
if (ioExtension->FindBool(B_TRANSLATOR_EXT_DATA_ONLY, &bdataonly))
|
||||
// if failed, make sure bool is default value
|
||||
bdataonly = false;
|
||||
|
||||
if (bheaderonly && bdataonly)
|
||||
// can't both "only write the header" and "only write the data"
|
||||
// at the same time
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
uint32 n32ch;
|
||||
memcpy(&n32ch, ch, sizeof(uint32));
|
||||
// if B_TRANSLATOR_BITMAP type
|
||||
if (n32ch == nbits)
|
||||
return B_NO_TRANSLATOR;
|
||||
// Not implemented yet
|
||||
|
||||
// Might be TIFF image
|
||||
else {
|
||||
// TIFF Byte Order / Magic
|
||||
const uint8 kleSig[] = { 0x49, 0x49, 0x2a, 0x00 };
|
||||
const uint8 kbeSig[] = { 0x4d, 0x4d, 0x00, 0x2a };
|
||||
|
||||
swap_action swp;
|
||||
if (memcmp(ch, kleSig, 4) == 0) {
|
||||
swp = B_SWAP_LENDIAN_TO_HOST;
|
||||
printf("Byte Order: little endian\n");
|
||||
} else if (memcmp(ch, kbeSig, 4) == 0) {
|
||||
swp = B_SWAP_BENDIAN_TO_HOST;
|
||||
printf("Byte Order: big endian\n");
|
||||
} else {
|
||||
// If not a TIFF or a Be Bitmap image
|
||||
printf("Invalid byte order value\n");
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
return translate_from_tiff(inSource, 4, ch, swp, outType,
|
||||
outDestination);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
@ -46,21 +46,31 @@
|
||||
|
||||
#define TIFF_IN_QUALITY 0.1
|
||||
#define TIFF_IN_CAPABILITY 0.1
|
||||
#define TIFF_OUT_QUALITY 0.0
|
||||
#define TIFF_OUT_CAPABILITY 0.0
|
||||
#define TIFF_OUT_QUALITY 0.6
|
||||
#define TIFF_OUT_CAPABILITY 0.2
|
||||
|
||||
#define BBT_IN_QUALITY 0.4
|
||||
#define BBT_IN_CAPABILITY 0.6
|
||||
#define BBT_OUT_QUALITY 0.4
|
||||
#define BBT_OUT_CAPABILITY 0.6
|
||||
|
||||
enum TIFF_IMAGE_TYPE {
|
||||
TIFF_RGB = 1,
|
||||
TIFF_CMYK
|
||||
};
|
||||
|
||||
// structure for storing only the TIFF fields
|
||||
// that are of interest to the TIFFTranslator
|
||||
struct TiffDetails {
|
||||
uint32 width;
|
||||
uint32 height;
|
||||
uint32 compression;
|
||||
uint32 rowsPerStrip;
|
||||
uint32 stripsPerImage;
|
||||
uint32 *pstripOffsets;
|
||||
uint32 *pstripByteCounts;
|
||||
uint16 interpretation;
|
||||
uint16 imageType;
|
||||
};
|
||||
|
||||
class TIFFTranslator : public BTranslator {
|
||||
|
@ -60,15 +60,20 @@
|
||||
#define PHOTO_RGB 2
|
||||
#define PHOTO_PALETTE 3
|
||||
#define PHOTO_MASK 4
|
||||
#define PHOTO_SEPARATED 5
|
||||
#define TAG_FILL_ORDER 266
|
||||
#define TAG_STRIP_OFFSETS 273
|
||||
#define TAG_ORIENTATION 274
|
||||
#define TAG_SAMPLES_PER_PIXEL 277
|
||||
#define TAG_ROWS_PER_STRIP 278
|
||||
#define DEFAULT_ROWS_PER_STRIP 4294967295L
|
||||
#define TAG_STRIP_BYTE_COUNTS 279
|
||||
#define TAG_PLANAR_CONFIGURATION 284
|
||||
#define TAG_RESOLUTION_UNIT 296
|
||||
#define TAG_COLOR_MAP 320
|
||||
#define TAG_INK_SET 332
|
||||
#define INK_SET_CMYK 1
|
||||
#define INK_SET_NOT_CMYK 2
|
||||
#define TAG_EXTRA_SAMPLES 338
|
||||
#define TAG_SAMPLE_FORMAT 339
|
||||
|
||||
|
@ -175,6 +175,42 @@ TiffIfd::GetUint(uint16 tag, uint32 index)
|
||||
throw TiffIfdFieldNotFoundException();
|
||||
}
|
||||
|
||||
uint32
|
||||
TiffIfd::GetUintArray(uint16 tag, uint32 **pout)
|
||||
{
|
||||
TiffField *pfield = GetField(tag);
|
||||
if (pfield) {
|
||||
|
||||
TiffUintField *puintField = NULL;
|
||||
puintField = dynamic_cast<TiffUintField *>(pfield);
|
||||
if (puintField) {
|
||||
|
||||
uint32 count = puintField->GetCount();
|
||||
(*pout) = new uint32[count];
|
||||
uint32 *puints = (*pout);
|
||||
if (!puints)
|
||||
throw TiffIfdNoMemoryException();
|
||||
|
||||
for (uint32 i = 0; i < count; i++) {
|
||||
uint32 num;
|
||||
status_t ret = puintField->GetUint(num, i + 1);
|
||||
if (ret == B_BAD_INDEX)
|
||||
throw TiffIfdBadIndexException();
|
||||
else if (ret == B_BAD_TYPE)
|
||||
throw TiffIfdUnexpectedTypeException();
|
||||
|
||||
puints[i] = num;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
} else
|
||||
throw TiffIfdUnexpectedTypeException();
|
||||
}
|
||||
|
||||
throw TiffIfdFieldNotFoundException();
|
||||
}
|
||||
|
||||
TiffField *
|
||||
TiffIfd::GetField(uint16 tag)
|
||||
{
|
||||
|
@ -52,6 +52,10 @@ class TiffIfdBadIndexException : public TiffIfdException {
|
||||
public:
|
||||
TiffIfdBadIndexException() { };
|
||||
};
|
||||
class TiffIfdNoMemoryException : public TiffIfdException {
|
||||
public:
|
||||
TiffIfdNoMemoryException() { };
|
||||
};
|
||||
|
||||
class TiffIfd {
|
||||
public:
|
||||
@ -73,6 +77,16 @@ public:
|
||||
// throws: TiffIfdFieldNotFoundException(),
|
||||
// TiffIfdUnexpectedTypeException(),
|
||||
// TiffIfdBadIndexException()
|
||||
|
||||
uint32 GetUintArray(uint16 tag, uint32 **pout);
|
||||
// copies all of the uints from tag to
|
||||
// the pointer pointed to by pout
|
||||
// and returns the number of uints copied
|
||||
//
|
||||
// throws: TiffIfdFieldNotFoundException(),
|
||||
// TiffIfdUnexpectedTypeException(),
|
||||
// TiffIfdBadIndexException()
|
||||
// TiffIfdNoMemoryException()
|
||||
|
||||
private:
|
||||
void LoadFields(uint32 offset, BPositionIO &io, swap_action swp);
|
||||
|
Loading…
Reference in New Issue
Block a user