2
// Copyright (C) 1997 - 2007, Paul C. Gregory
4
// Contact: pgregory@aqsis.org
6
// This library is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU General Public
8
// License as published by the Free Software Foundation; either
9
// version 2 of the License, or (at your option) any later version.
11
// This library is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
// General Public License for more details.
16
// You should have received a copy of the GNU General Public
17
// License along with this library; if not, write to the Free Software
18
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
* \brief Tiled TIFF input interface.
24
* \author Chris Foster [chris42f (at) gmail (d0t) com]
27
#include "tiledtiffinputfile.h"
29
#include <boost/scoped_array.hpp>
31
#include <aqsis/tex/texexception.h>
35
CqTiledTiffInputFile::CqTiledTiffInputFile(const boostfs::path& fileName)
37
m_fileHandle(new CqTiffFileHandle(fileName, "r")),
38
m_numDirs(m_fileHandle->numDirectories()),
43
m_headers.reserve(m_numDirs);
44
m_widths.reserve(m_numDirs);
45
m_heights.reserve(m_numDirs);
46
// Iterate through all subimages and check some conditions which will
47
// become assumptions in the rest of the code.
48
for(TqInt i = 0; i < m_numDirs; ++i)
50
CqTiffDirHandle dirHandle(m_fileHandle, i);
51
boost::shared_ptr<CqTexFileHeader> tmpHeader(new CqTexFileHeader);
52
dirHandle.fillHeader(*tmpHeader);
53
// Check that the subimage is tiled.
54
SqTileInfo* tileInfo= tmpHeader->findPtr<Attr::TileInfo>();
57
AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "TIFF file \""
58
<< fileName << "\" has non-tiled sub-image " << i);
60
// Check that we can natively read the pixel format held in the TIFF.
61
if(tmpHeader->find<Attr::TiffUseGenericRGBA>())
63
AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile,
64
"Unsupported TIFF pixel format");
68
// Store the tile info from the first sub-image only. We force the
69
// tile sizes for other sub-images to match this.
70
m_tileInfo = *tileInfo;
74
// Check that the tile size is the same as the first image.
75
if(m_tileInfo.width != tileInfo->width
76
|| m_tileInfo.height != tileInfo->height)
78
AQSIS_THROW_XQERROR(XqBadTexture, EqE_BadFile, "TIFF file \""
79
<< fileName << "\" has unequal tile sizes for sub-images");
82
// Grab store the width and height of the current subimage.
83
m_widths.push_back(tmpHeader->width());
84
m_heights.push_back(tmpHeader->height());
85
// Store the header itself. Sometimes we really do need access to the
86
// extra attributes (eg, matrices for occlusion sampling). We could
87
// define special extra methods for these, but it bloats up the
89
m_headers.push_back(tmpHeader);
93
boostfs::path CqTiledTiffInputFile::fileName() const
95
return m_fileHandle->fileName();
98
EqImageFileType CqTiledTiffInputFile::fileType() const
100
return ImageFile_Tiff;
103
const CqTexFileHeader& CqTiledTiffInputFile::header(TqInt index) const
105
if(index >= 0 && index < m_numDirs)
106
return *m_headers[index];
108
return *m_headers[0];
111
SqTileInfo CqTiledTiffInputFile::tileInfo() const
116
TqInt CqTiledTiffInputFile::numSubImages() const
121
TqInt CqTiledTiffInputFile::width(TqInt index) const
123
assert(index < m_numDirs);
124
return m_widths[index];
127
TqInt CqTiledTiffInputFile::height(TqInt index) const
129
assert(index < m_numDirs);
130
return m_heights[index];
133
void CqTiledTiffInputFile::readTileImpl(TqUint8* buffer, TqInt x, TqInt y,
134
TqInt subImageIdx, const SqTileInfo tileSize) const
136
CqTiffDirHandle dirHandle(m_fileHandle, subImageIdx);
137
if((x+1)*m_tileInfo.width > m_widths[subImageIdx]
138
|| (y+1)*m_tileInfo.height > m_heights[subImageIdx])
140
// Here we handle a special case where the tile overlaps either the
141
// right or bottom edge of the image. In this case, libtiff reads in
142
// the tile as the same size as all other tiles, not touching the parts
143
// of buffer outside the image. We want to truncate the tile instead.
144
boost::scoped_array<TqUint8> tmpBuf(
145
new TqUint8[TIFFTileSize(dirHandle.tiffPtr())]);
146
TIFFReadTile(dirHandle.tiffPtr(), static_cast<tdata_t>(tmpBuf.get()),
147
x*m_tileInfo.width, y*m_tileInfo.height, 0, 0);
148
TqInt bytesPerPixel = m_headers[subImageIdx]->channelList().bytesPerPixel();
149
stridedCopy(buffer, tileSize.width*bytesPerPixel, tmpBuf.get(),
150
m_tileInfo.width*bytesPerPixel, tileSize.height,
151
tileSize.width*bytesPerPixel);
155
// Simple case for wholly contained buffers - the provided buffer is
156
// the correct size, and we get libtiff to read directly into it.
157
TIFFReadTile(dirHandle.tiffPtr(), static_cast<tdata_t>(buffer),
158
x*m_tileInfo.width, y*m_tileInfo.height, 0, 0);