Example #1
0
 /**
  * Make a new entry from a bunch of bytes.
  *
  * This method will create the proper subclass of {@link PelEntry}
  * corresponding to the {@link PelTag} and {@link PelFormat} given.
  * The entry will be initialized with the data given.
  *
  * Please note that the data you pass to this method should come
  * from an image, that is, it should be raw bytes.  If instead you
  * want to create an entry for holding, say, an short integer, then
  * create a {@link PelEntryShort} object directly and load the data
  * into it.
  *
  * A {@link PelUnexpectedFormatException} is thrown if a mismatch is
  * discovered between the tag and format, and likewise a {@link
  * PelWrongComponentCountException} is thrown if the number of
  * components does not match the requirements of the tag.  The
  * requirements for a given tag (if any) can be found in the
  * documentation for {@link PelTag}.
  *
  * @param PelTag the tag of the entry.
  *
  * @param PelFormat the format of the entry.
  *
  * @param int the components in the entry.
  *
  * @param PelDataWindow the data which will be used to construct the
  * entry.
  *
  * @return PelEntry a newly created entry, holding the data given.
  */
 function newEntryFromData($tag, $format, $components, PelDataWindow $data)
 {
     /* First handle tags for which we have a specific PelEntryXXX
      * class. */
     switch ($this->type) {
         case self::IFD0:
         case self::IFD1:
         case self::EXIF:
         case self::INTEROPERABILITY:
             switch ($tag) {
                 case PelTag::DATE_TIME:
                 case PelTag::DATE_TIME_ORIGINAL:
                 case PelTag::DATE_TIME_DIGITIZED:
                     if ($format != PelFormat::ASCII) {
                         throw new PelUnexpectedFormatException($this->type, $tag, $format, PelFormat::ASCII);
                     }
                     if ($components != 20) {
                         throw new PelWrongComponentCountException($this->type, $tag, $components, 20);
                     }
                     // TODO: handle timezones.
                     return new PelEntryTime($tag, $data->getBytes(0, -1), PelEntryTime::EXIF_STRING);
                 case PelTag::COPYRIGHT:
                     if ($format != PelFormat::ASCII) {
                         throw new PelUnexpectedFormatException($this->type, $tag, $format, PelFormat::ASCII);
                     }
                     $v = explode("", trim($data->getBytes(), ' '));
                     return new PelEntryCopyright($v[0], $v[1]);
                 case PelTag::EXIF_VERSION:
                 case PelTag::FLASH_PIX_VERSION:
                 case PelTag::INTEROPERABILITY_VERSION:
                     if ($format != PelFormat::UNDEFINED) {
                         throw new PelUnexpectedFormatException($this->type, $tag, $format, PelFormat::UNDEFINED);
                     }
                     return new PelEntryVersion($tag, $data->getBytes() / 100);
                 case PelTag::USER_COMMENT:
                     if ($format != PelFormat::UNDEFINED) {
                         throw new PelUnexpectedFormatException($this->type, $tag, $format, PelFormat::UNDEFINED);
                     }
                     if ($data->getSize() < 8) {
                         return new PelEntryUserComment();
                     } else {
                         return new PelEntryUserComment($data->getBytes(8), rtrim($data->getBytes(0, 8)));
                     }
                 case PelTag::XP_TITLE:
                 case PelTag::XP_COMMENT:
                 case PelTag::XP_AUTHOR:
                 case PelTag::XP_KEYWORDS:
                 case PelTag::XP_SUBJECT:
                     if ($format != PelFormat::BYTE) {
                         throw new PelUnexpectedFormatException($this->type, $tag, $format, PelFormat::BYTE);
                     }
                     $v = '';
                     for ($i = 0; $i < $components; $i++) {
                         $b = $data->getByte($i);
                         /* Convert the byte to a character if it is non-null ---
                          * information about the character encoding of these entries
                          * would be very nice to have!  So far my tests have shown
                          * that characters in the Latin-1 character set are stored in
                          * a single byte followed by a NULL byte. */
                         if ($b != 0) {
                             $v .= chr($b);
                         }
                     }
                     return new PelEntryWindowsString($tag, $v);
             }
         case self::GPS:
         default:
             /* Then handle the basic formats. */
             switch ($format) {
                 case PelFormat::BYTE:
                     $v = new PelEntryByte($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getByte($i));
                     }
                     return $v;
                 case PelFormat::SBYTE:
                     $v = new PelEntrySByte($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getSByte($i));
                     }
                     return $v;
                 case PelFormat::ASCII:
                     return new PelEntryAscii($tag, $data->getBytes(0, -1));
                 case PelFormat::SHORT:
                     $v = new PelEntryShort($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getShort($i * 2));
                     }
                     return $v;
                 case PelFormat::SSHORT:
                     $v = new PelEntrySShort($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getSShort($i * 2));
                     }
                     return $v;
                 case PelFormat::LONG:
                     $v = new PelEntryLong($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getLong($i * 4));
                     }
                     return $v;
                 case PelFormat::SLONG:
                     $v = new PelEntrySLong($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getSLong($i * 4));
                     }
                     return $v;
                 case PelFormat::RATIONAL:
                     $v = new PelEntryRational($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getRational($i * 8));
                     }
                     return $v;
                 case PelFormat::SRATIONAL:
                     $v = new PelEntrySRational($tag);
                     for ($i = 0; $i < $components; $i++) {
                         $v->addNumber($data->getSRational($i * 8));
                     }
                     return $v;
                 case PelFormat::UNDEFINED:
                     return new PelEntryUndefined($tag, $data->getBytes());
                 default:
                     throw new PelException('Unsupported format: %s', PelFormat::getName($format));
             }
     }
 }
Example #2
0
 /**
  * Load data into a JPEG object.
  *
  * The data supplied will be parsed and turned into an object
  * structure representing the image.  This structure can then be
  * manipulated and later turned back into an string of bytes.
  *
  * This methods can be called at any time after a JPEG object has
  * been constructed, also after the {@link appendSection()} has been
  * called to append custom sections.  Loading several JPEG images
  * into one object will accumulate the sections, but there will only
  * be one {@link PelJpegMarker::SOS} section at any given time.
  *
  * @param PelDataWindow the data that will be turned into JPEG
  * sections.
  */
 function load(PelDataWindow $d)
 {
     Pel::debug('Parsing %d bytes...', $d->getSize());
     /* JPEG data is stored in big-endian format. */
     $d->setByteOrder(PelConvert::BIG_ENDIAN);
     /* Run through the data to read the sections in the image.  After
      * each section is read, the start of the data window will be
      * moved forward, and after the last section we'll terminate with
      * no data left in the window. */
     while ($d->getSize() > 0) {
         /* JPEG sections start with 0xFF. The first byte that is not
          * 0xFF is a marker (hopefully).
          */
         for ($i = 0; $i < 7; $i++) {
             if ($d->getByte($i) != 0xff) {
                 break;
             }
         }
         $marker = $d->getByte($i);
         if (!PelJpegMarker::isValid($marker)) {
             throw new PelJpegInvalidMarkerException($marker, $i);
         }
         /* Move window so first byte becomes first byte in this
          * section. */
         $d->setWindowStart($i + 1);
         if ($marker == PelJpegMarker::SOI || $marker == PelJpegMarker::EOI) {
             $content = new PelJpegContent(new PelDataWindow());
             $this->appendSection($marker, $content);
         } else {
             /* Read the length of the section.  The length includes the
              * two bytes used to store the length. */
             $len = $d->getShort(0) - 2;
             Pel::debug('Found %s section of length %d', PelJpegMarker::getName($marker), $len);
             /* Skip past the length. */
             $d->setWindowStart(2);
             if ($marker == PelJpegMarker::APP1) {
                 try {
                     $content = new PelExif();
                     $content->load($d->getClone(0, $len));
                 } catch (PelInvalidDataException $e) {
                     /* We store the data as normal JPEG content if it could
                      * not be parsed as Exif data. */
                     $content = new PelJpegContent($d->getClone(0, $len));
                 }
                 $this->appendSection($marker, $content);
                 /* Skip past the data. */
                 $d->setWindowStart($len);
             } elseif ($marker == PelJpegMarker::COM) {
                 $content = new PelJpegComment();
                 $content->load($d->getClone(0, $len));
                 $this->appendSection($marker, $content);
                 $d->setWindowStart($len);
             } else {
                 $content = new PelJpegContent($d->getClone(0, $len));
                 $this->appendSection($marker, $content);
                 /* Skip past the data. */
                 $d->setWindowStart($len);
                 /* In case of SOS, image data will follow. */
                 if ($marker == PelJpegMarker::SOS) {
                     /* Some images have some trailing (garbage?) following the
                      * EOI marker.  To handle this we seek backwards until we
                      * find the EOI marker.  Any trailing content is stored as
                      * a PelJpegContent object. */
                     $length = $d->getSize();
                     while ($d->getByte($length - 2) != 0xff || $d->getByte($length - 1) != PelJpegMarker::EOI) {
                         $length--;
                     }
                     $this->jpeg_data = $d->getClone(0, $length - 2);
                     Pel::debug('JPEG data: ' . $this->jpeg_data->__toString());
                     /* Append the EOI. */
                     $this->appendSection(PelJpegMarker::EOI, new PelJpegContent(new PelDataWindow()));
                     /* Now check to see if there are any trailing data. */
                     if ($length != $d->getSize()) {
                         Pel::maybeThrow(new PelException('Found trailing content ' . 'after EOI: %d bytes', $d->getSize() - $length));
                         $content = new PelJpegContent($d->getClone($length));
                         /* We don't have a proper JPEG marker for trailing
                          * garbage, so we just use 0x00... */
                         $this->appendSection(0x0, $content);
                     }
                     /* Done with the loop. */
                     break;
                 }
             }
         }
     }
     /* while ($d->getSize() > 0) */
 }
Example #3
0
 /**
  * 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 $d
  *            the bytes that will be examined.
  *
  * @return boolean true if the data looks like valid TIFF data,
  *         false otherwise.
  *
  * @see PelJpeg::isValid()
  */
 public 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;
 }
Example #4
0
 function testReadBigIntegers()
 {
     $window = new PelDataWindow("‰«Íï", PelConvert::BIG_ENDIAN);
     $this->assertEqual($window->getSize(), 4);
     $this->assertEqual($window->getBytes(), "‰«Íï");
     $this->assertEqual($window->getByte(0), 0x89);
     $this->assertEqual($window->getByte(1), 0xab);
     $this->assertEqual($window->getByte(2), 0xcd);
     $this->assertEqual($window->getByte(3), 0xef);
     $this->assertEqual($window->getShort(0), 0x89ab);
     $this->assertEqual($window->getShort(1), 0xabcd);
     $this->assertEqual($window->getShort(2), 0xcdef);
     $this->assertEqual($window->getLong(0), 0x89abcdef);
     $window->setByteOrder(PelConvert::LITTLE_ENDIAN);
     $this->assertEqual($window->getSize(), 4);
     $this->assertEqual($window->getBytes(), "‰«Íï");
     $this->assertEqual($window->getByte(0), 0x89);
     $this->assertEqual($window->getByte(1), 0xab);
     $this->assertEqual($window->getByte(2), 0xcd);
     $this->assertEqual($window->getByte(3), 0xef);
     $this->assertEqual($window->getShort(0), 0xab89);
     $this->assertEqual($window->getShort(1), 0xcdab);
     $this->assertEqual($window->getShort(2), 0xefcd);
     $this->assertEqual($window->getLong(0), 0xefcdab89);
 }