Exemple #1
0
 /**
  * Load and parse Exif data.
  *
  * This will populate the object with Exif data, contained as a
  * {@link PelTiff} object. This TIFF object can be accessed with
  * the {@link getTiff()} method.
  *
  * @param PelDataWindow $d
  */
 public function load(PelDataWindow $d)
 {
     Pel::debug('Parsing %d bytes of Exif data...', $d->getSize());
     /* There must be at least 6 bytes for the Exif header. */
     if ($d->getSize() < 6) {
         throw new PelInvalidDataException('Expected at least 6 bytes of Exif ' . 'data, found just %d bytes.', $d->getSize());
     }
     /* Verify the Exif header */
     if ($d->strcmp(0, self::EXIF_HEADER)) {
         $d->setWindowStart(strlen(self::EXIF_HEADER));
     } else {
         throw new PelInvalidDataException('Exif header not found.');
     }
     /* The rest of the data is TIFF data. */
     $this->tiff = new PelTiff();
     $this->tiff->load($d);
 }
Exemple #2
0
 /**
  * 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;
 }
Exemple #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;
 }
Exemple #4
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) */
 }
setlocale(LC_ALL, '');
/* Load the required files.  One would normally just require the
 * PelJpeg.php file for dealing with JPEG images, but because this
 * example can handle both JPEG and TIFF it loads the PelDataWindow
 * class too. */
require_once dirname(__FILE__) . '/../PelDataWindow.php';
require_once dirname(__FILE__) . '/../PelJpeg.php';
require_once dirname(__FILE__) . '/../PelTiff.php';
/* Store the name of the script in $prog and remove this first part of
 * the command line. */
$prog = array_shift($argv);
$error = false;
/* The next argument could be -d to signal debug mode where lots of
 * extra information is printed out when the image is parsed. */
if (isset($argv[0]) && $argv[0] == '-d') {
    Pel::$debug = true;
    array_shift($argv);
}
/* The mandatory input filename. */
if (isset($argv[0])) {
    $input = array_shift($argv);
} else {
    $error = true;
}
/* The mandatory output filename. */
if (isset($argv[0])) {
    $output = array_shift($argv);
} else {
    $error = true;
}
/* Usage information is printed if an error was found in the command
Exemple #6
0
 /**
  * Enable/disable debugging output.
  *
  * @param boolean $flag
  *            use true to enable debug output, false to
  *            diable.
  */
 public static function setDebug($flag)
 {
     self::$debug = $flag;
 }
Exemple #7
0
 /**
  * Enable/disable debugging output.
  *
  * @param boolean $flag use true to enable debug output, false to
  * diable.
  */
 function setDebug($flag)
 {
     self::$debug = $flag;
 }