public function getBytes($offset, $order)
{
$bytes = '';
$extra_bytes = '';
Pel::debug('Bytes from IDF will start at offset %d within Exif data', $offset);
$n = count($this->entries) + count($this->sub);
if ($this->thumb_data !== null) {
/*
* We need two extra entries for the thumbnail offset and
* length.
*/
$n += 2;
}
$bytes .= PelConvert::shortToBytes($n, $order);
/*
* Initialize offset of extra data. This included the bytes
* preceding this IFD, the bytes needed for the count of entries,
* the entries themselves (and sub entries), the extra data in the
* entries, and the IFD link.
*/
$end = $offset + 2 + 12 * $n + 4;
foreach ($this->entries as $tag => $entry) {
/* Each entry is 12 bytes long. */
$bytes .= PelConvert::shortToBytes($entry->getTag(), $order);
$bytes .= PelConvert::shortToBytes($entry->getFormat(), $order);
$bytes .= PelConvert::longToBytes($entry->getComponents(), $order);
/*
* Size? If bigger than 4 bytes, the actual data is not in
* the entry but somewhere else.
*/
$data = $entry->getBytes($order);
$s = strlen($data);
if ($s > 4) {
Pel::debug('Data size %d too big, storing at offset %d instead.', $s, $end);
$bytes .= PelConvert::longToBytes($end, $order);
$extra_bytes .= $data;
$end += $s;
} else {
Pel::debug('Data size %d fits.', $s);
/*
* Copy data directly, pad with NULL bytes as necessary to
* fill out the four bytes available.
*/
$bytes .= $data . str_repeat(chr(0), 4 - $s);
}
}
if ($this->thumb_data !== null) {
Pel::debug('Appending %d bytes of thumbnail data at %d', $this->thumb_data->getSize(), $end);
// TODO: make PelEntry a class that can be constructed with
// arguments corresponding to the newt four lines.
$bytes .= PelConvert::shortToBytes(PelTag::JPEG_INTERCHANGE_FORMAT_LENGTH, $order);
$bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
$bytes .= PelConvert::longToBytes(1, $order);
$bytes .= PelConvert::longToBytes($this->thumb_data->getSize(), $order);
$bytes .= PelConvert::shortToBytes(PelTag::JPEG_INTERCHANGE_FORMAT, $order);
$bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
$bytes .= PelConvert::longToBytes(1, $order);
$bytes .= PelConvert::longToBytes($end, $order);
$extra_bytes .= $this->thumb_data->getBytes();
$end += $this->thumb_data->getSize();
}
/* Find bytes from sub IFDs. */
$sub_bytes = '';
foreach ($this->sub as $type => $sub) {
if ($type == PelIfd::EXIF) {
$tag = PelTag::EXIF_IFD_POINTER;
} elseif ($type == PelIfd::GPS) {
$tag = PelTag::GPS_INFO_IFD_POINTER;
} elseif ($type == PelIfd::INTEROPERABILITY) {
$tag = PelTag::INTEROPERABILITY_IFD_POINTER;
}
/* Make an aditional entry with the pointer. */
$bytes .= PelConvert::shortToBytes($tag, $order);
/* Next the format, which is always unsigned long. */
$bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
/* There is only one component. */
$bytes .= PelConvert::longToBytes(1, $order);
$data = $sub->getBytes($end, $order);
$s = strlen($data);
$sub_bytes .= $data;
$bytes .= PelConvert::longToBytes($end, $order);
$end += $s;
}
/* Make link to next IFD, if any */
if ($this->isLastIFD()) {
$link = 0;
} else {
$link = $end;
}
Pel::debug('Link to next IFD: %d', $link);
$bytes .= PelConvert::longtoBytes($link, $order);
$bytes .= $extra_bytes . $sub_bytes;
if (!$this->isLastIfd()) {
$bytes .= $this->next->getBytes($end, $order);
}
return $bytes;
}