/** * Turn this directory into bytes. * * This directory will be turned into a byte string, with the * specified byte order. The offsets will be calculated from the * offset given. * * @param int the offset of the first byte of this directory. * * @param PelByteOrder the byte order that should be used when * turning integers into bytes. This should be one of {@link * PelConvert::LITTLE_ENDIAN} and {@link PelConvert::BIG_ENDIAN}. */ 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; }