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:
@@ -1,6 +1,7 @@
|
|||||||
SubDir OBOS_TOP src add-ons translators tifftranslator ;
|
SubDir OBOS_TOP src add-ons translators tifftranslator ;
|
||||||
|
|
||||||
Translator TIFFTranslator :
|
Translator TIFFTranslator :
|
||||||
|
StreamBuffer.cpp
|
||||||
TiffField.cpp
|
TiffField.cpp
|
||||||
TiffUintField.cpp
|
TiffUintField.cpp
|
||||||
TiffUnknownField.cpp
|
TiffUnknownField.cpp
|
||||||
|
|||||||
+223
@@ -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
@@ -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 "TIFFTranslator.h"
|
||||||
#include "TIFFView.h"
|
#include "TIFFView.h"
|
||||||
#include "TiffIfd.h"
|
#include "TiffIfd.h"
|
||||||
|
#include "StreamBuffer.h"
|
||||||
|
|
||||||
// The input formats that this translator supports.
|
// The input formats that this translator supports.
|
||||||
translation_format gInputFormats[] = {
|
translation_format gInputFormats[] = {
|
||||||
@@ -341,7 +342,7 @@ identify_bits_header(BPositionIO *inSource, translator_info *outInfo,
|
|||||||
outInfo->group = B_TRANSLATOR_BITMAP;
|
outInfo->group = B_TRANSLATOR_BITMAP;
|
||||||
outInfo->quality = BBT_IN_QUALITY;
|
outInfo->quality = BBT_IN_QUALITY;
|
||||||
outInfo->capability = BBT_IN_CAPABILITY;
|
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");
|
strcpy(outInfo->MIME, "image/x-be-bitmap");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,10 +363,14 @@ identify_bits_header(BPositionIO *inSource, translator_info *outInfo,
|
|||||||
status_t
|
status_t
|
||||||
check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails)
|
check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails)
|
||||||
{
|
{
|
||||||
TiffDetails details;
|
TiffDetails dtls;
|
||||||
memset(&details, 0, sizeof(TiffDetails));
|
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
|
// Only the default values are supported for the
|
||||||
// following fields. HasField is called so that
|
// following fields. HasField is called so that
|
||||||
// if a field is not present, a TiffIfdFieldNotFoundException
|
// if a field is not present, a TiffIfdFieldNotFoundException
|
||||||
@@ -387,29 +392,82 @@ check_tiff_fields(TiffIfd &ifd, TiffDetails *pdetails)
|
|||||||
return B_NO_TRANSLATOR;
|
return B_NO_TRANSLATOR;
|
||||||
|
|
||||||
// Copy fields useful to TIFFTranslator
|
// Copy fields useful to TIFFTranslator
|
||||||
details.width = ifd.GetUint(TAG_IMAGE_WIDTH);
|
dtls.width = ifd.GetUint(TAG_IMAGE_WIDTH);
|
||||||
details.height = ifd.GetUint(TAG_IMAGE_HEIGHT);
|
dtls.height = ifd.GetUint(TAG_IMAGE_HEIGHT);
|
||||||
details.compression = ifd.GetUint(TAG_COMPRESSION);
|
dtls.compression = ifd.GetUint(TAG_COMPRESSION);
|
||||||
details.interpretation = ifd.GetUint(TAG_PHOTO_INTERPRETATION);
|
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",
|
printf("width: %d\nheight: %d\ncompression: %d\ninterpretation: %d\n",
|
||||||
details.width, details.height, details.compression,
|
dtls.width, dtls.height, dtls.compression,
|
||||||
details.interpretation);
|
dtls.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;
|
|
||||||
|
|
||||||
// return read in details if output
|
// return read in details if output
|
||||||
// pointer is supplied
|
// pointer is supplied
|
||||||
if (pdetails)
|
if (pdetails) {
|
||||||
memcpy(pdetails, &details, sizeof(TiffDetails));
|
ifd.GetUintArray(TAG_STRIP_OFFSETS, &dtls.pstripOffsets);
|
||||||
|
ifd.GetUintArray(TAG_STRIP_BYTE_COUNTS, &dtls.pstripByteCounts);
|
||||||
|
|
||||||
|
memcpy(pdetails, &dtls, sizeof(TiffDetails));
|
||||||
|
}
|
||||||
|
|
||||||
} catch (TiffIfdException) {
|
} catch (TiffIfdException) {
|
||||||
|
|
||||||
printf("-- Caught TiffIfdException --\n");
|
printf("-- Caught TiffIfdException --\n");
|
||||||
|
|
||||||
|
delete[] dtls.pstripOffsets;
|
||||||
|
dtls.pstripOffsets = NULL;
|
||||||
|
delete[] dtls.pstripByteCounts;
|
||||||
|
dtls.pstripByteCounts = NULL;
|
||||||
|
|
||||||
return B_NO_TRANSLATOR;
|
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
|
// this particular TIFF image is supported by this translator
|
||||||
|
|
||||||
// Check the required fields
|
// Check the required fields
|
||||||
if (initcheck == B_OK)
|
if (initcheck == B_OK) {
|
||||||
return check_tiff_fields(ifd, pdetails);
|
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 if unexpected data was encountered
|
||||||
return B_NO_TRANSLATOR;
|
return B_NO_TRANSLATOR;
|
||||||
else
|
else
|
||||||
// return B_OK, B_ERROR or B_NO_MEMORY
|
// return B_ERROR or B_NO_MEMORY
|
||||||
return initcheck;
|
return initcheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +584,6 @@ TIFFTranslator::Identify(BPositionIO *inSource,
|
|||||||
// Read in the magic number and determine if it
|
// Read in the magic number and determine if it
|
||||||
// is a supported type
|
// is a supported type
|
||||||
uint8 ch[4];
|
uint8 ch[4];
|
||||||
inSource->Seek(0, SEEK_SET);
|
|
||||||
if (inSource->Read(ch, 4) != 4)
|
if (inSource->Read(ch, 4) != 4)
|
||||||
return B_NO_TRANSLATOR;
|
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
|
// Translate
|
||||||
//
|
//
|
||||||
@@ -605,9 +882,67 @@ TIFFTranslator::Translate(BPositionIO *inSource,
|
|||||||
outType = B_TRANSLATOR_BITMAP;
|
outType = B_TRANSLATOR_BITMAP;
|
||||||
if (outType != B_TRANSLATOR_BITMAP && outType != B_TIFF_FORMAT)
|
if (outType != B_TRANSLATOR_BITMAP && outType != B_TIFF_FORMAT)
|
||||||
return B_NO_TRANSLATOR;
|
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;
|
// Read settings from ioExtension
|
||||||
// translator isn't implemented yet
|
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_QUALITY 0.1
|
||||||
#define TIFF_IN_CAPABILITY 0.1
|
#define TIFF_IN_CAPABILITY 0.1
|
||||||
#define TIFF_OUT_QUALITY 0.0
|
#define TIFF_OUT_QUALITY 0.6
|
||||||
#define TIFF_OUT_CAPABILITY 0.0
|
#define TIFF_OUT_CAPABILITY 0.2
|
||||||
|
|
||||||
#define BBT_IN_QUALITY 0.4
|
#define BBT_IN_QUALITY 0.4
|
||||||
#define BBT_IN_CAPABILITY 0.6
|
#define BBT_IN_CAPABILITY 0.6
|
||||||
#define BBT_OUT_QUALITY 0.4
|
#define BBT_OUT_QUALITY 0.4
|
||||||
#define BBT_OUT_CAPABILITY 0.6
|
#define BBT_OUT_CAPABILITY 0.6
|
||||||
|
|
||||||
|
enum TIFF_IMAGE_TYPE {
|
||||||
|
TIFF_RGB = 1,
|
||||||
|
TIFF_CMYK
|
||||||
|
};
|
||||||
|
|
||||||
// structure for storing only the TIFF fields
|
// structure for storing only the TIFF fields
|
||||||
// that are of interest to the TIFFTranslator
|
// that are of interest to the TIFFTranslator
|
||||||
struct TiffDetails {
|
struct TiffDetails {
|
||||||
uint32 width;
|
uint32 width;
|
||||||
uint32 height;
|
uint32 height;
|
||||||
uint32 compression;
|
uint32 compression;
|
||||||
|
uint32 rowsPerStrip;
|
||||||
|
uint32 stripsPerImage;
|
||||||
|
uint32 *pstripOffsets;
|
||||||
|
uint32 *pstripByteCounts;
|
||||||
uint16 interpretation;
|
uint16 interpretation;
|
||||||
|
uint16 imageType;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TIFFTranslator : public BTranslator {
|
class TIFFTranslator : public BTranslator {
|
||||||
|
|||||||
@@ -60,15 +60,20 @@
|
|||||||
#define PHOTO_RGB 2
|
#define PHOTO_RGB 2
|
||||||
#define PHOTO_PALETTE 3
|
#define PHOTO_PALETTE 3
|
||||||
#define PHOTO_MASK 4
|
#define PHOTO_MASK 4
|
||||||
|
#define PHOTO_SEPARATED 5
|
||||||
#define TAG_FILL_ORDER 266
|
#define TAG_FILL_ORDER 266
|
||||||
#define TAG_STRIP_OFFSETS 273
|
#define TAG_STRIP_OFFSETS 273
|
||||||
#define TAG_ORIENTATION 274
|
#define TAG_ORIENTATION 274
|
||||||
#define TAG_SAMPLES_PER_PIXEL 277
|
#define TAG_SAMPLES_PER_PIXEL 277
|
||||||
#define TAG_ROWS_PER_STRIP 278
|
#define TAG_ROWS_PER_STRIP 278
|
||||||
|
#define DEFAULT_ROWS_PER_STRIP 4294967295L
|
||||||
#define TAG_STRIP_BYTE_COUNTS 279
|
#define TAG_STRIP_BYTE_COUNTS 279
|
||||||
#define TAG_PLANAR_CONFIGURATION 284
|
#define TAG_PLANAR_CONFIGURATION 284
|
||||||
#define TAG_RESOLUTION_UNIT 296
|
#define TAG_RESOLUTION_UNIT 296
|
||||||
#define TAG_COLOR_MAP 320
|
#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_EXTRA_SAMPLES 338
|
||||||
#define TAG_SAMPLE_FORMAT 339
|
#define TAG_SAMPLE_FORMAT 339
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,42 @@ TiffIfd::GetUint(uint16 tag, uint32 index)
|
|||||||
throw TiffIfdFieldNotFoundException();
|
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 *
|
TiffField *
|
||||||
TiffIfd::GetField(uint16 tag)
|
TiffIfd::GetField(uint16 tag)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ class TiffIfdBadIndexException : public TiffIfdException {
|
|||||||
public:
|
public:
|
||||||
TiffIfdBadIndexException() { };
|
TiffIfdBadIndexException() { };
|
||||||
};
|
};
|
||||||
|
class TiffIfdNoMemoryException : public TiffIfdException {
|
||||||
|
public:
|
||||||
|
TiffIfdNoMemoryException() { };
|
||||||
|
};
|
||||||
|
|
||||||
class TiffIfd {
|
class TiffIfd {
|
||||||
public:
|
public:
|
||||||
@@ -73,6 +77,16 @@ public:
|
|||||||
// throws: TiffIfdFieldNotFoundException(),
|
// throws: TiffIfdFieldNotFoundException(),
|
||||||
// TiffIfdUnexpectedTypeException(),
|
// TiffIfdUnexpectedTypeException(),
|
||||||
// TiffIfdBadIndexException()
|
// 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:
|
private:
|
||||||
void LoadFields(uint32 offset, BPositionIO &io, swap_action swp);
|
void LoadFields(uint32 offset, BPositionIO &io, swap_action swp);
|
||||||
|
|||||||
Reference in New Issue
Block a user