/** * 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 into a Image File Directory (IFD). * * @param PelDataWindow the data window that will provide the data. * * @param int the offset within the window where the directory will * be found. */ function load(PelDataWindow $d, $offset) { $thumb_offset = 0; $thumb_length = 0; Pel::debug('Constructing IFD at offset %d from %d bytes...', $offset, $d->getSize()); /* Read the number of entries */ $n = $d->getShort($offset); Pel::debug('Loading %d entries...', $n); $offset += 2; /* Check if we have enough data. */ if ($offset + 12 * $n > $d->getSize()) { $n = floor(($offset - $d->getSize()) / 12); Pel::maybeThrow(new PelIfdException('Adjusted to: %d.', $n)); } for ($i = 0; $i < $n; $i++) { // TODO: increment window start instead of using offsets. $tag = $d->getShort($offset + 12 * $i); Pel::debug('Loading entry with tag 0x%04X: %s (%d of %d)...', $tag, PelTag::getName($this->type, $tag), $i + 1, $n); switch ($tag) { case PelTag::EXIF_IFD_POINTER: case PelTag::GPS_INFO_IFD_POINTER: case PelTag::INTEROPERABILITY_IFD_POINTER: $o = $d->getLong($offset + 12 * $i + 8); Pel::debug('Found sub IFD at offset %d', $o); /* Map tag to IFD type. */ if ($tag == PelTag::EXIF_IFD_POINTER) { $type = PelIfd::EXIF; } elseif ($tag == PelTag::GPS_INFO_IFD_POINTER) { $type = PelIfd::GPS; } elseif ($tag == PelTag::INTEROPERABILITY_IFD_POINTER) { $type = PelIfd::INTEROPERABILITY; } $this->sub[$type] = new PelIfd($type); $this->sub[$type]->load($d, $o); break; case PelTag::JPEG_INTERCHANGE_FORMAT: $thumb_offset = $d->getLong($offset + 12 * $i + 8); $this->safeSetThumbnail($d, $thumb_offset, $thumb_length); break; case PelTag::JPEG_INTERCHANGE_FORMAT_LENGTH: $thumb_length = $d->getLong($offset + 12 * $i + 8); $this->safeSetThumbnail($d, $thumb_offset, $thumb_length); break; default: $format = $d->getShort($offset + 12 * $i + 2); $components = $d->getLong($offset + 12 * $i + 4); /* The data size. If bigger than 4 bytes, the actual data is * not in the entry but somewhere else, with the offset stored * in the entry. */ $s = PelFormat::getSize($format) * $components; if ($s > 0) { $doff = $offset + 12 * $i + 8; if ($s > 4) { $doff = $d->getLong($doff); } $data = $d->getClone($doff, $s); } else { $data = new PelDataWindow(); } try { $entry = $this->newEntryFromData($tag, $format, $components, $data); $this->addEntry($entry); } catch (PelException $e) { /* Throw the exception when running in strict mode, store * otherwise. */ Pel::maybeThrow($e); } /* The format of the thumbnail is stored in this tag. */ // TODO: handle TIFF thumbnail. // if ($tag == PelTag::COMPRESSION) { // $this->thumb_format = $data->getShort(); // } break; } } /* Offset to next IFD */ $o = $d->getLong($offset + 12 * $n); Pel::debug('Current offset is %d, link at %d points to %d.', $offset, $offset + 12 * $n, $o); if ($o > 0) { /* Sanity check: we need 6 bytes */ if ($o > $d->getSize() - 6) { Pel::maybeThrow(new PelIfdException('Bogus offset to next IFD: ' . '%d > %d!', $o, $d->getSize() - 6)); } else { if ($this->type == PelIfd::IFD1) { // IFD1 shouldn't link further... Pel::maybeThrow(new PelIfdException('IFD1 links to another IFD!')); } $this->next = new PelIfd(PelIfd::IFD1); $this->next->load($d, $o); } } else { Pel::debug('Last IFD.'); } }