twain2/hugaotwainds/CTiffWriter.cpp

289 lines
8.7 KiB
C++

/***************************************************************************
* Copyright ?2007 TWAIN Working Group:
* Adobe Systems Incorporated, AnyDoc Software Inc., Eastman Kodak Company,
* Fujitsu Computer Products of America, JFL Peripheral Solutions Inc.,
* Ricoh Corporation, and Xerox Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the TWAIN Working Group nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TWAIN Working Group ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL TWAIN Working Group BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
***************************************************************************/
/**
* @file CTiffWriter.cpp
* Write an image to disk as a tiff file.
* @author JFL Peripheral Solutions Inc.
* @date October 2007
*/
#include "stdafx.h"
#include "CTiffWriter.h"
#include <sstream>
CTiffWriter::CTiffWriter(const string& _filename,
const long int _width,
const long int _height,
const int _bitsPerPixel,
const unsigned long int _bytesPerRow)
{
m_pImageStream = 0;
m_nOffset = 0;
m_filename = _filename;
m_ImageWidth.TagID = kTIFF_TAG_IMGWIDTH;
m_ImageWidth.DataType = kTIFF_TY_LONG;
m_ImageWidth.DataCount = 1;
m_ImageWidth.DataOffset = _width;
m_ImageLength.TagID = kTIFF_TAG_IMGLENGTH;
m_ImageLength.DataType = kTIFF_TY_LONG;
m_ImageLength.DataCount = 1;
m_ImageLength.DataOffset = _height;
m_BitsPerSample.TagID = kTIFF_TAG_BITSPERSAMPLE;
m_BitsPerSample.DataType = kTIFF_TY_SHORT;
m_BitsPerSample.DataCount = 1;
if(24 == _bitsPerPixel)
{
m_BitsPerSample.DataOffset = 8;
}
else
{
m_BitsPerSample.DataOffset = _bitsPerPixel;
}
m_Compression.TagID = kTIFF_TAG_COMPRESSION;
m_Compression.DataType = kTIFF_TY_SHORT;
m_Compression.DataCount = 1;
m_Compression.DataOffset = 1;
m_PhotometricInterp.TagID = kTIFF_TAG_PHOTOMETRICINT;
m_PhotometricInterp.DataType = kTIFF_TY_SHORT;
m_PhotometricInterp.DataCount = 1;
if(24 == _bitsPerPixel)
{
m_PhotometricInterp.DataOffset = 2;
}
else
{
m_PhotometricInterp.DataOffset = 1;
}
// -there is only one strip that contains all the row data, and it starts right after the header.
// -There are always 12 tags being written for each tiff.
m_StripOffsets.TagID = kTIFF_TAG_STRIPOFFSETS;
m_StripOffsets.DataType = kTIFF_TY_SHORT;
m_StripOffsets.DataCount = 1;
m_StripOffsets.DataOffset = getSizeofHeader();
m_SamplesPerPixel.TagID = kTIFF_TAG_SAMPLESPERPIXEL;
m_SamplesPerPixel.DataType = kTIFF_TY_SHORT;
if(24 == _bitsPerPixel)
{
m_SamplesPerPixel.DataCount = 1;
m_SamplesPerPixel.DataOffset = 3;
}
else
{
m_SamplesPerPixel.DataCount = 1;
m_SamplesPerPixel.DataOffset = 1;
}
m_RowsPerStrip.TagID = kTIFF_TAG_ROWSPERSTRIP;
m_RowsPerStrip.DataType = kTIFF_TY_LONG;
m_RowsPerStrip.DataCount = 1;
m_RowsPerStrip.DataOffset = _height;
m_StripByteCounts.TagID = kTIFF_TAG_STRIPBYTECOUNTS;
m_StripByteCounts.DataType = kTIFF_TY_LONG;
m_StripByteCounts.DataCount = 1;
m_StripByteCounts.DataOffset = _bytesPerRow * _height;
m_XResolution.TagID = kTIFF_TAG_XRESOLUTION;
m_XResolution.DataType = kTIFF_TY_RATIONAL;
m_XResolution.DataCount = 1;
m_XResolution.DataOffset = m_StripOffsets.DataOffset - sizeof(DWORD)*4; // fixed offset from the end of the header
setXResolution(100, 1);
m_YResolution.TagID = kTIFF_TAG_YRESOLUTION;
m_YResolution.DataType = kTIFF_TY_RATIONAL;
m_YResolution.DataCount = 1;
m_YResolution.DataOffset = m_StripOffsets.DataOffset - sizeof(DWORD)*2; // fixed offset from the end of the header
setYResolution(100, 1);
m_ResolutionUnit.TagID = kTIFF_TAG_RESOLUTIONUNIT;
m_ResolutionUnit.DataType = kTIFF_TY_SHORT;
m_ResolutionUnit.DataCount = 1;
m_ResolutionUnit.DataOffset = 2;
}
CTiffWriter::~CTiffWriter()
{
if(0 != m_pImageStream)
{
if(m_pImageStream->is_open())
{
m_pImageStream->close();
}
delete m_pImageStream;
}
}
void CTiffWriter::setImageWidth(const long int _v)
{
m_ImageWidth.DataOffset = _v;
}
void CTiffWriter::setImageHeight(const long int _v)
{
m_ImageLength.DataOffset = _v;
}
void CTiffWriter::setBitsPerSample(const int _v)
{
m_BitsPerSample.DataOffset = _v;
}
void CTiffWriter::setCompression(const int _v)
{
m_Compression.DataOffset = _v;
}
void CTiffWriter::setPhotometricInterp(const int _v)
{
m_PhotometricInterp.DataOffset = _v;
}
void CTiffWriter::setSamplesPerPixel(const int _v)
{
m_SamplesPerPixel.DataOffset = _v;
}
void CTiffWriter::setXResolution(const int _numerator, const int _denominator)
{
m_xres[0] = _numerator;
m_xres[1] = _denominator;
}
void CTiffWriter::setYResolution(const int _numerator, const int _denominator)
{
m_yres[0] = _numerator;
m_yres[1] = _denominator;
}
void CTiffWriter::setBytesPerRow(const int _v)
{
m_StripByteCounts.DataOffset = _v * m_ImageLength.DataOffset;
}
void CTiffWriter::GetImageHeader(stringstream &Header)
{
// write the header
TIFFIFH hdr = {0x4949, 0x002a, sizeof(TIFFIFH)};
Header.write(reinterpret_cast<char*>(&hdr), sizeof(TIFFIFH));
// write the Tags immediately after the header
WORD numTags = 12;
Header.write(reinterpret_cast<char*>(&numTags), sizeof(numTags));
const int nsize = sizeof(TIFFTag);
Header.write(reinterpret_cast<char*>(&m_ImageWidth), nsize);
Header.write(reinterpret_cast<char*>(&m_ImageLength), nsize);
Header.write(reinterpret_cast<char*>(&m_BitsPerSample), nsize);
Header.write(reinterpret_cast<char*>(&m_Compression), nsize);
Header.write(reinterpret_cast<char*>(&m_PhotometricInterp), nsize);
Header.write(reinterpret_cast<char*>(&m_StripOffsets), nsize);
Header.write(reinterpret_cast<char*>(&m_SamplesPerPixel), nsize);
Header.write(reinterpret_cast<char*>(&m_RowsPerStrip), nsize);
Header.write(reinterpret_cast<char*>(&m_StripByteCounts), nsize);
Header.write(reinterpret_cast<char*>(&m_XResolution), nsize);
Header.write(reinterpret_cast<char*>(&m_YResolution), nsize);
Header.write(reinterpret_cast<char*>(&m_ResolutionUnit), nsize);
// end the header by setting the next image offset to null
DWORD end = 0;
Header.write(reinterpret_cast<char*>(&end), sizeof(end));
// write the X and Y resolutions
Header.write(reinterpret_cast<char*>(&m_xres), sizeof(DWORD)*2);
Header.write(reinterpret_cast<char*>(&m_yres), sizeof(DWORD)*2);
}
bool CTiffWriter::writeImageHeader()
{
// create the out stream if not done so already
if(0 == m_pImageStream)
{
m_pImageStream = new ofstream();
}
// open the stream. If already open, reset it
if(m_pImageStream->is_open())
{
m_pImageStream->seekp(0);
}
else
{
m_pImageStream->open(m_filename.c_str(), ios_base::out|ios_base::binary|ios_base::trunc);
}
stringstream Header;
GetImageHeader(Header);
Header.seekp(0, ios_base::end);
m_nOffset =(int) Header.tellp();
Header.seekg(0, ios_base::beg);
char *pData = new char[m_nOffset];
Header.read(pData,m_nOffset);
m_pImageStream->write(pData,m_nOffset);
delete []pData;
return true;
}
bool CTiffWriter::WriteTIFFData(char *_pData, DWORD _nCount)
{
bool bret = false;
if(0 != m_pImageStream &&
m_pImageStream->good())
{
m_pImageStream->seekp(m_nOffset);
m_pImageStream->write(_pData, _nCount);
m_nOffset += _nCount;
bret = true;
}
return bret;
}
unsigned int CTiffWriter::getSizeofHeader()
{
// Header is as follows:
// TIFFIFH + Num. of Tags + each tag + Xres Data (2 dwords) + Yres Data (2 dwords) + Next Image offset (1 dword)
return sizeof(TIFFIFH)+sizeof(WORD)+sizeof(TIFFTag)*12+sizeof(DWORD)*5;
}