diff options
Diffstat (limited to 'modules/autorotate/lib/pel/PelTiff.php')
| -rw-r--r-- | modules/autorotate/lib/pel/PelTiff.php | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/modules/autorotate/lib/pel/PelTiff.php b/modules/autorotate/lib/pel/PelTiff.php new file mode 100644 index 0000000..6f4af75 --- /dev/null +++ b/modules/autorotate/lib/pel/PelTiff.php @@ -0,0 +1,297 @@ +<?php + +/** + * PEL: PHP Exif Library. A library with support for reading and + * writing all Exif headers in JPEG and TIFF images using PHP. + * + * Copyright (C) 2004, 2005, 2006 Martin Geisler. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program in the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/* $Id$ */ + + +/** + * Classes for dealing with TIFF data. + * + * @author Martin Geisler <mgeisler@users.sourceforge.net> + * @version $Revision$ + * @date $Date$ + * @license http://www.gnu.org/licenses/gpl.html GNU General Public + * License (GPL) + * @package PEL + */ + +/**#@+ Required class definitions. */ +require_once('PelDataWindow.php'); +require_once('PelIfd.php'); +require_once('Pel.php'); +/**#@-*/ + + +/** + * Class for handling TIFF data. + * + * Exif data is actually an extension of the TIFF file format. TIFF + * images consist of a number of {@link PelIfd Image File Directories} + * (IFDs), each containing a number of {@link PelEntry entries}. The + * IFDs are linked to each other --- one can get hold of the first one + * with the {@link getIfd()} method. + * + * To parse a TIFF image for Exif data one would do: + * + * <code> + * $tiff = new PelTiff($data); + * $ifd0 = $tiff->getIfd(); + * $exif = $ifd0->getSubIfd(PelIfd::EXIF); + * $ifd1 = $ifd0->getNextIfd(); + * </code> + * + * Should one have some image data of an unknown type, then the {@link + * PelTiff::isValid()} function is handy: it will quickly test if the + * data could be valid TIFF data. The {@link PelJpeg::isValid()} + * function does the same for JPEG images. + * + * @author Martin Geisler <mgeisler@users.sourceforge.net> + * @package PEL + */ +class PelTiff { + + /** + * TIFF header. + * + * This must follow after the two bytes indicating the byte order. + */ + const TIFF_HEADER = 0x002A; + + /** + * The first Image File Directory, if any. + * + * If set, then the type of the IFD must be {@link PelIfd::IFD0}. + * + * @var PelIfd + */ + private $ifd = null; + + + /** + * Construct a new object for holding TIFF data. + * + * The new object will be empty (with no {@link PelIfd}) unless an + * argument is given from which it can initialize itself. This can + * either be the filename of a TIFF image or a {@link PelDataWindow} + * object. + * + * Use {@link setIfd()} to explicitly set the IFD. + */ + function __construct($data = false) { + if ($data === false) + return; + + if (is_string($data)) { + Pel::debug('Initializing PelTiff object from %s', $data); + $this->loadFile($data); + } elseif ($data instanceof PelDataWindow) { + Pel::debug('Initializing PelTiff object from PelDataWindow.'); + $this->load($data); + } else { + throw new PelInvalidArgumentException('Bad type for $data: %s', + gettype($data)); + } + } + + + /** + * Load TIFF data. + * + * The data given will be parsed and an internal tree representation + * will be built. If the data cannot be parsed correctly, a {@link + * PelInvalidDataException} is thrown, explaining the problem. + * + * @param PelDataWindow the data from which the object will be + * constructed. This should be valid TIFF data, coming either + * directly from a TIFF image or from the Exif data in a JPEG image. + */ + function load(PelDataWindow $d) { + Pel::debug('Parsing %d bytes of TIFF data...', $d->getSize()); + + /* There must be at least 8 bytes available: 2 bytes for the byte + * order, 2 bytes for the TIFF header, and 4 bytes for the offset + * to the first IFD. */ + if ($d->getSize() < 8) + throw new PelInvalidDataException('Expected at least 8 bytes of TIFF ' . + 'data, found just %d bytes.', + $d->getSize()); + + /* Byte order */ + if ($d->strcmp(0, 'II')) { + Pel::debug('Found Intel byte order'); + $d->setByteOrder(PelConvert::LITTLE_ENDIAN); + } elseif ($d->strcmp(0, 'MM')) { + Pel::debug('Found Motorola byte order'); + $d->setByteOrder(PelConvert::BIG_ENDIAN); + } else { + throw new PelInvalidDataException('Unknown byte order found in TIFF ' . + 'data: 0x%2X%2X', + $d->getByte(0), $d->getByte(1)); + } + + /* Verify the TIFF header */ + if ($d->getShort(2) != self::TIFF_HEADER) + throw new PelInvalidDataException('Missing TIFF magic value.'); + + /* IFD 0 offset */ + $offset = $d->getLong(4); + Pel::debug('First IFD at offset %d.', $offset); + + if ($offset > 0) { + /* Parse the first IFD, this will automatically parse the + * following IFDs and any sub IFDs. */ + $this->ifd = new PelIfd(PelIfd::IFD0); + $this->ifd->load($d, $offset); + } + } + + + /** + * Load data from a file into a TIFF object. + * + * @param string the filename. This must be a readable file. + */ + function loadFile($filename) { + $this->load(new PelDataWindow(file_get_contents($filename))); + } + + + /** + * Set the first IFD. + * + * @param PelIfd the new first IFD, which must be of type {@link + * PelIfd::IFD0}. + */ + function setIfd(PelIfd $ifd) { + if ($ifd->getType() != PelIfd::IFD0) + throw new PelInvalidDataException('Invalid type of IFD: %d, expected %d.', + $ifd->getType(), PelIfd::IFD0); + + $this->ifd = $ifd; + } + + + /** + * Return the first IFD. + * + * @return PelIfd the first IFD contained in the TIFF data, if any. + * If there is no IFD null will be returned. + */ + function getIfd() { + return $this->ifd; + } + + + /** + * Turn this object into bytes. + * + * TIFF images can have {@link PelConvert::LITTLE_ENDIAN + * little-endian} or {@link PelConvert::BIG_ENDIAN big-endian} byte + * order, and so this method takes an argument specifying that. + * + * @param PelByteOrder the desired byte order of the TIFF data. + * This should be one of {@link PelConvert::LITTLE_ENDIAN} or {@link + * PelConvert::BIG_ENDIAN}. + * + * @return string the bytes representing this object. + */ + function getBytes($order = PelConvert::LITTLE_ENDIAN) { + if ($order == PelConvert::LITTLE_ENDIAN) + $bytes = 'II'; + else + $bytes = 'MM'; + + /* TIFF magic number --- fixed value. */ + $bytes .= PelConvert::shortToBytes(self::TIFF_HEADER, $order); + + if ($this->ifd != null) { + /* IFD 0 offset. We will always start IDF 0 at an offset of 8 + * bytes (2 bytes for byte order, another 2 bytes for the TIFF + * header, and 4 bytes for the IFD 0 offset make 8 bytes + * together). + */ + $bytes .= PelConvert::longToBytes(8, $order); + + /* The argument specifies the offset of this IFD. The IFD will + * use this to calculate offsets from the entries to their data, + * all those offsets are absolute offsets counted from the + * beginning of the data. */ + $bytes .= $this->ifd->getBytes(8, $order); + } else { + $bytes .= PelConvert::longToBytes(0, $order); + } + + return $bytes; + } + + + /** + * Return a string representation of this object. + * + * @return string a string describing this object. This is mostly useful + * for debugging. + */ + function __toString() { + $str = Pel::fmt("Dumping TIFF data...\n"); + if ($this->ifd != null) + $str .= $this->ifd->__toString(); + + return $str; + } + + + /** + * Check if data is valid TIFF data. + * + * This will read just enough data from the data window to determine + * if the data could be a valid TIFF data. This means that the + * check is more like a heuristic than a rigorous check. + * + * @param PelDataWindow the bytes that will be examined. + * + * @return boolean true if the data looks like valid TIFF data, + * false otherwise. + * + * @see PelJpeg::isValid() + */ + static function isValid(PelDataWindow $d) { + /* First check that we have enough data. */ + if ($d->getSize() < 8) + return false; + + /* Byte order */ + if ($d->strcmp(0, 'II')) { + $d->setByteOrder(PelConvert::LITTLE_ENDIAN); + } elseif ($d->strcmp(0, 'MM')) { + Pel::debug('Found Motorola byte order'); + $d->setByteOrder(PelConvert::BIG_ENDIAN); + } else { + return false; + } + + /* Verify the TIFF header */ + return $d->getShort(2) == self::TIFF_HEADER; + } + +}
\ No newline at end of file |
