4 * PEL: PHP Exif Library.
5 * A library with support for reading and
6 * writing all Exif headers in JPEG and TIFF images using PHP.
8 * Copyright (C) 2004, 2005, 2006 Martin Geisler.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program in the file COPYING; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301 USA
25 namespace lsolesen\pel;
28 * Classes for dealing with TIFF data.
30 * @author Martin Geisler <mgeisler@users.sourceforge.net>
31 * @license http://www.gnu.org/licenses/gpl.html GNU General Public
37 * Class for handling TIFF data.
39 * Exif data is actually an extension of the TIFF file format. TIFF
40 * images consist of a number of {@link PelIfd Image File Directories}
41 * (IFDs), each containing a number of {@link PelEntry entries}. The
42 * IFDs are linked to each other --- one can get hold of the first one
43 * with the {@link getIfd()} method.
45 * To parse a TIFF image for Exif data one would do:
48 * $tiff = new PelTiff($data);
49 * $ifd0 = $tiff->getIfd();
50 * $exif = $ifd0->getSubIfd(PelIfd::EXIF);
51 * $ifd1 = $ifd0->getNextIfd();
54 * Should one have some image data of an unknown type, then the {@link
55 * PelTiff::isValid()} function is handy: it will quickly test if the
56 * data could be valid TIFF data. The {@link PelJpeg::isValid()}
57 * function does the same for JPEG images.
59 * @author Martin Geisler <mgeisler@users.sourceforge.net>
68 * This must follow after the two bytes indicating the byte order.
70 const TIFF_HEADER = 0x002A;
73 * The first Image File Directory, if any.
75 * If set, then the type of the IFD must be {@link PelIfd::IFD0}.
82 * Construct a new object for holding TIFF data.
84 * The new object will be empty (with no {@link PelIfd}) unless an
85 * argument is given from which it can initialize itself. This can
86 * either be the filename of a TIFF image or a {@link PelDataWindow}
89 * Use {@link setIfd()} to explicitly set the IFD.
91 * @param boolean|string|PelDataWindow $data;
93 public function __construct($data = false)
95 if ($data === false) {
98 if (is_string($data)) {
99 Pel::debug('Initializing PelTiff object from %s', $data);
100 $this->loadFile($data);
101 } elseif ($data instanceof PelDataWindow) {
102 Pel::debug('Initializing PelTiff object from PelDataWindow.');
105 throw new PelInvalidArgumentException('Bad type for $data: %s', gettype($data));
112 * The data given will be parsed and an internal tree representation
113 * will be built. If the data cannot be parsed correctly, a {@link
114 * PelInvalidDataException} is thrown, explaining the problem.
118 * PelDataWindow the data from which the object will be
119 * constructed. This should be valid TIFF data, coming either
120 * directly from a TIFF image or from the Exif data in a JPEG image.
122 public function load(PelDataWindow $d)
124 Pel::debug('Parsing %d bytes of TIFF data...', $d->getSize());
127 * There must be at least 8 bytes available: 2 bytes for the byte
128 * order, 2 bytes for the TIFF header, and 4 bytes for the offset
131 if ($d->getSize() < 8) {
132 throw new PelInvalidDataException('Expected at least 8 bytes of TIFF ' . 'data, found just %d bytes.', $d->getSize());
135 if ($d->strcmp(0, 'II')) {
136 Pel::debug('Found Intel byte order');
137 $d->setByteOrder(PelConvert::LITTLE_ENDIAN);
138 } elseif ($d->strcmp(0, 'MM')) {
139 Pel::debug('Found Motorola byte order');
140 $d->setByteOrder(PelConvert::BIG_ENDIAN);
142 throw new PelInvalidDataException('Unknown byte order found in TIFF ' . 'data: 0x%2X%2X', $d->getByte(0), $d->getByte(1));
145 /* Verify the TIFF header */
146 if ($d->getShort(2) != self::TIFF_HEADER) {
147 throw new PelInvalidDataException('Missing TIFF magic value.');
150 $offset = $d->getLong(4);
151 Pel::debug('First IFD at offset %d.', $offset);
155 * Parse the first IFD, this will automatically parse the
156 * following IFDs and any sub IFDs.
158 $this->ifd = new PelIfd(PelIfd::IFD0);
159 $this->ifd->load($d, $offset);
164 * Load data from a file into a TIFF object.
166 * @param string $filename
167 * the filename. This must be a readable file.
169 public function loadFile($filename)
171 $this->load(new PelDataWindow(file_get_contents($filename)));
178 * the new first IFD, which must be of type {@link
181 public function setIfd(PelIfd $ifd)
183 if ($ifd->getType() != PelIfd::IFD0) {
184 throw new PelInvalidDataException('Invalid type of IFD: %d, expected %d.', $ifd->getType(), PelIfd::IFD0);
190 * Return the first IFD.
192 * @return PelIfd the first IFD contained in the TIFF data, if any.
193 * If there is no IFD null will be returned.
195 public function getIfd()
201 * Turn this object into bytes.
203 * TIFF images can have {@link PelConvert::LITTLE_ENDIAN
204 * little-endian} or {@link PelConvert::BIG_ENDIAN big-endian} byte
205 * order, and so this method takes an argument specifying that.
207 * @param PelByteOrder $order
208 * the desired byte order of the TIFF data.
209 * This should be one of {@link PelConvert::LITTLE_ENDIAN} or {@link
210 * PelConvert::BIG_ENDIAN}.
212 * @return string the bytes representing this object.
214 public function getBytes($order = PelConvert::LITTLE_ENDIAN)
216 if ($order == PelConvert::LITTLE_ENDIAN) {
222 /* TIFF magic number --- fixed value. */
223 $bytes .= PelConvert::shortToBytes(self::TIFF_HEADER, $order);
225 if ($this->ifd !== null) {
227 * IFD 0 offset. We will always start IDF 0 at an offset of 8
228 * bytes (2 bytes for byte order, another 2 bytes for the TIFF
229 * header, and 4 bytes for the IFD 0 offset make 8 bytes
232 $bytes .= PelConvert::longToBytes(8, $order);
235 * The argument specifies the offset of this IFD. The IFD will
236 * use this to calculate offsets from the entries to their data,
237 * all those offsets are absolute offsets counted from the
238 * beginning of the data.
240 $bytes .= $this->ifd->getBytes(8, $order);
242 $bytes .= PelConvert::longToBytes(0, $order);
249 * Save the TIFF object as a TIFF image in a file.
252 * string the filename to save in. An existing file with the
253 * same name will be overwritten!
255 * @return integer|FALSE The number of bytes that were written to the
256 * file, or FALSE on failure.
258 public function saveFile($filename)
260 return file_put_contents($filename, $this->getBytes());
264 * Return a string representation of this object.
266 * @return string a string describing this object. This is mostly useful
269 public function __toString()
271 $str = Pel::fmt("Dumping TIFF data...\n");
272 if ($this->ifd !== null) {
273 $str .= $this->ifd->__toString();
280 * Check if data is valid TIFF data.
282 * This will read just enough data from the data window to determine
283 * if the data could be a valid TIFF data. This means that the
284 * check is more like a heuristic than a rigorous check.
286 * @param PelDataWindow $d
287 * the bytes that will be examined.
289 * @return boolean true if the data looks like valid TIFF data,
292 * @see PelJpeg::isValid()
294 public static function isValid(PelDataWindow $d)
296 /* First check that we have enough data. */
297 if ($d->getSize() < 8) {
302 if ($d->strcmp(0, 'II')) {
303 $d->setByteOrder(PelConvert::LITTLE_ENDIAN);
304 } elseif ($d->strcmp(0, 'MM')) {
305 Pel::debug('Found Motorola byte order');
306 $d->setByteOrder(PelConvert::BIG_ENDIAN);
311 /* Verify the TIFF header */
312 return $d->getShort(2) == self::TIFF_HEADER;