This commit is contained in:
2024-05-20 15:37:46 +03:00
commit 00b7dbd0b7
10404 changed files with 3285853 additions and 0 deletions

View File

@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitba6324246c1d906b530ebcb60468d7b9::getLoader();

View File

@ -0,0 +1,572 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
}

View File

@ -0,0 +1,350 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
$installed[] = self::$installed;
return $installed;
}
}

View File

@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,10 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View File

@ -0,0 +1,10 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'lsolesen\\pel\\' => array($vendorDir . '/lsolesen/pel/src'),
);

View File

@ -0,0 +1,57 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitba6324246c1d906b530ebcb60468d7b9
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInitba6324246c1d906b530ebcb60468d7b9', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInitba6324246c1d906b530ebcb60468d7b9', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitba6324246c1d906b530ebcb60468d7b9::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
return $loader;
}
}

View File

@ -0,0 +1,36 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitba6324246c1d906b530ebcb60468d7b9
{
public static $prefixLengthsPsr4 = array (
'l' =>
array (
'lsolesen\\pel\\' => 13,
),
);
public static $prefixDirsPsr4 = array (
'lsolesen\\pel\\' =>
array (
0 => __DIR__ . '/..' . '/lsolesen/pel/src',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitba6324246c1d906b530ebcb60468d7b9::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitba6324246c1d906b530ebcb60468d7b9::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitba6324246c1d906b530ebcb60468d7b9::$classMap;
}, null, ClassLoader::class);
}
}

View File

@ -0,0 +1,69 @@
{
"packages": [
{
"name": "lsolesen/pel",
"version": "0.9.12",
"version_normalized": "0.9.12.0",
"source": {
"type": "git",
"url": "https://github.com/pel/pel.git",
"reference": "b95fe29cdacf9d36330da277f10910a13648c84c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pel/pel/zipball/b95fe29cdacf9d36330da277f10910a13648c84c",
"reference": "b95fe29cdacf9d36330da277f10910a13648c84c",
"shasum": ""
},
"require": {
"php": ">=7.1.0"
},
"require-dev": {
"ext-exif": "*",
"ext-gd": "*",
"php-coveralls/php-coveralls": ">2.4",
"squizlabs/php_codesniffer": ">3.5",
"symfony/phpunit-bridge": "^4 || ^5"
},
"time": "2022-02-18T13:20:54+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"lsolesen\\pel\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0"
],
"authors": [
{
"name": "Lars Olesen",
"email": "lars@intraface.dk",
"homepage": "http://intraface.dk",
"role": "Developer"
},
{
"name": "Martin Geisler",
"email": "martin@geisler.net",
"homepage": "http://geisler.net",
"role": "Developer"
}
],
"description": "PHP Exif Library. A library for reading and writing Exif headers in JPEG and TIFF images using PHP.",
"homepage": "http://pel.github.com/pel/",
"keywords": [
"exif",
"image"
],
"support": {
"issues": "https://github.com/pel/pel/issues",
"source": "https://github.com/pel/pel/tree/0.9.12"
},
"install-path": "../lsolesen/pel"
}
],
"dev": true,
"dev-package-names": []
}

View File

@ -0,0 +1,32 @@
<?php return array(
'root' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '7c7818b3e0ef1be25af8125af68b5570bcbd60d9',
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '7c7818b3e0ef1be25af8125af68b5570bcbd60d9',
'dev_requirement' => false,
),
'lsolesen/pel' => array(
'pretty_version' => '0.9.12',
'version' => '0.9.12.0',
'type' => 'library',
'install_path' => __DIR__ . '/../lsolesen/pel',
'aliases' => array(),
'reference' => 'b95fe29cdacf9d36330da277f10910a13648c84c',
'dev_requirement' => false,
),
),
);

View File

@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}

Binary file not shown.

View File

@ -0,0 +1,16 @@
build:
environment:
php: '7.2'
tests:
override:
-
command: SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 ./vendor/bin/simple-phpunit --coverage-clover build/logs/clover.xml ./test
coverage:
file: build/logs/clover.xml
format: clover
checks:
php:
code_rating: true
duplication: true

View File

@ -0,0 +1,53 @@
AUTHORS file for PEL: PHP Exif Library. A library with support for
reading and writing Exif headers in JPEG and TIFF images using PHP.
Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
Copyright (c) 2008, 2009 Lars Olesen
Copyright (c) 2015 Johannes Weberhofer
Licensed under the GNU GPL, see COPYING for details.
Credits
*******
PEL is written by Martin Geisler <mgeisler@users.sourceforge.net> and
is now maintained by Lars Olesen <lars@intraface.dk>
and <jweberhofer@weberhofer.at>
The source started out as a port of the nice, clean C code found in
libexif. Most of the translations included with PEL also originates
from the libexif project, see below for details.
Test Image Contributors
***********************
Bernhard Bittel: Nikon E950 and E5000 test images.
Stéphanie Bittel: Canon IXUS II test image.
Lars Geisler: Nikon Coolscan IV ED test image.
Mikkel Krøigård: Canon PowerShot S60 test image.
Paul Mitchum: Pentax *ist DS and Olympus C-5050z test images.
Lisbeth Nygaard Pedersen: Leica D-LUX test image.
Thomas B. Pedersen: Olympus C-50z and C-765z test images.
Translators
***********
Danish: Martin Geisler.
French: Arnaud Launay (for libexif) and David Lesieur.
German: Hans Ulrich Niedermann, Lutz Möller (for libexif).
Japanese: Tadashi Jokagi.
Polish: Jakub Bogusz (for libexif).
Spanish: Fabian Mandelbaum (for libexif).

View File

@ -0,0 +1,584 @@
# CHANGELOG
## 0.9.11 - 2022-02-04
* Update dump-image.php
* Drop Travis CI config and add GitHub Actions
* Test from PHP 7.1 up only.
* Update badge in README
* Update tests.yml
* PHP 8.1 compatibility
* Added Eclipse project information
Thank you, @mondrake!
## 0.9.10 - 2021-01-01
* Breaking changes:
- The constructor of PelJpeg(filename) and PelJpeg::loadFile()
now throws a PelException if file can not be read.
* Get make-image-test.php working again
* Major refactorings and simplifications of code
* Fix of several issues detected by scrutinizer
## 0.9.9 - 2020-11-07
* Cast output from getBytes() to float (#155)
* Fix non-numeric value issue in PelIfd (#156, #163)
* Avoid division by zero. (#164)
## 0.9.8 - 2020-02-11
* Improved PHP 7.4 compatibility
* Improved TIFF handling
## 0.9.7 - 2019-12-03
Fixes some errors, refactor code and make compatible to PHP 7.4.
* Simplify phpunit dependency (#143)
* Updates in the README (#139, #137, #108)
* TravisCI tests up to PHP 7.4 and fix PHP 7.4 syntax (#142)
* XP tags fixed (#115)
* Improve IFD type names for Canon Maker Notes (#124)
* Move non-camera specific tests from /test/imagetests to /test (#123)
* Refactor ReadWriteTest and fix NumberTest (#122)
* Clean up the code and all the tests to match coding standards (#121)
* Convert to new array syntax (PHP 5.4) (#120)
* Update tests to run under PHPUnit 6+ and backwards to PHP 5.5 and 5.4 (#118)
* Catch DataWindow exceptions in PelIfd (#114)
* Fix several types (#113)
* Fix static makerNotes in PelIfd (#112)
* Fixes for [pel-Bugs-2979466 ] endless loop in PelIfd->load (#110)
* Fix build status badge (#111)
* Fix skipped tests for PHP 7.1+ (#109)
* Parsing canon maker notes (#99)
* Exif section corrections (#101)
* Enabled code rating (#106)
* Changed access of the $sections property to allow section manipulations in subclasses. (#104)
* Now available from PEL organization (#97)
* Enable PHP 7.2 build on TravisCI (#102)
* Rating percent tag (#100)
* Add composer installation instructions (#96)
* HHVM needs to run on Trusty (#95)
* Added reverse lookup methods, fixed PHPDOC for PelTag enumerations (#93)
## 0.9.6 - 2017-02-03
* Trim null characters from the end of ascii fields only when available. Fixes #77
## 0.9.5 - 2017-01-31
This release improves the code quality and the test coverage.
New features:
* new method PelTiff::saveFile()
* PHP 7.1 compatibility
## 0.9.4 - 2016-03-21
Notes:
This is mainly a cleanup version and better composer integration.
We added Scrutinizer, which should make sure that the code improves
in the future.
Changes:
* Improved performance of PelJpeg.
* Fixed wrong usage of private variable in examples.
## 0.9.3 - 2015-08-08
Notes:
This is a major update, and should have been the first tag of the
0.10.0 series. If you want to use the latest stable version without
namespaces, you should use 0.9.2.
Changes:
* Introduced namespaces.
* Added composer support and made it available on
[packagist.org](https://packagist.org/packages/lsolesen/pel) and
introduced PSR-4 autoloader.
* Major cleanup of the code and following PSR-2 standards.
## 0.9.2 - 2010-03-09
Notes:
This release is the last release before introducing namespaces.
Added a static method, Pel::setJPEGQuality(), for controlling the
quality for encoding JPEG images. Fixed bug in conversion between
Julian Day count and UNIX timestamps and removed dependency on the
calendar PHP extension. Fixed placement of Windows XP tags. Added GPS
example.
Changes:
* Added an example of how GPS information can be added. Thanks Andac
Aydin for contributing and testing this.
* Fixed PelJpegComment::getBytes(): it didn't return anything! Thanks
macondos.
* Fixed SF bug #1699489: Incorrect UNIX/Julian conversion.
* PEL 0.9.1 introduced a dependency on the calendar extension for PHP.
The necessary functions have now been reimplemented in pure PHP. The
patch was supplied by Francois Pirsch, thanks.
* Fixed doc comment for PelEntryTime, the variables for date() was
swapped. Thanks Francois Pirsch.
* Added static Pel::setJPEGQuality() and Pel::getJPEGQuality() method
for setting and getting the quality used when PelJpeg automatically
converts an image resource to a JPEG image. Thanks Csaba Gabor for
asking about this.
* Moved the XP specific tags from the Exif IFD to the IFD0/1 IFD.
Thanks Piotr Golebiowski for noticing this.
* Added links from PelTag::XP_* tags to the PelEntryWindowsString
class. Thanks Garrison Locke for indirectly pointing out the need
for this.
## 0.9.1 - 2016-12-19
Notes:
Added setExif(), getExif(), and clearExif() methods as a convenient
and recommended way of manipulating the Exif data in a PelJpeg object.
Improved PelEntryTime to deal with timestamps in the full range from
year 0 to year 9999. Removed PelTag::getDescription() because the
descriptions were out of context. A new example demonstrates how to
resize images while keeping the Exif data intact. Added a Japanese and
updated the French and Danish translations.
Changes:
* The constructors of PelJpeg and PelTiff can now take an argument
which is used for initialization. This can be a filename (equivalent
to calling loadFromFile()), a PelDataWindow (equivalent to load()).
The PelJpeg constructor will also accept an image resource.
* Added PelJpeg::setExif(). This method should always be used in
preference to PelJpeg::insertSection() and PelJpeg::appendSection().
One should actually not be using appendSection() unless one is very
sure that the image has not been ended by a EOI marker.
* Added PelJpeg::getExif(). This method is the new preferred way of
obtaining the PelExif object from a PelJpeg object. Updated the
examples and code to make use of it.
* An example of how to resize images while keeping the Exif data
intact is given in resize.php.
* The PelTag::getDescription() method is no more. The descriptions
were taken directly from the Exif specification and they were often
impossible to translate in a meaningful out of context because they
had references to figures and tables from said specification.
* Fixed bug in edit-description.php which still called the constructor
of PelIfd in the old pre-0.9 way.
* Updated documentation of PelIfd to make it clearer that it can be
used as an array because it implements the ArrayAccess SPL (Standard
PHP Library) interface.
* Added Japanese translation by Tadashi Jokagi.
* Update by David Lesieur of the French translation.
* Rewrote entry for version 0.9 in NEWS to highlight the API
incompatible changes made from version 0.8.
* Renamed test.php to run-tests.php and implemented a simple search
functionality for finding the SimpleTest installation.
* Rewrote make-release.sh script to work with Subversion.
## 0.9.0 - 2006-01-08
Notes:
Added full support for GPS information (this breaks API compatibility
with version 0.8), JPEG comments, the Gamma tag, and Windows XP
specific title, comment, author, keywords, and subject tags.
Implemented a non-strict mode for broken images where most errors wont
result in visible exceptions. The edit-description.php example now
correctly deals with images with no previous Exif data. A partial
Polish translation was added. The API documentation was updated with
details about the constrains on format and number of components for
each tag.
API incompatible changes:
* Changed PelIfd::getSubIfd() to take an IFD type as argument instead
of a PelTag. The IFD types are constants in PelIfd. So use
$exif = $ifd0->getSubIfd(PelIfd::EXIF);
instead of
$exif = $ifd0->getSubIfd(PelTag::EXIF_IFD_POINTER);
in your code.
* Added support for the GPS IFD. This API break compatibility with
version 0.8. The problem is that the GPS related tags have the same
value as some other tags, and so the function PelTag::getName(),
PelTag::getTitle(), and PelTag::getDescription() has been changed to
take an extra argument specifying IFD type of the tag.
This might change very well further in the future.
Changes:
* Added support for JPEG comments through the PelJpegComment class
which works almost like PelEntry (use getValue() and setValue() to
read and write the comment).
* Enabled iterating a PelIfd object with foreach(). It will iterate
over (PelTag, PelEntry) pairs.
* Added PelIfd::getValidTags() which return an array of tags valid for
the IFD in question. Using this, PEL now reject entries in wrong
IFDs. For example, you cannot have a UserComment tag in a IFD for
GPS information.
* Added a new concept of strict/non-strict mode. The old behavior
was strict mode where an errors would abort the loading of an image
because of exceptions --- in non-strict mode most exceptions will be
trapped and broken images can still be loaded. See the description
in Pel.php and the answer in the FAQ for more information.
* Added support for the 0xA500 Gamma tag.
* Changed paths in example shell scripts to /usr/bin/php and explained
in the README how to execute them.
* Updated FAQ with information about making Gettext work and the new
strict/non-strict mode.
* Added support for Windows XP specific title, comment, author,
keywords, and subject tags. These tags can be edited in Windows XP
in the Properties dialog found by right-clicking on an image.
* A number of translations in the German, French, and Spanish
translations were inactive because of small differences between PHP
and C (such as using %d and %i in format strings).
* Added Polish translation by Jakub Bogusz from the libexif project.
* Corrected tag documentation in PelTag.
* Made edit-description.php correctly add an empty Exif structure in
case the original image has none.
* Removed PelJpegContent::getSize() method. Calling this method in
the PelExif subclass resulted in an error, and overriding it
correctly in PelExif would have required too much code to justify
the effort.
* Better doc comments and small code cleanups in PelJpeg.php,
PelExif.php, and PelIfd.php.
* PelEntry.php now unconditionally includes the class definitions of
all the entry types. The conditionally loading only worked when one
created a new PelJpeg object, but not when one had stored such an
object in, say, a session.
* Moved PelEntry::newFromData() to PelIfd::newEntryFromData() since it
needs knowledge about PelIfd::$type. Updated the documentation it
to indicate that one shouldn't use this method unless the data comes
directly from an image. The method signature was corrected with a
type hint, so that $data really is a PelDataWindow.
* Updated the documentation in PelTag. All tags now details their
expected format and the expected number of components. One can
still freely choose to obey or disregard these constrains, but doing
so will lead to non-compliant images, which might cause PEL to throw
exceptions when reloading.
* Updated the documentation in PelFormat with links to the PelEntry
classes corresponding to each format.
* Updated the make-release.sh script to use a run-phpdoc.sh script for
generating the API documentation.
## 0.8.0 - 2005-02-18
Notes:
Erroneous entries will now be skipped while loading instead of causing
a total abort. The documentation was expanded with a short tutorial
and a FAQ. New test images were added from Leica D-LUX, Olympos C50Z
and C765 cameras.
Changes:
* Added more documentation in the form of a short tutorial and a FAQ.
* Instead of aborting on load errors, PelIfd::load() will now continue
with the next entry. A warning will be issued if debugging is
turned on in PEL.
* Added a PelEntryException class. When an entry cannot be loaded in
PelEntry::newFromData(), an appropriate subclass of this exception
will be thrown.
* Described the requirements in terms of formats and component counts
in the documentation for individual tags in PelTag.
* Fixed the edit-description.php example, it still used PelEntryString
instead of PelEntryAscii. Thanks goes to Achim Gerber.
* Fixed the throwing of a PelWrongComponentCountException in PelEntry,
the class name was misspelled.
* Added abstract getValue() and setValue() methods to PelEntry, to
better describe that all objects representing Exif entries have
those two methods.
* Updated copyright statements throughout the source to year 2005.
* Fixed (some) of the XHTML errors in the phpDocumentor template.
## 0.7.0 - 2004-10-10
Notes:
Running PEL under PHP version 5.0.2 would produce incorrect Exif data,
this was fixed so that PEL works correctly on all versions of PHP 5.
PEL now runs on installations without support for Gettext, but does so
with English texts only. A new example script was added, showing how
one can mass-rename images based on their timestamps using PEL. The
Danish translation was updated slightly. The collection of test
images has been split out as a separate download, cutting down on the
size of a PEL download.
Changes:
* The image tests are now split into their own, separate download.
* Added a test image from a Canon PowerShot S60.
* Fixed a bug caused by a change in the way PHP 5.0.2 handles integers
larger than 2^31-1. This change means that one can no longer use
PelConvert::longToBytes() to convert both signed and unsigned bytes,
one must now use sLongToBytes() for signed longs and longToBytes()
for unsigned bytes.
* Added a work-around, so the PEL will run (with English texts only)
on installations without support for Gettext.
* Added test/rename.php which shows how one can easily rename images
based on their Exif timestamps.
* Updated the Danish translation.
* Removed trailing newlines at the end of Pel.php and PelConvert.php.
## 0.6 - 2004-07-21
Notes:
The interface for PelJpeg and PelTiff was changed so that one can now
add new content from scratch to JPEG and TIFF images. Bugs in the
loading of signed bytes and shorts were fixed, as well as a bug where
timestamps were saved in UTC time, but loaded in local time. The code
that turned PelJpeg objects into bytes was fixed, and new test cases
were written to test the writing and reading of PelJpeg objects to and
from files. New images from Nikon models E950, E5000, and Coolscan IV
have been added to the test suite, bringing the total number of tests
up to more than 1000.
Changes:
* The timestamps were saved as UTC time in PelEntryTime, but loaded as
local time in PelEntry. This lead to differences when one tried to
load a previously saved timestamp.
* Changed the constructors in PelJpeg, PelExif, PelTiff, and PelIfd so
that one can now make new objects without filling them with data
immediately. This makes it possible to add, say, a new APP1 section
with Exif to a JPEG image lacking such information.
* Fixed loading of signed bytes and shorts in PelConvert.
* Renamed the isValidMarker() method into just isValid() in
PelJpegMarker, so that it matches the other isValid() methods found
in PelJpeg and PelTiff.
* Added test images from Nikon models E950, E5000 and the film scanner
Coolscan IV ED, and added tests that would read their contents.
* The shell scripts could only be run from the test directory because
of the use of relative paths in the require_once() statements. The
scripts can now be run from any directory.
* A stupid bug that prevented PelJpeg objects from being turned into
bytes was fixed.
* Fixed the output of PelEntryRationals::getText().
## 0.5.0 - 2004-06-28
Notes:
This release has been tested with images from a number of different
camera models (from Fujifilm, Nikon, Ricoh, Sony, and Canon), leading
to the discovery and fixing of a number of bugs. The API for
PelJpeg::getSection() was changed slightly, making it more convenient
to use. All classes and methods are now documented.
Changes:
* Some images have content following the EOI marker --- this would
make PEL thrown an exception. The content is now stored as a
PelJpegContent object associated with the fictive marker 0x00.
* Added code to handle images where the length of the thumbnail image
is broken. PEL would previously throw an exception, but the length
is now adjusted instead, and the parsing continues.
* Fixed a number of bugs regarding the conversion back and forth
between integers and bytes. These bugs affected the parsing of
large integers that would overflow a signed 32 bit integer.
* Fixed bug #976782. If an image contains two APP1 sections, PEL
would crash trying to parse the second non-Exif section. PEL will
now just store a non-Exif APP1 section as a generic PelJpegContent
object.
* Removed the PelJpegSection class. This lead to a rewrite of the
PelJpeg::getSection() method, so that it now takes a PelJpegMarker
as argument instead of the section number.
* The byte order can now be specified when a PelTiff object is
converted into bytes.
* Updated documentation, PEL is now fully documented.
## 0.4.0 - 2004-06-09
Notes:
The infrastructure for internationalization has been put in place.
Preliminary translations for Danish, German, French, and Spanish is
included. Support for tags with GPS information were disabled due to
conflicts with a number of normal tags.
Changes:
* Disabled the code that tries to look up the title and description of
the GPS related tags, since those tags have the same hexadecimal
value as a number of other normal tags. This means that there is no
support for tags with GPS information.
* Marked strings for translation throughout the source code.
* Added German, French, and Spanish translations taken from libexif.
The translations were made by Lutz M<>ller, Arnaud Launay, and Fabian
Mandelbaum, respectively.
* Added Danish translation.
* Added new static methods Pel::tra() and Pel::fmt() which are used
for interaction with Gettext. The first function simply translates
its argument, the second will in addition function like sprintf()
when given several arguments.
* Updated documentation, both the doc comments in the code and the
README and INSTALL files.
## 0.3.0 - 2004-05-25
Notes:
Support was added for parsing TIFF images, leading to a mass renaming
of files and classes to cleanup the class hierarchy. The decoding of
Exif data is now tested against known values (over 400 individual
tests), this lead to the discovery of a couple of subtle bugs. The
documentation has been updated and expanded.
Changes:
* Renamed all files and classes so that only Exif specific code is
labeled with Exif. So, for example, PelExifIfd is now PelIfd, since
the IFD structure is not specific to Exif but rather to TIFF images.
The same applies to the former PelExifEntry* classes.
* Fixed offset bug in PelDataWindow::getBytes() which caused the
method to return too much data.
* Added support for the SCENE_TYPE tag.
* Fixed display of integer version numbers. Version x.0 would be
displayed as just version 'x' before.
* Unit tests for Exif decoding. PEL is now tested with an image from
a Sony DSC V1 and one from a Canon IXUS II.
* Changed all occurrences of include_once() to require_once() since
the files are required.
* Updated documentation all over.
## 0.2.0 - 2004-05-16
Notes:
This release brings updated documentation and better support for the
Exif user comment tag and tags containing version information. The
code is now tested using SimpleTest.
Changes:
* All PelExifEntry descendant classes now use setValue() and
getValue() methods consistently.
* Signed and unsigned numbers (bytes, shorts, longs, and rationals)
are now handled correctly.
* The SimpleTest (http://sf.net/projects/simpletest) framework is used
for regression testing.
* Added new PelExifEntryUserComment class to better support the Exif
user comment tag.
* Added new PelExifEntryVersion class to support the Exif tags with
version information, namely the EXIF_VERSION, FLASH_PIX_VERSION, and
INTEROPERABILITY_VERSION tags.
* Updated doc comments all over.
## 0.1.0 - 2004-05-08
Notes:
The initial release of PEL. Most of the functionality is in place:
JPEG files are parsed, Exif entries are found and interpreted, the
entries can be edited and new entries can be added, and finally, the
whole thing can be turned into bytes and saved as a valid JPEG file.
The API is still subject to change, and will remain so until version
1.0 is reached.

View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -0,0 +1,95 @@
# INSTALL
## Requirements
PEL requires PHP version 5.
## Installation
### Composer
The preferred way of installing PEL is through composer. Simply add a
dependency on ´lsolesen/pel´ to your projects composer.json.
{
"require": {
"lsolesen/pel": "0.9.*"
}
}
For a system-wide installation via Composer, you can run:
composer global require "lsolesen/pel=0.9.*"
### Clone via git
You can also use git to install it using:
git clone git://github.com/pel/pel.git
git checkout <tag name>
Finally, you can install PEL by extracting it to a local directory. You can find
the compressed files here: https://github.com/pel/pel/downloads.
Make sure that you extract the files to a path included in your include path:
You can set the include path using.
set_include_path('/path/to/pel' . PATH_SEPARATOR . get_include_path());
## Upgrading
If you have already been using a previous version of PEL, then be sure
to read the CHANGELOG.md file before starting with a new version.
## Using PEL
Your application should include PelJpeg.php or PelTiff.php for working
with JPEG or TIFF files. The files will define the PelJpeg and
PelTiff classes, which can hold a JPEG or TIFF image, respectively.
Please see the API documentation in the doc directory or online at
http://lsolesen.github.com/pel/doc/
for the full story about those classes and all other available classes
in PEL.
Still, an example would be good. The following example will load a
JPEG file given as a command line argument, parse the Exif data
within, change the image description to 'Edited by PEL', and finally
save the file again. All in just six lines of code:
```php5
<?php
require_once('PelJpeg.php');
$jpeg = new PelJpeg($argv[1]);
$ifd0 = $jpeg->getExif()->getTiff()->getIfd();
$entry = $ifd0->getEntry(PelTag::IMAGE_DESCRIPTION);
$entry->setValue('Edited by PEL');
$jpeg->saveFile($argv[1]);
?>
```
See the examples directory for this example (or rather a more
elaborate version in the file edit-description.php) and others as PHP
files. You may have to adjust the path to PHP, found in the very
first line of the files before you can execute them.
## Changing PEL
If you find a bug in PEL then please send a report back so that it can
be fixed in the next version. You can submit your bugs and other
requests here:
http://github.com/pel/pel/issues
If you change the code (to fix bugs or to implement enhancements), it
is highly recommended that you test your changes against known good
data. Please see the test/README.md file for more information about
running the PEL test suite.

View File

@ -0,0 +1,109 @@
# PEL: PHP Exif Library
[![Tests](https://github.com/pel/pel/actions/workflows/tests.yml/badge.svg)](https://github.com/pel/pel/actions/workflows/tests.yml) [![Code Coverage](https://scrutinizer-ci.com/g/pel/pel/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/pel/pel/?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/pel/pel/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/pel/pel/?branch=master) [![Latest Stable Version](https://poser.pugx.org/lsolesen/pel/v/stable)](https://packagist.org/packages/lsolesen/pel) [![Total Downloads](https://poser.pugx.org/lsolesen/pel/downloads)](https://packagist.org/packages/lsolesen/pel) [![License](https://poser.pugx.org/lsolesen/pel/license)](https://packagist.org/packages/lsolesen/pel)
README file for PEL: PHP Exif Library. A library with support for
reading and writing Exif headers in JPEG and TIFF images using PHP.
Copyright (C) 2004, 2005, 2006 Martin Geisler.
Licensed under the GNU GPL, see COPYING for details.
## Description
The PHP Exif Library (PEL) makes it easy to develop programs that will
read and write the Exif metadata headers found in JPEG and TIFF
images. See the file INSTALL for an introduction to how PEL can be
used by your application.
PEL is a library written entirely in PHP 5, which means that it does
not have any dependencies outside the core of PHP, it does not even
use the Exif module available for PHP.
Please note that the API for PEL is not yet frozen, and it will remain
changeable until version 1.0 is reached. Read the NEWS file for
important information about API changes.
Also, please go to the PEL development mailing list (look below) and
share your ideas about how the API should look like.
## Installation
```
composer require lsolesen/pel
```
## Documentation Overview
* README.markdown: gives you a short introduction to PEL (this file).
* INSTALL.md: explain how to install and get going with PEL.
* CHANGELOG.md: contains important information about changes in PEL.
* examples/: small self-contained examples of how to use PEL.
* AUTHORS: list of people who have helped.
* run run-phpdoc.sh to generate API-documention or see it online at https://pel.github.io/pel/doc/
## Features of PEL
* Reads and writes Exif metadata from both JPEG and TIFF images.
* Supports reading and writing all Exif tags.
* Supports internationalization.
* Extensible object-oriented design.
* PhpUnit tested
* Documented with PhpDocumentor (http://phpdoc.org/).
## Helping out
Help will be very much appreciated. You can report issues, run the test
suite, add patches. The best way to help out is applying patches and
helping out with the tests. See instructions in the test/ directory.
All changes to code should be issued through a pull request, and other
maintainers should review the code and merge it.
## Languages
To work with the translations, you need the gettext package installed.
## Getting Support
The first place you should consult for support is the documentation
supplied with PEL, found at https://pel.github.io/pel/doc/.
There you will find a complete API documentation with descriptions of
all classes and files in PEL.
The scripts found in the examples/ directory are also a good source of
information, especially the edit-description.php file which has tons
of comments.
PEL is hosted on Github and uses the tools found there for
support. This means that all questions, bug reports, etc. should be
directed there (and not directly to the developers).
Please try the latest version before reporting bugs -- it might have
been fixed already. The latest code can be found in the git
repository at
http://github.com/pel/pel
It is very helpful if you try out the latest code from the git
repository before submitting a bug report. The code found there is
generally very stable.
## Contributing Test Images
To make PEL as stable as possible, it is tested with images from a
number of different camera models.
New test images are very much appreciated -- please download the
existing test images and read the README file found there for
instructions.
## Credits
Please see the AUTHORS file for a list of people who have contributed
to PEL. See the full list of [code contributors](https://github.com/pel/pel/graphs/contributors).

View File

@ -0,0 +1,36 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2015, Johannes Weberhofer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Register autoloader for pel
*/
spl_autoload_register(function ($class) {
if (substr_compare($class, 'lsolesen\\pel\\', 0, 13) === 0) {
$classname = str_replace('lsolesen\\pel\\', '', $class);
$load = realpath(__DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $classname . '.php');
if ($load !== false) {
include_once realpath($load);
}
}
});

View File

@ -0,0 +1,43 @@
{
"name" : "lsolesen/pel",
"type" : "library",
"description" : "PHP Exif Library. A library for reading and writing Exif headers in JPEG and TIFF images using PHP.",
"keywords" : [
"image",
"exif"
],
"homepage" : "http://pel.github.com/pel/",
"authors" : [{
"name" : "Lars Olesen",
"email" : "lars@intraface.dk",
"homepage" : "http://intraface.dk",
"role" : "Developer"
}, {
"name" : "Martin Geisler",
"email" : "martin@geisler.net",
"homepage" : "http://geisler.net",
"role" : "Developer"
}
],
"license" : "GPL-2.0",
"require" : {
"php" : ">=7.1.0"
},
"require-dev" : {
"ext-gd" : "*",
"ext-exif" : "*",
"squizlabs/php_codesniffer" : ">3.5",
"php-coveralls/php-coveralls" : ">2.4",
"symfony/phpunit-bridge" : "^4 || ^5"
},
"autoload" : {
"psr-4" : {
"lsolesen\\pel\\" : "src/"
}
},
"autoload-dev" : {
"psr-4" : {
"Pel\\Test\\" : "test/"
}
}
}

View File

@ -0,0 +1,197 @@
#!/bin/sh
#
# PEL: PHP Exif Library. A library with support for reading and
# writing all Exif headers in JPEG and TIFF images using PHP.
#
# Copyright (C) 2004, 2005, 2006 Martin Geisler.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program in the file COPYING; if not, write to the
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301 USA
# $Id$
# This small script retrieves the latest version of PEL, packs it up
# into two tarballs (gz and bz2) and a zip file, and then asks for
# permission to upload these files to SourceForge. The generated
# files are placed in the current directory.
# Fix the locale to C, e.g. untranslated.
export LC_ALL=C
# Paths used below
BUILD_BASE="build-base.$$"
PHPDOC_PATH='phpdoc'
# Create the base directory for the build or bail out if it already
# exists
if [[ -d $BUILD_BASE ]]; then
echo "The build directory $BUILD_BASE already exists!"
exit
else
echo "Building the release in $BUILD_BASE"
mkdir $BUILD_BASE
fi
cd $BUILD_BASE
echo -n "Exporting trunk from SourceForge... "
svn export https://pel.svn.sourceforge.net/svnroot/pel/trunk pel || exit
echo "done."
# Grab version number from ChangeLog...
PREFIX='PEL Version'
MIDDLE='[0-9]+\.[0-9]+(\.[0-9]+(-[0-9a-z]+)?)?'
DATE=$(date -u '+%B %-d.. %Y')
REGEXP="$PREFIX $MIDDLE $DATE"
OFFSET=$(grep -n -E -m 1 "$REGEXP" pel/NEWS | cut -d ':' -f 1)
if [[ -z $OFFSET ]]; then
echo "Found no version from today in NEWS, creating SVN version."
VERSION='svn' #$(date -u '+svn-%Y-%m-%d')
else
echo "Offset: $OFFSET"
VERSION=$(head -n $OFFSET pel/NEWS | tail -n 1 | cut -d ' ' -f 3)
echo "Found match for today in NEWS: $VERSION."
LINE=$(head -n $OFFSET pel/NEWS | tail -n 1)
STARS=$(head -n $((OFFSET+1)) pel/NEWS | tail -n 1)
if [[ ${#LINE} != ${#STARS} ]]; then
echo "Aborting because of bad underlining:"
echo
echo "$LINE"
echo "$STARS"
exit
fi
fi
mv pel pel-$VERSION
if [[ $VERSION == "svn" ]]; then
echo "Skipping tagging since this is a SVN snapshot."
else
read -p "Create SVN tag? [y/N] " -n 1
echo
if [[ $REPLY == "y" ]]; then
echo -n "Creating SVN tag 'pel-$VERSION'... "
svn copy \
https://pel.svn.sourceforge.net/svnroot/pel/trunk \
https://pel.svn.sourceforge.net/svnroot/pel/tags/pel-$VERSION \
-m "Tagging PEL version $VERSION."
echo "done."
else
echo "Skipping tagging by user request."
fi
fi
cd pel-$VERSION
# Generate the ChangeLog, prefixed with a standard header
echo -n "Generating SVN ChangeLog... "
echo "ChangeLog file for PEL: PHP Exif Library. A library with support for
reading and writing Exif headers in JPEG and TIFF images using PHP.
Copyright (C) 2004, 2005, 2006 Martin Geisler.
Licensed under the GNU GPL, see COPYING for details.
" > ChangeLog
svn2cl --include-rev --group-by-day --separate-daylogs \
--reparagraph --authors=authors.xml --stdout \
https://pel.svn.sourceforge.net/svnroot/pel/trunk/ >> ChangeLog || exit
echo "done."
#echo -n "Marking releases in ChangeLog... "
#sed -re '/./{H;$!d;};x;/tags/s|tags/pel-([0-9]+\.[0-9]+).*|PEL Version \1|'
#echo "done."
# Generate the binary MO files
./update-locales.sh
# Generate the API documentation
./run-phpdoc.sh $VERSION $PHPDOC_PATH
# Cleanup files that aren't needed in the released package
rm make-release.sh authors.xml
rm -r tutorials
# Add anchors and headers to the HTML ChangeLog so that each release
# notices can link back to it
#sed -i -re 's|^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2} tag release-([0-9])_([0-9])$|</pre>\n\n<div align="center"><h2 id="v\1.\2">PEL Version \1.\2</h2></div>\n\n<pre>\n|g' doc/ric_ChangeLog.html
# Leave the pel-$VERSION directory
cd ..
mv pel-$VERSION/test/image-tests image-tests
echo -n "Creating pel-image-tests-$VERSION.tar.gz... "
tar -cz image-tests -f pel-image-tests-$VERSION.tar.gz
echo "done."
echo -n "Creating pel-image-tests-$VERSION.tar.bz2... "
tar -cj image-tests -f pel-image-tests-$VERSION.tar.bz2
echo "done."
echo -n "Creating pel-images-$VERSION.zip... "
zip -qr pel-image-tests-$VERSION.zip image-tests
echo "done."
echo -n "Creating pel-$VERSION.tar.gz... "
tar -cz pel-$VERSION -f pel-$VERSION.tar.gz
echo "done."
echo -n "Creating pel-$VERSION.tar.bz2... "
tar -cj pel-$VERSION -f pel-$VERSION.tar.bz2
echo "done."
echo -n "Creating pel-$VERSION.zip... "
zip -qr pel-$VERSION.zip pel-$VERSION
echo "done."
# Upload the compressed files and API documentation, if allowed
if [[ $VERSION != "svn" && ( $REPLY == "y" || $REPLY == "Y" ) ]]; then
echo -n "Uploading files to SourceForge for release... "
ncftpput upload.sourceforge.net /incoming \
pel-$VERSION.tar.gz \
pel-$VERSION.tar.bz2 \
pel-$VERSION.zip \
pel-image-tests-$VERSION.tar.gz \
pel-image-tests-$VERSION.tar.bz2 \
pel-image-tests-$VERSION.zip
echo "done."
echo -n "Uploading API documentation to SourceForge... "
scp -C -q -r pel-$VERSION/doc \
shell.sourceforge.net:/home/groups/p/pe/pel/htdocs
echo "done."
else
echo "Skipping upload."
fi
echo "All done. The $BUILD_BASE directory can be removed at any time."
# The End --- PEL has now been packaged (and maybe even released)!

View File

@ -0,0 +1,360 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class with miscellaneous static methods.
*
* This class will contain various methods that govern the overall
* behavior of PEL.
*
* Debugging output from PEL can be turned on and off by assigning
* true or false to {@link Pel::$debug}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
*/
namespace lsolesen\pel;
class Pel
{
/**
* Flag that controls if dgettext can be used.
* Is set to true or fals at the first access
*
* @var boolean|NULL
*/
private static $hasdgetext = null;
/**
* Flag for controlling debug information.
*
* The methods producing debug information ({@link debug()} and
* {@link warning()}) will only output something if this variable is
* set to true.
*
* @var boolean
*/
private static $debug = false;
/**
* Flag for strictness of parsing.
*
* If this variable is set to true, then most errors while loading
* images will result in exceptions being thrown. Otherwise a
* warning will be emitted (using {@link Pel::warning}) and the
* exceptions will be appended to {@link Pel::$exceptions}.
*
* Some errors will still be fatal and result in thrown exceptions,
* but an effort will be made to skip over as much garbage as
* possible.
*
* @var boolean
*/
private static $strict = false;
/**
* Stored exceptions.
*
* When {@link Pel::$strict} is set to false exceptions will be
* accumulated here instead of being thrown.
*/
private static $exceptions = [];
/**
* Quality setting for encoding JPEG images.
*
* This controls the quality used then PHP image resources are
* encoded into JPEG images. This happens when you create a
* {@link PelJpeg} object based on an image resource.
*
* The default is 75 for average quality images, but you can change
* this to an integer between 0 and 100.
*
* @var int
*/
private static $quality = 75;
/**
* Set the JPEG encoding quality.
*
* @param int $quality
* an integer between 0 and 100 with 75 being
* average quality and 95 very good quality.
*/
public static function setJPEGQuality($quality)
{
self::$quality = $quality;
}
/**
* Get current setting for JPEG encoding quality.
*
* @return int the quality.
*/
public static function getJPEGQuality()
{
return self::$quality;
}
/**
* Return list of stored exceptions.
*
* When PEL is parsing in non-strict mode, it will store most
* exceptions instead of throwing them. Use this method to get hold
* of them when a call returns.
*
* Code for using this could look like this:
*
* <code>
* Pel::setStrictParsing(true);
* Pel::clearExceptions();
*
* $jpeg = new PelJpeg($file);
*
* // Check for exceptions.
* foreach (Pel::getExceptions() as $e) {
* printf("Exception: %s\n", $e->getMessage());
* if ($e instanceof PelEntryException) {
* // Warn about entries that couldn't be loaded.
* printf("Warning: Problem with %s.\n",
* PelTag::getName($e->getType(), $e->getTag()));
* }
* }
* </code>
*
* This gives applications total control over the amount of error
* messages shown and (hopefully) provides the necessary information
* for proper error recovery.
*
* @return array the exceptions.
*/
public static function getExceptions()
{
return self::$exceptions;
}
/**
* Clear list of stored exceptions.
*
* Use this function before a call to some method if you intend to
* check for exceptions afterwards.
*/
public static function clearExceptions()
{
self::$exceptions = [];
}
/**
* Conditionally throw an exception.
*
* This method will throw the passed exception when strict parsing
* in effect (see {@link setStrictParsing()}). Otherwise the
* exception is stored (it can be accessed with {@link
* getExceptions()}) and a warning is issued (with {@link
* Pel::warning}).
*
* @param PelException $e
* the exceptions.
*/
public static function maybeThrow(PelException $e)
{
if (self::$strict) {
throw $e;
} else {
self::$exceptions[] = $e;
self::warning('%s (%s:%s)', $e->getMessage(), basename($e->getFile()), $e->getLine());
}
}
/**
* Enable/disable strict parsing.
*
* If strict parsing is enabled, then most errors while loading
* images will result in exceptions being thrown. Otherwise a
* warning will be emitted (using {@link Pel::warning}) and the
* exceptions will be stored for later use via {@link
* getExceptions()}.
*
* Some errors will still be fatal and result in thrown exceptions,
* but an effort will be made to skip over as much garbage as
* possible.
*
* @param boolean $flag
* use true to enable strict parsing, false to
* diable.
*/
public static function setStrictParsing($flag)
{
self::$strict = $flag;
}
/**
* Get current setting for strict parsing.
*
* @return boolean true if strict parsing is in effect, false
* otherwise.
*/
public static function getStrictParsing()
{
return self::$strict;
}
/**
* Enable/disable debugging output.
*
* @param boolean $flag
* use true to enable debug output, false to
* diable.
*/
public static function setDebug($flag)
{
self::$debug = $flag;
}
/**
* Get current setting for debug output.
*
* @return boolean true if debug is enabled, false otherwise.
*/
public static function getDebug()
{
return self::$debug;
}
/**
* Conditionally output debug information.
*
* This method works just like printf() except that it always
* terminates the output with a newline, and that it only outputs
* something if the {@link Pel::$debug} is true.
*
* @param string $format
* the format string.
* @param mixed ...$args
* any number of arguments can be given. The
* arguments will be available for the format string as usual with
* sprintf().
*/
public static function debug($format)
{
if (self::$debug) {
$args = func_get_args();
$str = array_shift($args);
vprintf($str . "\n", $args);
}
}
/**
* Conditionally output a warning.
*
* This method works just like printf() except that it prepends the
* output with the string 'Warning: ', terminates the output with a
* newline, and that it only outputs something if the PEL_DEBUG
* defined to some true value.
*
* @param string $format
* the format string.
* @param mixed ...$args
* any number of arguments can be given. The
* arguments will be available for the format string as usual with
* sprintf().
*/
public static function warning($format)
{
if (self::$debug) {
$args = func_get_args();
$str = array_shift($args);
vprintf('Warning: ' . $str . "\n", $args);
}
}
/**
* Translate a string.
*
* This static function will use Gettext to translate a string. By
* always using this function for static string one is assured that
* the translation will be taken from the correct text domain.
* Dynamic strings should be passed to {@link fmt} instead.
*
* @param string $str
* the string that should be translated.
* @return string the translated string, or the original string if
* no translation could be found.
*/
public static function tra($str)
{
return self::dgettextWrapper('pel', $str);
}
/**
* Translate and format a string.
*
* This static function will first use Gettext to translate a format
* string, which will then have access to any extra arguments. By
* always using this function for dynamic string one is assured that
* the translation will be taken from the correct text domain. If
* the string is static, use {@link tra} instead as it will be
* faster.
*
* @param string $format
* the format string. This will be translated
* before being used as a format string.
* @param mixed ...$args
* any number of arguments can be given. The
* arguments will be available for the format string as usual with
* sprintf().
* @return string the translated string, or the original string if
* no translation could be found.
*/
public static function fmt($format)
{
$args = func_get_args();
$str = array_shift($args);
return vsprintf(self::dgettextWrapper('pel', $str), $args);
}
/**
* Warapper for dgettext.
* The untranslated stub will be return in the case that dgettext is not available.
*
* @param string $domain
* @param string $str
* @return string
*/
private static function dgettextWrapper($domain, $str)
{
if (self::$hasdgetext === null) {
self::$hasdgetext = function_exists('dgettext');
if (self::$hasdgetext === true) {
bindtextdomain('pel', __DIR__ . '/locale');
}
}
if (self::$hasdgetext) {
return dgettext($domain, $str);
} else {
return $str;
}
}
}

View File

@ -0,0 +1,341 @@
<?php
/*
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
* Copyright (C) 2017 Johannes Weberhofer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Namespace for functions operating on Exif formats.
*
* This class defines the constants that are to be used whenever one
* has to refer to the format of an Exif tag. They will be
* collectively denoted by the pseudo-type PelFormat throughout the
* documentation.
*
* All the methods defined here are static, and they all operate on a
* single argument which should be one of the class constants.
*
* @author Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
* @author Thanks to Benedikt Rosenkranz <beluro@web.de>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package
*
*/
namespace lsolesen\pel;
class PelCanonMakerNotes extends PelMakerNotes
{
private $undefinedMakerNotesTags = [
0x0000,
0x0003,
0x000a,
0x000e,
0x0011,
0x0014,
0x0016,
0x0017,
0x0018,
0x0019,
0x001b,
0x001c,
0x001d,
0x001f,
0x0020,
0x0021,
0x0022,
0x0023,
0x0024,
0x0025,
0x0031,
0x0035,
0x0098,
0x009a,
0x00b5,
0x00c0,
0x00c1,
0x4008,
0x4009,
0x4010,
0x4011,
0x4012,
0x4013,
0x4015,
0x4016,
0x4018,
0x4019,
0x4020,
0x4025,
0x4027
];
private $undefinedCameraSettingsTags = [
0x0006,
0x0008,
0x0015,
0x001e,
0x001f,
0x0026,
0x002b,
0x002c,
0x002d,
0x002f,
0x0030,
0x0031
];
private $undefinedShotInfoTags = [
0x0001,
0x0006,
0x000a,
0x000b,
0x000c,
0x000d,
0x0011,
0x0012,
0x0014,
0x0018,
0x0019,
0x001d,
0x001e,
0x001f,
0x0020,
0x0021,
0x0022
];
private $undefinedPanoramaTags = [
0x0001,
0x0003,
0x0004
];
private $undefinedPicInfoTags = [
0x0001,
0x0006,
0x0007,
0x0008,
0x0009,
0x000a,
0x000b,
0x000c,
0x000d,
0x000e,
0x000f,
0x0010,
0x0011,
0x0012,
0x0013,
0x0014,
0x0015,
0x0017,
0x0018,
0x0019,
0x001b,
0x001c
];
private $undefinedFileInfoTags = [
0x0002,
0x000a,
0x000b,
0x0011,
0x0012,
0x0016,
0x0017,
0x0018,
0x001a,
0x001b,
0x001c,
0x001d,
0x001e,
0x001f,
0x0020
];
public function __construct($parent, $data, $size, $offset)
{
parent::__construct($parent, $data, $size, $offset);
$this->type = PelIfd::CANON_MAKER_NOTES;
}
public function load()
{
$this->components = $this->data->getShort($this->offset);
$this->offset += 2;
Pel::debug('Loading %d components in maker notes.', $this->components);
$mkNotesIfd = new PelIfd(PelIfd::CANON_MAKER_NOTES);
for ($i = 0; $i < $this->components; $i ++) {
$tag = $this->data->getShort($this->offset + 12 * $i);
$components = $this->data->getLong($this->offset + 12 * $i + 4);
$data = $this->data->getLong($this->offset + 12 * $i + 8);
// check if tag is defined
if (in_array($tag, $this->undefinedMakerNotesTags)) {
continue;
}
switch ($tag) {
case PelTag::CANON_CAMERA_SETTINGS:
$this->parseCameraSettings($mkNotesIfd, $this->data, $data, $components);
break;
case PelTag::CANON_SHOT_INFO:
$this->parseShotInfo($mkNotesIfd, $this->data, $data, $components);
break;
case PelTag::CANON_PANORAMA:
$this->parsePanorama($mkNotesIfd, $this->data, $data, $components);
break;
case PelTag::CANON_PICTURE_INFO:
// TODO: Does not work at the moment
// $this->parsePictureInfo($mkNotesIfd, $this->data, $data, $components);
break;
case PelTag::CANON_FILE_INFO:
$this->parseFileInfo($mkNotesIfd, $this->data, $data, $components);
break;
case PelTag::CANON_CUSTOM_FUNCTIONS:
// TODO
default:
$mkNotesIfd->loadSingleValue($this->data, $this->offset, $i, $tag);
break;
}
}
$this->parent->addSubIfd($mkNotesIfd);
}
private function parseCameraSettings($parent, $data, $offset, $components)
{
$type = PelIfd::CANON_CAMERA_SETTINGS;
Pel::debug('Found Canon Camera Settings sub IFD at offset %d', $offset);
$size = $data->getShort($offset);
$offset += 2;
$elemSize = PelFormat::getSize(PelFormat::SSHORT);
if ((! $components) || ($size / $components !== $elemSize)) {
throw new PelMakerNotesMalformedException('Size of Canon Camera Settings does not match the number of entries.');
}
$camIfd = new PelIfd($type);
for ($i = 0; $i < $components; $i ++) {
// check if tag is defined
if (in_array($i + 1, $this->undefinedCameraSettingsTags)) {
continue;
}
$camIfd->loadSingleMakerNotesValue($type, $data, $offset, $size, $i, PelFormat::SSHORT);
}
$parent->addSubIfd($camIfd);
}
private function parseShotInfo($parent, $data, $offset, $components)
{
$type = PelIfd::CANON_SHOT_INFO;
Pel::debug('Found Canon Shot Info sub IFD at offset %d', $offset);
$size = $data->getShort($offset);
$offset += 2;
$elemSize = PelFormat::getSize(PelFormat::SHORT);
if ($size / $components !== $elemSize) {
throw new PelMakerNotesMalformedException('Size of Canon Shot Info does not match the number of entries.');
}
$shotIfd = new PelIfd($type);
for ($i = 0; $i < $components; $i ++) {
// check if tag is defined
if (in_array($i + 1, $this->undefinedShotInfoTags)) {
continue;
}
$shotIfd->loadSingleMakerNotesValue($type, $data, $offset, $size, $i, PelFormat::SHORT);
}
$parent->addSubIfd($shotIfd);
}
private function parsePanorama($parent, $data, $offset, $components)
{
$type = PelIfd::CANON_PANORAMA;
Pel::debug('Found Canon Panorama sub IFD at offset %d', $offset);
$size = $data->getShort($offset);
$offset += 2;
$elemSize = PelFormat::getSize(PelFormat::SHORT);
if ($size / $components !== $elemSize) {
throw new PelMakerNotesMalformedException('Size of Canon Panorama does not match the number of entries.');
}
$panoramaIfd = new PelIfd($type);
for ($i = 0; $i < $components; $i ++) {
// check if tag is defined
if (in_array($i + 1, $this->undefinedPanoramaTags)) {
continue;
}
$panoramaIfd->loadSingleMakerNotesValue($type, $data, $offset, $size, $i, PelFormat::SHORT);
}
$parent->addSubIfd($panoramaIfd);
}
/**
* This method does not work properly
*/
private function parsePictureInfo($parent, $data, $offset, $components)
{
$type = PelIfd::CANON_PICTURE_INFO;
Pel::debug('Found Canon Picture Info sub IFD at offset %d', $offset);
$size = $data->getShort($offset);
$offset += 2;
$elemSize = PelFormat::getSize(PelFormat::SHORT);
if ($size / $components !== $elemSize) {
throw new PelMakerNotesMalformedException('Size of Canon Picture Info does not match the number of entries. ' . $size . '/' . $components . ' = ' . $elemSize);
}
$picIfd = new PelIfd($type);
for ($i = 0; $i < $components; $i ++) {
// check if tag is defined
printf("Current Tag: %d\n", ($i + 1));
if (in_array($i + 1, $this->undefinedPicInfoTags)) {
continue;
}
$picIfd->loadSingleMakerNotesValue($type, $data, $offset, $size, $i, PelFormat::SHORT);
}
$parent->addSubIfd($picIfd);
}
private function parseFileInfo($parent, $data, $offset, $components)
{
$type = PelIfd::CANON_FILE_INFO;
Pel::debug('Found Canon File Info sub IFD at offset %d', $offset);
$size = $data->getShort($offset);
$offset += 2;
$elemSize = PelFormat::getSize(PelFormat::SSHORT);
if ($size === $elemSize * ($components - 1) + PelFormat::getSize(PelFormat::LONG)) {
throw new PelMakerNotesMalformedException('Size of Canon File Info does not match the number of entries.');
}
$fileIfd = new PelIfd($type);
for ($i = 0; $i < $components; $i ++) {
// check if tag is defined
if (in_array($i + 1, $this->undefinedFileInfoTags)) {
continue;
}
$format = PelFormat::SSHORT;
if ($i + 1 == PelTag::CANON_FI_FILE_NUMBER) {
$format = PelFormat::LONG;
}
$fileIfd->loadSingleMakerNotesValue($type, $data, $offset, $size, $i, $format);
}
$parent->addSubIfd($fileIfd);
}
}

View File

@ -0,0 +1,394 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
namespace lsolesen\pel;
/**
* Routines for converting back and forth between bytes and integers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Conversion functions to and from bytes and integers.
*
* The functions found in this class are used to convert bytes into
* integers of several sizes ({@link bytesToShort}, {@link
* bytesToLong}, and {@link bytesToRational}) and convert integers of
* several sizes into bytes ({@link shortToBytes} and {@link
* longToBytes}).
*
* All the methods are static and they all rely on an argument that
* specifies the byte order to be used, this must be one of the class
* constants {@link LITTLE_ENDIAN} or {@link BIG_ENDIAN}. These
* constants will be referred to as the pseudo type PelByteOrder
* throughout the documentation.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelConvert
{
/**
* Little-endian (Intel) byte order.
*
* Data stored in little-endian byte order store the least
* significant byte first, so the number 0x12345678 becomes 0x78
* 0x56 0x34 0x12 when stored with little-endian byte order.
*/
const LITTLE_ENDIAN = true;
/**
* Big-endian (Motorola) byte order.
*
* Data stored in big-endian byte order store the most significant
* byte first, so the number 0x12345678 becomes 0x12 0x34 0x56 0x78
* when stored with big-endian byte order.
*/
const BIG_ENDIAN = false;
/**
* Convert an unsigned short into two bytes.
*
* @param integer $value
* the unsigned short that will be converted. The lower
* two bytes will be extracted regardless of the actual size passed.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return string the bytes representing the unsigned short.
*/
public static function shortToBytes($value, $endian)
{
if ($endian == self::LITTLE_ENDIAN) {
return chr($value) . chr($value >> 8);
} else {
return chr($value >> 8) . chr($value);
}
}
/**
* Convert a signed short into two bytes.
*
* @param integer $value
* the signed short that will be converted. The lower
* two bytes will be extracted regardless of the actual size passed.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return string the bytes representing the signed short.
*/
public static function sShortToBytes($value, $endian)
{
/*
* We can just use shortToBytes, since signed shorts fits well
* within the 32 bit signed integers used in PHP.
*/
return self::shortToBytes($value, $endian);
}
/**
* Convert an unsigned long into four bytes.
*
* Because PHP limits the size of integers to 32 bit signed, one
* cannot really have an unsigned integer in PHP. But integers
* larger than 2^31-1 will be promoted to 64 bit signed floating
* point numbers, and so such large numbers can be handled too.
*
* @param integer $value
* the unsigned long that will be converted. The
* argument will be treated as an unsigned 32 bit integer and the
* lower four bytes will be extracted. Treating the argument as an
* unsigned integer means that the absolute value will be used. Use
* {@link sLongToBytes} to convert signed integers.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return string the bytes representing the unsigned long.
*/
public static function longToBytes($value, $endian)
{
/*
* We cannot convert the number to bytes in the normal way (using
* shifts and modulo calculations) because the PHP operator >> and
* function chr() clip their arguments to 2^31-1, which is the
* largest signed integer known to PHP. But luckily base_convert
* handles such big numbers.
*/
$hex = str_pad(base_convert($value, 10, 16), 8, '0', STR_PAD_LEFT);
if ($endian == self::LITTLE_ENDIAN) {
return chr((int) hexdec($hex[6] . $hex[7])) . chr((int) hexdec($hex[4] . $hex[5])) . chr((int) hexdec($hex[2] . $hex[3])) . chr((int) hexdec($hex[0] . $hex[1]));
} else {
return chr((int) hexdec($hex[0] . $hex[1])) . chr((int) hexdec($hex[2] . $hex[3])) . chr((int) hexdec($hex[4] . $hex[5])) . chr((int) hexdec($hex[6] . $hex[7]));
}
}
/**
* Convert a signed long into four bytes.
*
* @param integer $value
* the signed long that will be converted. The argument
* will be treated as a signed 32 bit integer, from which the lower
* four bytes will be extracted.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return string the bytes representing the signed long.
*/
public static function sLongToBytes($value, $endian)
{
/*
* We can convert the number into bytes in the normal way using
* shifts and modulo calculations here (in contrast with
* longToBytes) because PHP automatically handles 32 bit signed
* integers for us.
*/
if ($endian == self::LITTLE_ENDIAN) {
return (chr($value) . chr($value >> 8) . chr($value >> 16) . chr($value >> 24));
} else {
return (chr($value >> 24) . chr($value >> 16) . chr($value >> 8) . chr($value));
}
}
/**
* Extract an unsigned byte from a string of bytes.
*
* @param string $bytes
* the bytes.
* @param integer $offset
* The byte found at the offset will be
* returned as an integer. The must be at least one byte available
* at offset.
* @return integer $offset the unsigned byte found at offset, e.g., an integer
* in the range 0 to 255.
*/
public static function bytesToByte($bytes, $offset)
{
return ord($bytes[$offset]);
}
/**
* Extract a signed byte from bytes.
*
* @param string $bytes
* the bytes.
* @param integer $offset
* the offset. The byte found at the offset will be
* returned as an integer. The must be at least one byte available
* at offset.
* @return integer the signed byte found at offset, e.g., an integer in
* the range -128 to 127.
*/
public static function bytesToSByte($bytes, $offset)
{
$n = self::bytesToByte($bytes, $offset);
if ($n > 127) {
return $n - 256;
} else {
return $n;
}
}
/**
* Extract an unsigned short from bytes.
*
* @param string $bytes
* the bytes.
* @param integer $offset
* the offset. The short found at the offset will be
* returned as an integer. There must be at least two bytes
* available beginning at the offset given.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return integer the unsigned short found at offset, e.g., an integer
* in the range 0 to 65535.
*/
public static function bytesToShort($bytes, $offset, $endian)
{
if ($endian == self::LITTLE_ENDIAN) {
return (ord($bytes[$offset + 1]) * 256 + ord($bytes[$offset]));
} else {
return (ord($bytes[$offset]) * 256 + ord($bytes[$offset + 1]));
}
}
/**
* Extract a signed short from bytes.
*
* @param string $bytes
*
* @param integer $offset
* The short found at offset will be returned
* as an integer. There must be at least two bytes available
* beginning at the offset given.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return integer the signed byte found at offset, e.g., an integer in
* the range -32768 to 32767.
*/
public static function bytesToSShort($bytes, $offset, $endian)
{
$n = self::bytesToShort($bytes, $offset, $endian);
if ($n > 32767) {
return $n - 65536;
} else {
return $n;
}
}
/**
* Extract an unsigned long from bytes.
*
* @param string $bytes
*
* @param integer $offset
* The long found at offset will be returned
* as an integer. There must be at least four bytes available
* beginning at the offset given.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return integer the unsigned long found at offset, e.g., an integer
* in the range 0 to 4294967295.
*/
public static function bytesToLong($bytes, $offset, $endian)
{
if ($endian == self::LITTLE_ENDIAN) {
return (ord($bytes[$offset + 3]) * 16777216 + ord($bytes[$offset + 2]) * 65536 + ord($bytes[$offset + 1]) * 256 + ord($bytes[$offset]));
} else {
return (ord($bytes[$offset]) * 16777216 + ord($bytes[$offset + 1]) * 65536 + ord($bytes[$offset + 2]) * 256 + ord($bytes[$offset + 3]));
}
}
/**
* Extract a signed long from bytes.
*
* @param string $bytes
*
* @param integer $offset
* The long found at offset will be returned
* as an integer. There must be at least four bytes available
* beginning at the offset given.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}. *
* @return integer the signed long found at offset, e.g., an integer in
* the range -2147483648 to 2147483647.
*/
public static function bytesToSLong($bytes, $offset, $endian)
{
$n = self::bytesToLong($bytes, $offset, $endian);
if ($n > 2147483647) {
return $n - 4294967296;
} else {
return $n;
}
}
/**
* Extract an unsigned rational from bytes.
*
* @param string $bytes
*
* @param integer $offset
* The rational found at offset will be
* returned as an array. There must be at least eight bytes
* available beginning at the offset given.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}. *
* @return array the unsigned rational found at offset, e.g., an
* array with two integers in the range 0 to 4294967295.
*/
public static function bytesToRational($bytes, $offset, $endian)
{
return [
self::bytesToLong($bytes, $offset, $endian),
self::bytesToLong($bytes, $offset + 4, $endian)
];
}
/**
* Extract a signed rational from bytes.
*
* @param string $bytes
*
* @param integer $offset
* The rational found at offset will be
* returned as an array. There must be at least eight bytes
* available beginning at the offset given.
* @param boolean $endian
* one of {@link LITTLE_ENDIAN} and {@link
* BIG_ENDIAN}.
* @return array the signed rational found at offset, e.g., an array
* with two integers in the range -2147483648 to 2147483647.
*/
public static function bytesToSRational($bytes, $offset, $endian)
{
return [
self::bytesToSLong($bytes, $offset, $endian),
self::bytesToSLong($bytes, $offset + 4, $endian)
];
}
/**
* Format bytes for dumping.
*
* This method is for debug output, it will format a string as a
* hexadecimal dump suitable for display on a terminal. The output
* is printed directly to standard out.
*
* @param string $bytes
* the bytes that will be dumped.
* @param integer $max
* the maximum number of bytes to dump. If this is left
* out (or left to the default of 0), then the entire string will be
* dumped.
* @return void
*/
public static function bytesToDump($bytes, $max = 0)
{
$s = strlen($bytes);
if ($max > 0) {
$s = min($max, $s);
}
$line = 24;
for ($i = 0; $i < $s; $i ++) {
printf('%02X ', ord($bytes[$i]));
if (($i + 1) % $line == 0) {
print("\n");
}
}
print("\n");
}
}

View File

@ -0,0 +1,542 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
namespace lsolesen\pel;
/**
* The window.
*
* @package PEL
*/
class PelDataWindow
{
/**
* The data held by this window.
*
* The string can contain any kind of data, including binary data.
*
* @var string
*/
private $data = '';
/**
* The byte order currently in use.
*
* This will be the byte order used when data is read using the for
* example the {@link getShort} function. It must be one of {@link
* PelConvert::LITTLE_ENDIAN} and {@link PelConvert::BIG_ENDIAN}.
*
* @var boolean
* @see PelDataWindow::setByteOrder, getByteOrder
*/
private $order;
/**
* The start of the current window.
*
* All offsets used for access into the data will count from this
* offset, effectively limiting access to a window starting at this
* byte.
*
* @var int
* @see PelDataWindow::setWindowStart
*/
private $start = 0;
/**
* The size of the current window.
*
* All offsets used for access into the data will be limited by this
* variable. A valid offset must be strictly less than this
* variable.
*
* @var int
* @see PelDataWindow::setWindowSize
*/
private $size = 0;
/**
* Construct a new data window with the data supplied.
*
* @param string|resource|\GDImage $data
* the data that this window will contain. This can
* either be given as a string (interpreted litteraly as a sequence
* of bytes) or a PHP image resource handle. The data will be copied
* into the new data window.
* @param boolean $endianess
* the initial byte order of the window. This must
* be either {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}. This will be used when integers are
* read from the data, and it can be changed later with {@link
* setByteOrder()}.
* @throws PelInvalidArgumentException if $data was of invalid type
*/
public function __construct($data = '', $endianess = PelConvert::LITTLE_ENDIAN)
{
if (is_string($data)) {
$this->data = $data;
} elseif ((is_resource($data) && get_resource_type($data) === 'gd') || (PHP_VERSION_ID >= 80000 && is_object($data) && $data instanceof \GDImage)) {
/*
* The ImageJpeg() function insists on printing the bytes
* instead of returning them in a more civil way as a string, so
* we have to buffer the output...
*/
ob_start();
ImageJpeg($data, null, Pel::getJPEGQuality());
$this->data = ob_get_clean();
} else {
throw new PelInvalidArgumentException('Bad type for $data: %s', gettype($data));
}
$this->order = $endianess;
$this->size = strlen($this->data);
}
/**
* Get the size of the data window.
*
* @return integer the number of bytes covered by the window. The
* allowed offsets go from 0 up to this number minus one.
* @see getBytes()
*/
public function getSize()
{
return $this->size;
}
/**
* Change the byte order of the data.
*
* @param boolean $order
* the new byte order. This must be either
* {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}.
*/
public function setByteOrder($order)
{
$this->order = $order;
}
/**
* Get the currently used byte order.
*
* @return boolean this will be either {@link
* PelConvert::LITTLE_ENDIAN} or {@link PelConvert::BIG_ENDIAN}.
*/
public function getByteOrder()
{
return $this->order;
}
/**
* Move the start of the window forward.
*
* @param integer $start
* the new start of the window. All new offsets will be
* calculated from this new start offset, and the size of the window
* will shrink to keep the end of the window in place.
* @throws PelDataWindowWindowException
*/
public function setWindowStart($start)
{
if ($start < 0 || $start > $this->size) {
throw new PelDataWindowWindowException('Window [%d, %d] does ' . 'not fit in window [0, %d]', $start, $this->size, $this->size);
}
$this->start += $start;
$this->size -= $start;
}
/**
* Adjust the size of the window.
* The size can only be made smaller.
*
* @param integer $size
* the desired size of the window. If the argument is
* negative, the window will be shrunk by the argument.
* @throws PelDataWindowWindowException
*/
public function setWindowSize($size)
{
if ($size < 0) {
$size += $this->size;
}
if ($size < 0 || $size > $this->size) {
throw new PelDataWindowWindowException('Window [0, %d] ' . 'does not fit in window [0, %d]', $size, $this->size);
}
$this->size = $size;
}
/**
* Make a new data window with the same data as the this window.
*
* @param integer|null $start
* if an integer is supplied, then it will be the start
* of the window in the clone. If left unspecified, then the clone
* will inherit the start from this object.
* @param integer|null $size
* if an integer is supplied, then it will be the size
* of the window in the clone. If left unspecified, then the clone
* will inherit the size from this object.
* @return PelDataWindow a new window that operates on the same data
* as this window, but (optionally) with a smaller window size.
* @throws PelDataWindowWindowException
*/
public function getClone($start = null, $size = null)
{
$c = clone $this;
if (is_int($start)) {
$c->setWindowStart($start);
}
if (is_int($size)) {
$c->setWindowSize($size);
}
return $c;
}
/**
* Validate an offset against the current window.
*
* @param integer $offset
* the offset to be validated. If the offset is negative
* or if it is greater than or equal to the current window size,
* then a {@link PelDataWindowOffsetException} is thrown.
* @return void if the offset is valid nothing is returned, if it is
* invalid a new {@link PelDataWindowOffsetException} is thrown.
* @throws PelDataWindowOffsetException
*/
private function validateOffset($offset)
{
if ($offset < 0 || $offset >= $this->size) {
throw new PelDataWindowOffsetException('Offset %d not within [%d, %d]', $offset, 0, $this->size - 1);
}
}
/**
* Return some or all bytes visible in the window.
*
* This method works just like the standard {@link substr()}
* function in PHP with the exception that it works within the
* window of accessible bytes and does strict range checking.
*
* @param integer|null $start
* the offset to the first byte returned. If a negative
* number is given, then the counting will be from the end of the
* window. Invalid offsets will result in a {@link
* PelDataWindowOffsetException} being thrown.
* @param integer|null $size
* the size of the sub-window. If a negative number is
* given, then that many bytes will be omitted from the result.
* @return string a subset of the bytes in the window. This will
* always return no more than {@link getSize()} bytes.
* @throws PelDataWindowOffsetException
*/
public function getBytes($start = null, $size = null)
{
if (is_int($start)) {
if ($start < 0) {
$start += $this->size;
}
$this->validateOffset($start);
} else {
$start = 0;
}
if (is_int($size)) {
if ($size <= 0) {
$size += $this->size - $start;
}
$this->validateOffset($start + $size);
} else {
$size = $this->size - $start;
}
return substr($this->data, $this->start + $start, $size);
}
/**
* Return an unsigned byte from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first byte in the current allowed window. The last
* valid offset is equal to {@link getSize()}-1. Invalid offsets
* will result in a {@link PelDataWindowOffsetException} being
* thrown.
* @return integer the unsigned byte found at offset.
* @throws PelDataWindowOffsetException
*/
public function getByte($offset = 0)
{
/*
* Validate the offset --- this throws an exception if offset is
* out of range.
*/
$this->validateOffset($offset);
/* Translate the offset into an offset into the data. */
$offset += $this->start;
/* Return an unsigned byte. */
return PelConvert::bytesToByte($this->data, $offset);
}
/**
* Return a signed byte from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first byte in the current allowed window. The last
* valid offset is equal to {@link getSize()}-1. Invalid offsets
* will result in a {@link PelDataWindowOffsetException} being
* thrown.
* @return integer the signed byte found at offset.
* @throws PelDataWindowOffsetException
*/
public function getSByte($offset = 0)
{
/*
* Validate the offset --- this throws an exception if offset is
* out of range.
*/
$this->validateOffset($offset);
/* Translate the offset into an offset into the data. */
$offset += $this->start;
/* Return a signed byte. */
return PelConvert::bytesToSByte($this->data, $offset);
}
/**
* Return an unsigned short read from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first short available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-2. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
* @return integer the unsigned short found at offset.
* @throws PelDataWindowOffsetException
*/
public function getShort($offset = 0)
{
/*
* Validate the offset+1 to see if we can safely get two bytes ---
* this throws an exception if offset is out of range.
*/
$this->validateOffset($offset);
$this->validateOffset($offset + 1);
/* Translate the offset into an offset into the data. */
$offset += $this->start;
/* Return an unsigned short. */
return PelConvert::bytesToShort($this->data, $offset, $this->order);
}
/**
* Return a signed short read from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first short available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-2. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
* @return integer the signed short found at offset.
* @throws PelDataWindowOffsetException
*/
public function getSShort($offset = 0)
{
/*
* Validate the offset+1 to see if we can safely get two bytes ---
* this throws an exception if offset is out of range.
*/
$this->validateOffset($offset);
$this->validateOffset($offset + 1);
/* Translate the offset into an offset into the data. */
$offset += $this->start;
/* Return a signed short. */
return PelConvert::bytesToSShort($this->data, $offset, $this->order);
}
/**
* Return an unsigned long read from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first long available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-4. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
* @return integer the unsigned long found at offset.
* @throws PelDataWindowOffsetException
*/
public function getLong($offset = 0)
{
/*
* Validate the offset+3 to see if we can safely get four bytes
* --- this throws an exception if offset is out of range.
*/
$this->validateOffset($offset);
$this->validateOffset($offset + 3);
/* Translate the offset into an offset into the data. */
$offset += $this->start;
/* Return an unsigned long. */
return PelConvert::bytesToLong($this->data, $offset, $this->order);
}
/**
* Return a signed long read from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first long available in the current allowed window.
* The last valid offset is equal to {@link getSize()}-4. Invalid
* offsets will result in a {@link PelDataWindowOffsetException}
* being thrown.
* @return integer the signed long found at offset.
* @throws PelDataWindowOffsetException
*/
public function getSLong($offset = 0)
{
/*
* Validate the offset+3 to see if we can safely get four bytes
* --- this throws an exception if offset is out of range.
*/
$this->validateOffset($offset);
$this->validateOffset($offset + 3);
/* Translate the offset into an offset into the data. */
$offset += $this->start;
/* Return a signed long. */
return PelConvert::bytesToSLong($this->data, $offset, $this->order);
}
/**
* Return an unsigned rational read from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first rational available in the current allowed
* window. The last valid offset is equal to {@link getSize()}-8.
* Invalid offsets will result in a {@link
* PelDataWindowOffsetException} being thrown.
* @return array the unsigned rational found at offset. A rational
* number is represented as an array of two numbers: the enumerator
* and denominator. Both of these numbers will be unsigned longs.
* @throws PelDataWindowOffsetException
*/
public function getRational($offset = 0)
{
return [
$this->getLong($offset),
$this->getLong($offset + 4)
];
}
/**
* Return a signed rational read from the data.
*
* @param integer $offset
* the offset into the data. An offset of zero will
* return the first rational available in the current allowed
* window. The last valid offset is equal to {@link getSize()}-8.
* Invalid offsets will result in a {@link
* PelDataWindowOffsetException} being thrown.
* @return array the signed rational found at offset. A rational
* number is represented as an array of two numbers: the enumerator
* and denominator. Both of these numbers will be signed longs.
* @throws PelDataWindowOffsetException
*/
public function getSRational($offset = 0)
{
return [
$this->getSLong($offset),
$this->getSLong($offset + 4)
];
}
/**
* String comparison on substrings.
*
* @param integer $offset
* the offset into the data. An offset of zero will make
* the comparison start with the very first byte available in the
* window. The last valid offset is equal to {@link getSize()}
* minus the length of the string. If the string is too long, then
* a {@link PelDataWindowOffsetException} will be thrown.
* @param string $str
* the string to compare with.
* @return boolean true if the string given matches the data in the
* window, at the specified offset, false otherwise. The comparison
* will stop as soon as a mismatch if found.
* @throws PelDataWindowOffsetException
*/
public function strcmp($offset, $str)
{
/*
* Validate the offset of the final character we might have to
* check.
*/
$s = strlen($str);
$this->validateOffset($offset);
$this->validateOffset($offset + $s - 1);
/* Translate the offset into an offset into the data. */
$offset += $this->start;
/* Check each character, return as soon as the answer is known. */
for ($i = 0; $i < $s; $i ++) {
if ($this->data[$offset + $i] != $str[$i]) {
return false;
}
}
/* All characters matches each other, return true. */
return true;
}
/**
* Return a string representation of the data window.
*
* @return string a description of the window with information about
* the number of bytes accessible, the total number of bytes, and
* the window start and stop.
*/
public function __toString()
{
return Pel::fmt('DataWindow: %d bytes in [%d, %d] of %d bytes', $this->size, $this->start, $this->start + $this->size, strlen($this->data));
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
namespace lsolesen\pel;
/**
* An exception thrown when an invalid offset is encountered.
*
* @package PEL
* @subpackage Exception
*/
class PelDataWindowOffsetException extends PelException
{
}

View File

@ -0,0 +1,43 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
namespace lsolesen\pel;
/**
* A container for bytes with a limited window of accessible bytes.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License (GPL)
* @package PEL
*/
/**
* An exception thrown when an invalid window is encountered.
*
* @package PEL
* @subpackage Exception
*/
class PelDataWindowWindowException extends PelException
{
}

View File

@ -0,0 +1,251 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with Exif entries.
*
* This file defines two exception classes and the abstract class
* {@link PelEntry} which provides the basic methods that all Exif
* entries will have. All Exif entries will be represented by
* descendants of the {@link PelEntry} class --- the class itself is
* abstract and so it cannot be instantiated.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Common ancestor class of all {@link PelIfd} entries.
*
* As this class is abstract you cannot instantiate objects from it.
* It only serves as a common ancestor to define the methods common to
* all entries. The most important methods are {@link getValue()} and
* {@link setValue()}, both of which is abstract in this class. The
* descendants will give concrete implementations for them.
*
* If you have some data coming from an image (some raw bytes), then
* the static method {@link newFromData()} is helpful --- it will look
* at the data and give you a proper decendent of {@link PelEntry}
* back.
*
* If you instead want to have an entry for some data which take the
* form of an integer, a string, a byte, or some other PHP type, then
* don't use this class. You should instead create an object of the
* right subclass ({@link PelEntryShort} for short integers, {@link
* PelEntryAscii} for strings, and so on) directly.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
abstract class PelEntry
{
/**
* Type of IFD containing this tag.
*
* This must be one of the constants defined in {@link PelIfd}:
* {@link PelIfd::IFD0} for the main image IFD, {@link PelIfd::IFD1}
* for the thumbnail image IFD, {@link PelIfd::EXIF} for the Exif
* sub-IFD, {@link PelIfd::GPS} for the GPS sub-IFD, or {@link
* PelIfd::INTEROPERABILITY} for the interoperability sub-IFD.
*
* @var int
*/
protected $ifd_type;
/**
* The bytes representing this entry.
*
* Subclasses must either override {@link getBytes()} or, if
* possible, maintain this property so that it always contains a
* true representation of the entry.
*
* @var string
*/
protected $bytes = '';
/**
* The {@link PelTag} of this entry.
*
* @var int
*/
protected $tag;
/**
* The {@link PelFormat} of this entry.
*
* @var int
*/
protected $format;
/**
* The number of components of this entry.
*
* @var int
*/
protected $components;
/**
* Return the tag of this entry.
*
* @return int the tag of this entry.
*/
public function getTag()
{
return $this->tag;
}
/**
* Return the type of IFD which holds this entry.
*
* @return int one of the constants defined in {@link PelIfd}:
* {@link PelIfd::IFD0} for the main image IFD, {@link PelIfd::IFD1}
* for the thumbnail image IFD, {@link PelIfd::EXIF} for the Exif
* sub-IFD, {@link PelIfd::GPS} for the GPS sub-IFD, or {@link
* PelIfd::INTEROPERABILITY} for the interoperability sub-IFD.
*/
public function getIfdType()
{
return $this->ifd_type;
}
/**
* Update the IFD type.
*
* @param int $type
* must be one of the constants defined in {@link
* PelIfd}: {@link PelIfd::IFD0} for the main image IFD, {@link
* PelIfd::IFD1} for the thumbnail image IFD, {@link PelIfd::EXIF}
* for the Exif sub-IFD, {@link PelIfd::GPS} for the GPS sub-IFD, or
* {@link PelIfd::INTEROPERABILITY} for the interoperability
* sub-IFD.
*/
public function setIfdType($type)
{
$this->ifd_type = $type;
}
/**
* Return the format of this entry.
*
* @return int the format of this entry.
*/
public function getFormat()
{
return $this->format;
}
/**
* Return the number of components of this entry.
*
* @return int the number of components of this entry.
*/
public function getComponents()
{
return $this->components;
}
/**
* Turn this entry into bytes.
*
* @param boolean $o
* the desired byte order, which must be either
* {@link Convert::LITTLE_ENDIAN} or {@link Convert::BIG_ENDIAN}.
* @return string bytes representing this entry.
*/
public function getBytes($o)
{
return $this->bytes;
}
/**
* Get the value of this entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., rationals will be returned as 'x/y', ASCII strings will be
* returned as themselves etc.
*
* @param boolean $brief
* some values can be returned in a long or more
* brief form, and this parameter controls that.
* @return string the value as text.
*/
abstract public function getText($brief = false);
/**
* Get the value of this entry.
*
* The value returned will generally be the same as the one supplied
* to the constructor or with {@link setValue()}. For a formatted
* version of the value, one should use {@link getText()} instead.
*
* @return mixed the unformatted value.
*/
abstract public function getValue();
/**
* Set the value of this entry.
*
* The value should be in the same format as for the constructor.
*
* @param mixed $value
* the new value.
* @abstract
*
*/
public function setValue($value)
{
/*
* This (fake) abstract method is here to make it possible for the
* documentation to refer to PelEntry::setValue().
* It cannot declared abstract in the proper PHP way, for then PHP
* wont allow subclasses to define it with two arguments (which is
* what PelEntryCopyright does).
*/
throw new PelException('setValue() is abstract.');
}
/**
* Turn this entry into a string.
*
* @return string a string representation of this entry. This is
* mostly for debugging.
*/
public function __toString()
{
$str = Pel::fmt(" Tag: 0x%04X (%s)\n", $this->tag, PelTag::getName($this->ifd_type, $this->tag));
$str .= Pel::fmt(" Format : %d (%s)\n", $this->format, PelFormat::getName($this->format));
$str .= Pel::fmt(" Components: %d\n", $this->components);
if ($this->getTag() != PelTag::MAKER_NOTE && $this->getTag() != PelTag::PRINT_IM) {
$str .= Pel::fmt(" Value : %s\n", print_r($this->getValue(), true));
}
$str .= Pel::fmt(" Text : %s\n", $this->getText());
return $str;
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to hold ASCII strings.
*
* The classes defined here are to be used for Exif entries holding
* ASCII strings, such as {@link PelTag::MAKE}, {@link
* PelTag::SOFTWARE}, and {@link PelTag::DATE_TIME}. For
* entries holding normal textual ASCII strings the class {@link
* PelEntryAscii} should be used, but for entries holding
* timestamps the class {@link PelEntryTime} would be more
* convenient instead. Copyright information is handled by the {@link
* PelEntryCopyright} class.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding a plain ASCII string.
*
* This class can hold a single ASCII string, and it will be used as in
* <code>
* $entry = $ifd->getEntry(PelTag::IMAGE_DESCRIPTION);
* print($entry->getValue());
* $entry->setValue('This is my image. I like it.');
* </code>
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryAscii extends PelEntry
{
/**
* The string hold by this entry.
*
* This is the string that was given to the {@link __construct
* constructor} or later to {@link setValue}, without any final NULL
* character.
*
* @var string
*/
private $str;
/**
* Make a new PelEntry that can hold an ASCII string.
*
* @param int $tag
* the tag which this entry represents. This should be
* one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::IMAGE_DESCRIPTION}, {@link PelTag::MODEL}, or any other
* tag with format {@link PelFormat::ASCII}.
* @param string $str
* the string that this entry will represent. The
* string must obey the same rules as the string argument to {@link
* setValue}, namely that it should be given without any trailing
* NULL character and that it must be plain 7-bit ASCII.
*/
public function __construct($tag, $str = '')
{
$this->tag = $tag;
$this->format = PelFormat::ASCII;
$this->setValue($str);
}
/**
*
* {@inheritdoc}
* @see \lsolesen\pel\PelEntry::setValue()
*/
public function setValue($str)
{
$this->components = strlen($str) + 1;
$this->str = $str;
$this->bytes = $str . chr(0x00);
}
/**
*
* {@inheritdoc}
* @see \lsolesen\pel\PelEntry::getValue()
*/
public function getValue()
{
return $this->str;
}
/**
*
* {@inheritdoc}
* @see \lsolesen\pel\PelEntry::getText()
*/
public function getText($brief = false)
{
return $this->str;
}
}

View File

@ -0,0 +1,92 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to hold bytes, both signed and unsigned.
* The {@link
* PelEntryWindowsString} class is used to manipulate strings in the
* format Windows XP needs.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding unsigned bytes.
*
* This class can hold bytes, either just a single byte or an array of
* bytes. The class will be used to manipulate any of the Exif tags
* which has format {@link PelFormat::BYTE}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryByte extends PelEntryNumber
{
/**
* Make a new entry that can hold an unsigned byte.
*
* The method accept several integer arguments. The {@link
* getValue} method will always return an array except for when a
* single integer argument is given here.
*
* @param int $tag
* the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which has format {@link PelFormat::BYTE}.
* @param int $value...
* the byte(s) that this entry will represent.
* The argument passed must obey the same rules as the argument to
* {@link setValue}, namely that it should be within range of an
* unsigned byte, that is between 0 and 255 (inclusive). If not,
* then a {@link PelOverflowException} will be thrown.
*/
public function __construct($tag, $value = null)
{
$this->tag = $tag;
$this->min = 0;
$this->max = 255;
$this->format = PelFormat::BYTE;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
*
* {@inheritdoc}
* @see \lsolesen\pel\PelEntryNumber::numberToBytes()
*/
public function numberToBytes($number, $order)
{
return chr($number);
}
}

View File

@ -0,0 +1,171 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class for holding copyright information.
*
* The Exif standard specifies a certain format for copyright
* information where the one {@link PelTag::COPYRIGHT copyright
* tag} holds both the photographer and editor copyrights, separated
* by a NULL character.
*
* This class is used to manipulate that tag so that the format is
* kept to the standard. A common use would be to add a new copyright
* tag to an image, since most cameras do not add this tag themselves.
* This would be done like this:
*
* <code>
* $entry = new PelEntryCopyright('Copyright, Martin Geisler, 2004');
* $ifd0->addEntry($entry);
* </code>
*
* Here we only set the photographer copyright, use the optional
* second argument to specify the editor copyright. If there is only
* an editor copyright, then let the first argument be the empty
* string.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryCopyright extends PelEntryAscii
{
/**
* The photographer copyright.
*
* @var string
*/
private $photographer;
/**
* The editor copyright.
*
* @var string
*/
private $editor;
/**
* Make a new entry for holding copyright information.
*
* @param string $photographer
* the photographer copyright. Use the empty string
* if there is no photographer copyright.
* @param string $editor
* the editor copyright. Use the empty string if
* there is no editor copyright.
*/
public function __construct($photographer = '', $editor = '')
{
parent::__construct(PelTag::COPYRIGHT);
$this->setValue($photographer, $editor);
}
/**
* Update the copyright information.
*
* @param
* string the photographer copyright. Use the empty string
* if there is no photographer copyright.
* @param
* string the editor copyright. Use the empty string if
* there is no editor copyright.
*/
public function setValue($photographer = '', $editor = '')
{
$this->photographer = $photographer;
$this->editor = $editor;
if ($photographer == '' && $editor != '') {
$photographer = ' ';
}
if ($editor == '') {
parent::setValue($photographer);
} else {
parent::setValue($photographer . chr(0x00) . $editor);
}
}
/**
* Retrive the copyright information.
*
* The strings returned will be the same as the one used previously
* with either {@link __construct the constructor} or with {@link
* setValue}.
*
* @return array an array with two strings, the photographer and
* editor copyrights. The two fields will be returned in that
* order, so that the first array index will be the photographer
* copyright, and the second will be the editor copyright.
*/
public function getValue()
{
return [
$this->photographer,
$this->editor
];
}
/**
* Return a text string with the copyright information.
*
* The photographer and editor copyright fields will be returned
* with a '-' in between if both copyright fields are present,
* otherwise only one of them will be returned.
*
* @param boolean $brief
* if false, then the strings '(Photographer)' and
* '(Editor)' will be appended to the photographer and editor
* copyright fields (if present), otherwise the fields will be
* returned as is.
* @return string the copyright information in a string.
*/
public function getText($brief = false)
{
if ($brief) {
$p = '';
$e = '';
} else {
$p = ' ' . Pel::tra('(Photographer)');
$e = ' ' . Pel::tra('(Editor)');
}
if ($this->photographer != '' && $this->editor != '') {
return $this->photographer . $p . ' - ' . $this->editor . $e;
}
if ($this->photographer != '') {
return $this->photographer . $p;
}
if ($this->editor != '') {
return $this->editor . $e;
}
return '';
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with Exif entries.
*
* This file defines two exception classes and the abstract class
* {@link PelEntry} which provides the basic methods that all Exif
* entries will have. All Exif entries will be represented by
* descendants of the {@link PelEntry} class --- the class itself is
* abstract and so it cannot be instantiated.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Exception indicating a problem with an entry.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelEntryException extends PelException
{
/**
* The IFD type (if known).
*
* @var int
*/
protected $type;
/**
* The tag of the entry (if known).
*
* @var int
*/
protected $tag;
/**
* Get the IFD type associated with the exception.
*
* @return int one of {@link PelIfd::IFD0}, {@link PelIfd::IFD1},
* {@link PelIfd::EXIF}, {@link PelIfd::GPS}, or {@link
* PelIfd::INTEROPERABILITY}. If no type is set, null is returned.
*/
public function getIfdType()
{
return $this->type;
}
/**
* Get the tag associated with the exception.
*
* @return int the tag. If no tag is set, null is returned.
*/
public function getTag()
{
return $this->tag;
}
}

View File

@ -0,0 +1,115 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
namespace lsolesen\pel;
/**
* Classes used to hold longs, both signed and unsigned.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding unsigned longs.
*
* This class can hold longs, either just a single long or an array of
* longs. The class will be used to manipulate any of the Exif tags
* which can have format {@link PelFormat::LONG} like in this
* example:
* <code>
* $w = $ifd->getEntry(PelTag::EXIF_IMAGE_WIDTH);
* $w->setValue($w->getValue() / 2);
* $h = $ifd->getEntry(PelTag::EXIF_IMAGE_HEIGHT);
* $h->setValue($h->getValue() / 2);
* </code>
* Here the width and height is updated to 50% of their original
* values.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
class PelEntryLong extends PelEntryNumber
{
/**
* Make a new entry that can hold an unsigned long.
*
* The method accept its arguments in two forms: several integer
* arguments or a single array argument. The {@link getValue}
* method will always return an array except for when a single
* integer argument is given here, or when an array with just a
* single integer is given.
*
* This means that one can conveniently use objects like this:
* <code>
* $a = new PelEntryLong(PelTag::EXIF_IMAGE_WIDTH, 123456);
* $b = $a->getValue() - 654321;
* </code>
* where the call to {@link getValue} will return an integer instead
* of an array with one integer element, which would then have to be
* extracted.
*
* @param int $tag
* the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag},
* e.g., {@link PelTag::IMAGE_WIDTH}, or any other tag which can
* have format {@link PelFormat::LONG}.
* @param int $value...
* the long(s) that this entry will
* represent or an array of longs. The argument passed must obey
* the same rules as the argument to {@link setValue}, namely that
* it should be within range of an unsigned long (32 bit), that is
* between 0 and 4294967295 (inclusive). If not, then a {@link
* PelExifOverflowException} will be thrown.
*/
public function __construct($tag, $value = null)
{
$this->tag = $tag;
$this->min = 0;
$this->max = 4294967295;
$this->format = PelFormat::LONG;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int $number
* the number that should be converted.
* @param boolean $order
* one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
* @return string bytes representing the number given.
*/
public function numberToBytes($number, $order)
{
return PelConvert::longToBytes($number, $order);
}
}

View File

@ -0,0 +1,280 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Abstract class for numbers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding numbers.
*
* This class can hold numbers, with range checks.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
abstract class PelEntryNumber extends PelEntry
{
/**
* The value held by this entry.
*
* @var array
*/
protected $value = [];
/**
* The minimum allowed value.
*
* Any attempt to change the value below this variable will result
* in a {@link PelOverflowException} being thrown.
*
* @var int
*/
protected $min;
/**
* The maximum allowed value.
*
* Any attempt to change the value over this variable will result in
* a {@link PelOverflowException} being thrown.
*
* @var int
*/
protected $max;
/**
* The dimension of the number held.
*
* Normal numbers have a dimension of one, pairs have a dimension of
* two, etc.
*
* @var int
*/
protected $dimension = 1;
/**
* Change the value.
*
* This method can change both the number of components and the
* value of the components. Range checks will be made on the new
* value, and a {@link PelOverflowException} will be thrown if the
* value is found to be outside the legal range.
*
* The method accept several number arguments. The {@link getValue}
* method will always return an array except for when a single
* number is given here.
*
* @param int|array $value...
* the new value(s). This can be zero or
* more numbers, that is, either integers or arrays. The input will
* be checked to ensure that the numbers are within the valid range.
* If not, then a {@link PelOverflowException} will be thrown.
* @see PelEntryNumber::getValue
*/
public function setValue($value)
{
$value = func_get_args();
$this->setValueArray($value);
}
/**
* Change the value.
*
* This method can change both the number of components and the
* value of the components. Range checks will be made on the new
* value, and a {@link PelOverflowException} will be thrown if the
* value is found to be outside the legal range.
*
* @param array $values
* the new values. The array must contain the new
* numbers.
* @see PelEntryNumber::getValue
*/
public function setValueArray($values)
{
foreach ($values as $v) {
$this->validateNumber($v);
}
$this->components = count($values);
$this->value = $values;
}
/**
* Return the numeric value held.
*
* @return int|array this will either be a single number if there is
* only one component, or an array of numbers otherwise.
*/
public function getValue()
{
if ($this->components == 1) {
return $this->value[0];
} else {
return $this->value;
}
}
/**
* Validate a number.
*
* This method will check that the number given is within the range
* given my {@link getMin()} and {@link getMax()}, inclusive. If
* not, then a {@link PelOverflowException} is thrown.
*
* @param int|array $n
* the number in question.
* @return void nothing, but will throw a {@link
* PelOverflowException} if the number is found to be outside the
* legal range and {@link Pel::$strict} is true.
*/
public function validateNumber($n)
{
if ($this->dimension == 1 || is_scalar($n)) {
if ($n < $this->min || $n > $this->max) {
Pel::maybeThrow(new PelOverflowException((int) $n, $this->min, $this->max));
}
} else {
for ($i = 0; $i < $this->dimension; $i ++) {
if (! isset($n[$i])) {
continue;
}
if ($n[$i] < $this->min || $n[$i] > $this->max) {
Pel::maybeThrow(new PelOverflowException($n[$i], $this->min, $this->max));
}
}
}
}
/**
* Add a number.
*
* This appends a number to the numbers already held by this entry,
* thereby increasing the number of components by one.
*
* @param int|array $n
* the number to be added.
*/
public function addNumber($n)
{
$this->validateNumber($n);
$this->value[] = $n;
$this->components ++;
}
/**
* Convert a number into bytes.
*
* The concrete subclasses will have to implement this method so
* that the numbers represented can be turned into bytes.
*
* The method will be called once for each number held by the entry.
*
* @param int $number
* the number that should be converted.
* @param boolean $order
* one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
* @return string bytes representing the number given.
*/
abstract public function numberToBytes($number, $order);
/**
* Turn this entry into bytes.
*
* @param boolean $o
* the desired byte order, which must be either
* {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}.
* @return string bytes representing this entry.
*/
public function getBytes($o)
{
$bytes = '';
for ($i = 0; $i < $this->components; $i ++) {
if ($this->dimension == 1) {
$bytes .= $this->numberToBytes($this->value[$i], $o);
} else {
for ($j = 0; $j < $this->dimension; $j ++) {
$bytes .= $this->numberToBytes($this->value[$i][$j], $o);
}
}
}
return $bytes;
}
/**
* Format a number.
*
* This method is called by {@link getText} to format numbers.
* Subclasses should override this method if they need more
* sophisticated behavior than the default, which is to just return
* the number as is.
*
* @param int $number
* the number which will be formatted.
* @param boolean $brief
* it could be that there is both a verbose and a
* brief formatting available, and this argument controls that.
* @return string the number formatted as a string suitable for
* display.
*/
public function formatNumber($number, $brief = false)
{
return $number;
}
/**
* Get the numeric value of this entry as text.
*
* @param boolean $brief
* use brief output? The numbers will be separated
* by a single space if brief output is requested, otherwise a space
* and a comma will be used.
* @return string the numbers(s) held by this entry.
*/
public function getText($brief = false)
{
if ($this->components == 0) {
return '';
}
$str = $this->formatNumber($this->value[0]);
for ($i = 1; $i < $this->components; $i ++) {
$str .= ($brief ? ' ' : ', ');
$str .= $this->formatNumber($this->value[$i]);
}
return $str;
}
}

View File

@ -0,0 +1,174 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to manipulate rational numbers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding unsigned rational numbers.
*
* This class can hold rational numbers, consisting of a numerator and
* denominator both of which are of type unsigned long. Each rational
* is represented by an array with just two entries: the numerator and
* the denominator, in that order.
*
* The class can hold either just a single rational or an array of
* rationals. The class will be used to manipulate any of the Exif
* tags which can have format {@link PelFormat::RATIONAL} like in this
* example:
*
* <code>
* $resolution = $ifd->getEntry(PelTag::X_RESOLUTION);
* $resolution->setValue([1, 300]);
* </code>
*
* Here the x-resolution is adjusted to 1/300, which will be 300 DPI,
* unless the {@link PelTag::RESOLUTION_UNIT resolution unit} is set
* to something different than 2 which means inches.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryRational extends PelEntryLong
{
/**
* Make a new entry that can hold an unsigned rational.
*
* @param int $tag
* the tag which this entry represents. This should
* be one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::X_RESOLUTION}, or any other tag which can have format
* {@link PelFormat::RATIONAL}.
* @param array ...$value
* the rational(s) that this entry will
* represent. The arguments passed must obey the same rules as the
* argument to {@link setValue}, namely that each argument should be
* an array with two entries, both of which must be within range of
* an unsigned long (32 bit), that is between 0 and 4294967295
* (inclusive). If not, then a {@link PelOverflowException} will be
* thrown.
* @throws PelOverflowException
*/
public function __construct($tag, ...$value)
{
$this->tag = $tag;
$this->format = PelFormat::RATIONAL;
$this->dimension = 2;
$this->min = 0;
$this->max = 4294967295;
$this->setValueArray($value);
}
/**
* Format a rational number.
*
* The rational will be returned as a string with a slash '/'
* between the numerator and denominator.
*
* @param array $number
* the rational which will be formatted.
* @param boolean $brief
* not used.
* @return string the rational formatted as a string suitable for
* display.
*/
public function formatNumber($number, $brief = false)
{
return $number[0] . '/' . $number[1];
}
/**
* Get the value of an entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., rationals will be returned as 'x/y', ASCII strings will be
* returned as themselves etc.
*
* @param boolean $brief
* some values can be returned in a long or more
* brief form, and this parameter controls that.
* @return boolean|string the value as text.
*/
public function getText($brief = false)
{
if (isset($this->value[0])) {
$v = $this->value[0];
} else {
// TODO: Not sure, if this is the correct path; maybe throw an exception?
return '';
}
switch ($this->tag) {
case PelTag::FNUMBER:
// CC (e->components, 1, v);
return Pel::fmt('f/%.01f', $v[0] / $v[1]);
case PelTag::APERTURE_VALUE:
// CC (e->components, 1, v);
// if (!v_rat.denominator) return (NULL);
return Pel::fmt('f/%.01f', pow(2, $v[0] / $v[1] / 2));
case PelTag::FOCAL_LENGTH:
// CC (e->components, 1, v);
// if (!v_rat.denominator) return (NULL);
return Pel::fmt('%.1f mm', $v[0] / $v[1]);
case PelTag::SUBJECT_DISTANCE:
// CC (e->components, 1, v);
// if (!v_rat.denominator) return (NULL);
return Pel::fmt('%.1f m', $v[0] / $v[1]);
case PelTag::EXPOSURE_TIME:
// CC (e->components, 1, v);
// if (!v_rat.denominator) return (NULL);
if ($v[0] / $v[1] < 1) {
return Pel::fmt('1/%d sec.', $v[1] / $v[0]);
} else {
return Pel::fmt('%d sec.', $v[0] / $v[1]);
}
break;
case PelTag::GPS_LATITUDE:
case PelTag::GPS_LONGITUDE:
$degrees = $v[0] / $v[1];
$minutes = $this->value[1][0] / $this->value[1][1];
$seconds = $this->value[2][0] / $this->value[2][1];
return sprintf('%s° %s\' %s" (%.2f°)', $degrees, $minutes, $seconds, $degrees + $minutes / 60 + $seconds / 3600);
default:
return parent::getText($brief);
}
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to hold bytes, both signed and unsigned.
* The {@link
* PelEntryWindowsString} class is used to manipulate strings in the
* format Windows XP needs.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding signed bytes.
*
* This class can hold bytes, either just a single byte or an array of
* bytes. The class will be used to manipulate any of the Exif tags
* which has format {@link PelFormat::BYTE}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntrySByte extends PelEntryNumber
{
/**
* Make a new entry that can hold a signed byte.
*
* The method accept several integer arguments. The {@link getValue}
* method will always return an array except for when a single
* integer argument is given here.
*
* @param int $tag
* the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which has format {@link PelFormat::BYTE}.
* @param int $value...
* the byte(s) that this entry will represent.
* The argument passed must obey the same rules as the argument to
* {@link setValue}, namely that it should be within range of a
* signed byte, that is between -128 and 127 (inclusive). If not,
* then a {@link PelOverflowException} will be thrown.
*/
public function __construct($tag, $value = null)
{
$this->tag = $tag;
$this->min = - 128;
$this->max = 127;
$this->format = PelFormat::SBYTE;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int $number
* the number that should be converted.
* @param boolean $order
* one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
* @return string bytes representing the number given.
*/
public function numberToBytes($number, $order)
{
return chr($number);
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to hold longs, both signed and unsigned.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding signed longs.
*
* This class can hold longs, either just a single long or an array of
* longs. The class will be used to manipulate any of the Exif tags
* which can have format {@link PelFormat::SLONG}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntrySLong extends PelEntryNumber
{
/**
* Make a new entry that can hold a signed long.
*
* The method accept its arguments in two forms: several integer
* arguments or a single array argument. The {@link getValue}
* method will always return an array except for when a single
* integer argument is given here, or when an array with just a
* single integer is given.
*
* @param int $tag
* the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which have format {@link PelFormat::SLONG}.
* @param int $value
* the long(s) that this entry will represent
* or an array of longs. The argument passed must obey the same
* rules as the argument to {@link setValue}, namely that it should
* be within range of a signed long (32 bit), that is between
* -2147483648 and 2147483647 (inclusive). If not, then a {@link
* PelOverflowException} will be thrown.
*/
public function __construct($tag, $value = null)
{
$this->tag = $tag;
$this->min = - 2147483648;
$this->max = 2147483647;
$this->format = PelFormat::SLONG;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int $number
* the number that should be converted.
* @param boolean $order
* one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
* @return string bytes representing the number given.
*/
public function numberToBytes($number, $order)
{
return PelConvert::sLongToBytes($number, $order);
}
}

View File

@ -0,0 +1,150 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to manipulate rational numbers.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding signed rational numbers.
*
* This class can hold rational numbers, consisting of a numerator and
* denominator both of which are of type unsigned long. Each rational
* is represented by an array with just two entries: the numerator and
* the denominator, in that order.
*
* The class can hold either just a single rational or an array of
* rationals. The class will be used to manipulate any of the Exif
* tags which can have format {@link PelFormat::SRATIONAL}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntrySRational extends PelEntrySLong
{
/**
* Make a new entry that can hold a signed rational.
*
* @param int $tag
* the tag which this entry represents. This should
* be one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::SHUTTER_SPEED_VALUE}, or any other tag which can have
* format {@link PelFormat::SRATIONAL}.
* @param array $value
* the rational(s) that this entry will
* represent. The arguments passed must obey the same rules as the
* argument to {@link setValue}, namely that each argument should be
* an array with two entries, both of which must be within range of
* a signed long (32 bit), that is between -2147483648 and
* 2147483647 (inclusive). If not, then a {@link
* PelOverflowException} will be thrown.
*/
public function __construct($tag, $value = null)
{
$this->tag = $tag;
$this->format = PelFormat::SRATIONAL;
$this->dimension = 2;
$this->min = - 2147483648;
$this->max = 2147483647;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Format a rational number.
*
* The rational will be returned as a string with a slash '/'
* between the numerator and denominator. Care is taken to display
* '-1/2' instead of the ugly but mathematically equivalent '1/-2'.
*
* @param array $number
* the rational which will be formatted.
* @param boolean $brief
* not used.
* @return string the rational formatted as a string suitable for
* display.
*/
public function formatNumber($number, $brief = false)
{
if ($number[1] < 0) {
/* Turn output like 1/-2 into -1/2. */
return (- $number[0]) . '/' . (- $number[1]);
} else {
return $number[0] . '/' . $number[1];
}
}
/**
* Get the value of an entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., rationals will be returned as 'x/y', ASCII strings will be
* returned as themselves etc.
*
* @param boolean $brief
* some values can be returned in a long or more
* brief form, and this parameter controls that.
* @return string the value as text.
*/
public function getText($brief = false)
{
if (isset($this->value[0])) {
$v = $this->value[0];
}
switch ($this->tag) {
case PelTag::SHUTTER_SPEED_VALUE:
// CC (e->components, 1, v);
// if (!v_srat.denominator) return (NULL);
return Pel::fmt('%.0f/%.0f sec. (APEX: %d)', $v[0], $v[1], pow(sqrt(2), $v[0] / $v[1]));
case PelTag::BRIGHTNESS_VALUE:
// CC (e->components, 1, v);
//
// TODO: figure out the APEX thing, or remove this so that it is
// handled by the default clause at the bottom.
return sprintf('%d/%d', $v[0], $v[1]);
// FIXME: How do I calculate the APEX value?
case PelTag::EXPOSURE_BIAS_VALUE:
// CC (e->components, 1, v);
// if (!v_srat.denominator) return (NULL);
return sprintf('%s%.01f', $v[0] * $v[1] > 0 ? '+' : '', $v[0] / $v[1]);
default:
return parent::getText($brief);
}
}
}

View File

@ -0,0 +1,806 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to hold shorts, both signed and unsigned.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding signed shorts.
*
* This class can hold shorts, either just a single short or an array
* of shorts. The class will be used to manipulate any of the Exif
* tags which has format {@link PelFormat::SSHORT}.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntrySShort extends PelEntryNumber
{
private const TRANSLATIONS = [
PelIfd::CANON_FILE_INFO => [
PelTag::CANON_FI_BRACKET_MODE => [
0 => 'Off',
1 => 'AEB',
2 => 'FEB',
3 => 'ISO',
4 => 'WB'
],
PelTag::CANON_FI_RAW_JPG_QUALITY => [
1 => 'Economy',
2 => 'Normal',
3 => 'Fine',
4 => 'RAW',
5 => 'Superfine',
130 => 'Normal Movie',
131 => 'Movie (2)'
],
PelTag::CANON_FI_RAW_JPG_SIZE => [
0 => 'Large',
1 => 'Medium',
2 => 'Small',
5 => 'Medium 1',
6 => 'Medium 2',
7 => 'Medium 3',
8 => 'Postcard',
9 => 'Widescreen',
10 => 'Medium Widescreen',
14 => 'Small 1',
15 => 'Small 2',
16 => 'Small 3',
128 => '640x480 Movie',
129 => 'Medium Movie',
130 => 'Small Movie',
137 => '1280x720 Movie',
142 => '1920x1080 Movie'
],
PelTag::CANON_FI_NOISE_REDUCTION => [
0 => 'Off',
1 => 'On (1D)',
3 => 'On',
4 => 'Auto'
],
PelTag::CANON_FI_WB_BRACKET_MODE => [
0 => 'Off',
1 => 'On (shift AB)',
2 => 'On (shift GM)'
],
PelTag::CANON_FI_FILTER_EFFECT => [
0 => 'None',
1 => 'Yellow',
2 => 'Orange',
3 => 'Red',
4 => 'Green'
],
PelTag::CANON_FI_TONING_EFFECT => [
0 => 'None',
1 => 'Sepia',
2 => 'Blue',
3 => 'Purple',
4 => 'Green'
],
PelTag::CANON_FI_LIVE_VIEW_SHOOTING => [
0 => 'Off',
1 => 'On'
],
PelTag::CANON_FI_FLASH_EXPOSURE_LOCK => [
0 => 'Off',
1 => 'On'
]
],
PelIfd::CANON_CAMERA_SETTINGS => [
PelTag::CANON_CS_MACRO => [
1 => 'Macro',
2 => 'Normal'
],
PelTag::CANON_CS_QUALITY => [
1 => 'Economy',
2 => 'Normal',
3 => 'Fine',
4 => 'RAW',
5 => 'Superfine',
130 => 'Normal Movie',
131 => 'Movie (2)'
],
PelTag::CANON_CS_FLASH_MODE => [
0 => 'Off',
1 => 'Auto',
2 => 'On',
3 => 'Red-eye reduction',
4 => 'Slow-sync',
5 => 'Red-eye reduction (Auto)',
6 => 'Red-eye reduction (On)',
16 => 'External flash'
],
PelTag::CANON_CS_DRIVE_MODE => [
0 => 'Single',
1 => 'Continuous',
2 => 'Movie',
3 => 'Continuous, Speed Priority',
4 => 'Continuous, Low',
5 => 'Continuous, High',
6 => 'Silent Single',
9 => 'Single, Silent',
10 => 'Continuous, Silent'
],
PelTag::CANON_CS_FOCUS_MODE => [
0 => 'One-shot AF',
1 => 'AI Servo AF',
2 => 'AI Focus AF',
3 => 'Manual Focus (3)',
4 => 'Single',
5 => 'Continuous',
6 => 'Manual Focus (6)',
16 => 'Pan Focus',
256 => 'AF + MF',
512 => 'Movie Snap Focus',
519 => 'Movie Servo AF'
],
PelTag::CANON_CS_RECORD_MODE => [
1 => 'JPEG',
2 => 'CRW+THM',
3 => 'AVI+THM',
4 => 'TIF',
5 => 'TIF+JPEG',
6 => 'CR2',
7 => 'CR2+JPEG',
9 => 'MOV',
10 => 'MP4'
],
PelTag::CANON_CS_IMAGE_SIZE => [
0 => 'Large',
1 => 'Medium',
2 => 'Small',
5 => 'Medium 1',
6 => 'Medium 2',
7 => 'Medium 3',
8 => 'Postcard',
9 => 'Widescreen',
10 => 'Medium Widescreen',
14 => 'Small 1',
15 => 'Small 2',
16 => 'Small 3',
128 => '640x480 Movie',
129 => 'Medium Movie',
130 => 'Small Movie',
137 => '1280x720 Movie',
142 => '1920x1080 Movie'
],
PelTag::CANON_CS_EASY_MODE => [
0 => 'Full auto',
1 => 'Manual',
2 => 'Landscape',
3 => 'Fast shutter',
4 => 'Slow shutter',
5 => 'Night',
6 => 'Gray Scale',
7 => 'Sepia',
8 => 'Portrait',
9 => 'Sports',
10 => 'Macro',
11 => 'Black & White',
12 => 'Pan focus',
13 => 'Vivid',
14 => 'Neutral',
15 => 'Flash Off',
16 => 'Long Shutter',
17 => 'Super Macro',
18 => 'Foliage',
19 => 'Indoor',
20 => 'Fireworks',
21 => 'Beach',
22 => 'Underwater',
23 => 'Snow',
24 => 'Kids & Pets',
25 => 'Night Snapshot',
26 => 'Digital Macro',
27 => 'My Colors',
28 => 'Movie Snap',
29 => 'Super Macro 2',
30 => 'Color Accent',
31 => 'Color Swap',
32 => 'Aquarium',
33 => 'ISO 3200',
34 => 'ISO 6400',
35 => 'Creative Light Effect',
36 => 'Easy',
37 => 'Quick Shot',
38 => 'Creative Auto',
39 => 'Zoom Blur',
40 => 'Low Light',
41 => 'Nostalgic',
42 => 'Super Vivid',
43 => 'Poster Effect',
44 => 'Face Self-timer',
45 => 'Smile',
46 => 'Wink Self-timer',
47 => 'Fisheye Effect',
48 => 'Miniature Effect',
49 => 'High-speed Burst',
50 => 'Best Image Selection',
51 => 'High Dynamic Range',
52 => 'Handheld Night Scene',
53 => 'Movie Digest',
54 => 'Live View Control',
55 => 'Discreet',
56 => 'Blur Reduction',
57 => 'Monochrome',
58 => 'Toy Camera Effect',
59 => 'Scene Intelligent Auto',
60 => 'High-speed Burst HQ',
61 => 'Smooth Skin',
62 => 'Soft Focus',
257 => 'Spotlight',
258 => 'Night 2',
259 => 'Night+',
260 => 'Super Night',
261 => 'Sunset',
263 => 'Night Scene',
264 => 'Surface',
265 => 'Low Light 2'
],
PelTag::CANON_CS_DIGITAL_ZOOM => [
0 => 'None',
1 => '2x',
2 => '4x',
3 => 'Other'
],
PelTag::CANON_CS_CONTRAST => [
0 => 'Normal'
],
PelTag::CANON_CS_SATURATION => [
0 => 'Normal'
],
PelTag::CANON_CS_METERING_MODE => [
0 => 'Default',
1 => 'Spot',
2 => 'Average',
3 => 'Evaluative',
4 => 'Partial',
5 => 'Center-weighted average'
],
PelTag::CANON_CS_FOCUS_TYPE => [
0 => 'Manual',
1 => 'Auto',
2 => 'Not Known',
3 => 'Macro',
4 => 'Very Close',
5 => 'Close',
6 => 'Middle Range',
7 => 'Far Range',
8 => 'Pan Focus',
9 => 'Super Macro',
10 => 'Infinity'
],
PelTag::CANON_CS_AF_POINT => [
0x2005 => 'Manual AF point selection',
0x3000 => 'None (MF)',
0x3001 => 'Auto AF point selection',
0x3002 => 'Right',
0x3003 => 'Center',
0x3004 => 'Left',
0x4001 => 'Auto AF point selection',
0x4006 => 'Face Detect'
],
PelTag::CANON_CS_EXPOSURE_PROGRAM => [
0 => 'Easy',
1 => 'Program AE',
2 => 'Shutter speed priority AE',
3 => 'Aperture-priority AE',
4 => 'Manual',
5 => 'Depth-of-field AE',
6 => 'M-Dep',
7 => 'Bulb'
],
PelTag::CANON_CS_LENS_TYPE => [
// ATTENTION: Every index is multiplied by 100
1000 => 'Canon EF 50mm f/1.8',
2000 => 'Canon EF 28mm f/2.8',
3000 => 'Canon EF 135mm f/2.8 Soft',
4000 => 'Canon EF 35-105mm f/3.5-4.5 or Sigma Lens',
4100 => 'Sigma UC Zoom 35-135mm f/4-5.6',
5000 => 'Canon EF 35-70mm f/3.5-4.5',
6000 => 'Canon EF 28-70mm f/3.5-4.5 or Sigma or Tokina Lens',
6100 => 'Sigma 18-50mm f/3.5-5.6 DC',
6200 => 'Sigma 18-125mm f/3.5-5.6 DC IF ASP',
6300 => 'Tokina AF 193-2 19-35mm f/3.5-4.5',
6400 => 'Sigma 28-80mm f/3.5-5.6 II Macro',
7000 => 'Canon EF 100-300mm f/5.6L',
8000 => 'Canon EF 100-300mm f/5.6 or Sigma or Tokina Lens',
8100 => 'Sigma 70-300mm f/4-5.6 [APO] DG Macro',
8200 => 'Tokina AT-X 242 AF 24-200mm f/3.5-5.6',
9000 => 'Canon EF 70-210mm f/4',
9100 => 'Sigma 55-200mm f/4-5.6 DC',
1000 => 'Canon EF 50mm f/2.5 Macro or Sigma Lens',
1010 => 'Sigma 50mm f/2.8 EX',
1020 => 'Sigma 28mm f/1.8',
1030 => 'Sigma 105mm f/2.8 Macro EX',
1040 => 'Sigma 70mm f/2.8 EX DG Macro EF',
1100 => 'Canon EF 35mm f/2',
1300 => 'Canon EF 15mm f/2.8 Fisheye',
1400 => 'Canon EF 50-200mm f/3.5-4.5L',
1500 => 'Canon EF 50-200mm f/3.5-4.5',
1600 => 'Canon EF 35-135mm f/3.5-4.5',
1700 => 'Canon EF 35-70mm f/3.5-4.5A',
1800 => 'Canon EF 28-70mm f/3.5-4.5',
2000 => 'Canon EF 100-200mm f/4.5A',
2100 => 'Canon EF 80-200mm f/2.8L',
2200 => 'Canon EF 20-35mm f/2.8L or Tokina Lens',
2210 => 'Tokina AT-X 280 AF Pro 28-80mm f/2.8 Aspherical',
2300 => 'Canon EF 35-105mm f/3.5-4.5',
2400 => 'Canon EF 35-80mm f/4-5.6 Power Zoom',
2500 => 'Canon EF 35-80mm f/4-5.6 Power Zoom',
2600 => 'Canon EF 100mm f/2.8 Macro or Other Lens',
2610 => 'Cosina 100mm f/3.5 Macro AF',
2620 => 'Tamron SP AF 90mm f/2.8 Di Macro',
2630 => 'Tamron SP AF 180mm f/3.5 Di Macro',
2640 => 'Carl Zeiss Planar T* 50mm f/1.4',
2700 => 'Canon EF 35-80mm f/4-5.6',
2800 => 'Canon EF 80-200mm f/4.5-5.6 or Tamron Lens',
2810 => 'Tamron SP AF 28-105mm f/2.8 LD Aspherical IF',
2820 => 'Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro',
2830 => 'Tamron AF 70-300mm f/4-5.6 Di LD 1:2 Macro',
2840 => 'Tamron AF Aspherical 28-200mm f/3.8-5.6',
2900 => 'Canon EF 50mm f/1.8 II',
3000 => 'Canon EF 35-105mm f/4.5-5.6',
3100 => 'Canon EF 75-300mm f/4-5.6 or Tamron Lens',
3110 => 'Tamron SP AF 300mm f/2.8 LD IF',
3200 => 'Canon EF 24mm f/2.8 or Sigma Lens',
3210 => 'Sigma 15mm f/2.8 EX Fisheye',
3300 => 'Voigtlander or Carl Zeiss Lens',
3310 => 'Voigtlander Ultron 40mm f/2 SLII Aspherical',
3320 => 'Voigtlander Color Skopar 20mm f/3.5 SLII Aspherical',
3330 => 'Voigtlander APO-Lanthar 90mm f/3.5 SLII Close Focus',
3340 => 'Carl Zeiss Distagon T* 15mm f/2.8 ZE',
3350 => 'Carl Zeiss Distagon T* 18mm f/3.5 ZE',
3360 => 'Carl Zeiss Distagon T* 21mm f/2.8 ZE',
3370 => 'Carl Zeiss Distagon T* 25mm f/2 ZE',
3380 => 'Carl Zeiss Distagon T* 28mm f/2 ZE',
3390 => 'Carl Zeiss Distagon T* 35mm f/2 ZE',
3310 => 'Carl Zeiss Distagon T* 35mm f/1.4 ZE',
3311 => 'Carl Zeiss Planar T* 50mm f/1.4 ZE',
3312 => 'Carl Zeiss Makro-Planar T* 50mm f/2 ZE',
3313 => 'Carl Zeiss Makro-Planar T* 100mm f/2 ZE',
3314 => 'Carl Zeiss Apo-Sonnar T* 135mm f/2 ZE',
3500 => 'Canon EF 35-80mm f/4-5.6',
3600 => 'Canon EF 38-76mm f/4.5-5.6',
3700 => 'Canon EF 35-80mm f/4-5.6 or Tamron Lens',
3710 => 'Tamron 70-200mm f/2.8 Di LD IF Macro',
3720 => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20',
3730 => 'Tamron SP AF 17-50mm f/2.8 XR Di II VC LD Aspherical [IF]',
3740 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC LD Aspherical [IF] Macro',
3800 => 'Canon EF 80-200mm f/4.5-5.6',
3900 => 'Canon EF 75-300mm f/4-5.6',
4000 => 'Canon EF 28-80mm f/3.5-5.6',
4100 => 'Canon EF 28-90mm f/4-5.6',
4200 => 'Canon EF 28-200mm f/3.5-5.6 or Tamron Lens',
4210 => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20',
4300 => 'Canon EF 28-105mm f/4-5.6',
4400 => 'Canon EF 90-300mm f/4.5-5.6',
4500 => 'Canon EF-S 18-55mm f/3.5-5.6 [II]',
4600 => 'Canon EF 28-90mm f/4-5.6',
4700 => 'Zeiss Milvus 35mm f/2 or 50mm f/2',
4710 => 'Zeiss Milvus 50mm f/2 Makro',
4800 => 'Canon EF-S 18-55mm f/3.5-5.6 IS',
4900 => 'Canon EF-S 55-250mm f/4-5.6 IS',
5000 => 'Canon EF-S 18-200mm f/3.5-5.6 IS',
5100 => 'Canon EF-S 18-135mm f/3.5-5.6 IS',
5200 => 'Canon EF-S 18-55mm f/3.5-5.6 IS II',
5300 => 'Canon EF-S 18-55mm f/3.5-5.6 III',
5400 => 'Canon EF-S 55-250mm f/4-5.6 IS II',
6000 => 'Irix 11mm f/4',
9400 => 'Canon TS-E 17mm f/4L',
9500 => 'Canon TS-E 24.0mm f/3.5 L II',
12400 => 'Canon MP-E 65mm f/2.8 1-5x Macro Photo',
12500 => 'Canon TS-E 24mm f/3.5L',
12600 => 'Canon TS-E 45mm f/2.8',
12700 => 'Canon TS-E 90mm f/2.8',
12900 => 'Canon EF 300mm f/2.8L',
13000 => 'Canon EF 50mm f/1.0L',
13100 => 'Canon EF 28-80mm f/2.8-4L or Sigma Lens',
13110 => 'Sigma 8mm f/3.5 EX DG Circular Fisheye',
13120 => 'Sigma 17-35mm f/2.8-4 EX DG Aspherical HSM',
13130 => 'Sigma 17-70mm f/2.8-4.5 DC Macro',
13140 => 'Sigma APO 50-150mm f/2.8 [II] EX DC HSM',
13150 => 'Sigma APO 120-300mm f/2.8 EX DG HSM',
13160 => 'Sigma 4.5mm f/2.8 EX DC HSM Circular Fisheye',
13170 => 'Sigma 70-200mm f/2.8 APO EX HSM',
13200 => 'Canon EF 1200mm f/5.6L',
13400 => 'Canon EF 600mm f/4L IS',
13500 => 'Canon EF 200mm f/1.8L',
13600 => 'Canon EF 300mm f/2.8L',
13700 => 'Canon EF 85mm f/1.2L or Sigma or Tamron Lens',
13710 => 'Sigma 18-50mm f/2.8-4.5 DC OS HSM',
13720 => 'Sigma 50-200mm f/4-5.6 DC OS HSM',
13730 => 'Sigma 18-250mm f/3.5-6.3 DC OS HSM',
13740 => 'Sigma 24-70mm f/2.8 IF EX DG HSM',
13750 => 'Sigma 18-125mm f/3.8-5.6 DC OS HSM',
13760 => 'Sigma 17-70mm f/2.8-4 DC Macro OS HSM | C',
13770 => 'Sigma 17-50mm f/2.8 OS HSM',
13780 => 'Sigma 18-200mm f/3.5-6.3 DC OS HSM [II]',
13790 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD',
13710 => 'Sigma 8-16mm f/4.5-5.6 DC HSM',
13711 => 'Tamron SP 17-50mm f/2.8 XR Di II VC',
13712 => 'Tamron SP 60mm f/2 Macro Di II',
13713 => 'Sigma 10-20mm f/3.5 EX DC HSM',
13714 => 'Tamron SP 24-70mm f/2.8 Di VC USD',
13715 => 'Sigma 18-35mm f/1.8 DC HSM',
13716 => 'Sigma 12-24mm f/4.5-5.6 DG HSM II',
13800 => 'Canon EF 28-80mm f/2.8-4L',
13900 => 'Canon EF 400mm f/2.8L',
14000 => 'Canon EF 500mm f/4.5L',
14100 => 'Canon EF 500mm f/4.5L',
14200 => 'Canon EF 300mm f/2.8L IS',
14300 => 'Canon EF 500mm f/4L IS or Sigma Lens',
14310 => 'Sigma 17-70mm f/2.8-4 DC Macro OS HSM',
14400 => 'Canon EF 35-135mm f/4-5.6 USM',
14500 => 'Canon EF 100-300mm f/4.5-5.6 USM',
14600 => 'Canon EF 70-210mm f/3.5-4.5 USM',
14700 => 'Canon EF 35-135mm f/4-5.6 USM',
14800 => 'Canon EF 28-80mm f/3.5-5.6 USM',
14900 => 'Canon EF 100mm f/2 USM',
15000 => 'Canon EF 14mm f/2.8L or Sigma Lens',
15010 => 'Sigma 20mm EX f/1.8',
15020 => 'Sigma 30mm f/1.4 DC HSM',
15030 => 'Sigma 24mm f/1.8 DG Macro EX',
15040 => 'Sigma 28mm f/1.8 DG Macro EX',
15100 => 'Canon EF 200mm f/2.8L',
15200 => 'Canon EF 300mm f/4L IS or Sigma Lens',
15210 => 'Sigma 12-24mm f/4.5-5.6 EX DG ASPHERICAL HSM',
15220 => 'Sigma 14mm f/2.8 EX Aspherical HSM',
15230 => 'Sigma 10-20mm f/4-5.6',
15240 => 'Sigma 100-300mm f/4',
15300 => 'Canon EF 35-350mm f/3.5-5.6L or Sigma or Tamron Lens',
15310 => 'Sigma 50-500mm f/4-6.3 APO HSM EX',
15320 => 'Tamron AF 28-300mm f/3.5-6.3 XR LD Aspherical [IF] Macro',
15330 => 'Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical [IF] Macro Model A14',
15340 => 'Tamron 18-250mm f/3.5-6.3 Di II LD Aspherical [IF] Macro',
15400 => 'Canon EF 20mm f/2.8 USM or Zeiss Lens',
15410 => 'Zeiss Milvus 21mm f/2.8',
15500 => 'Canon EF 85mm f/1.8 USM',
15600 => 'Canon EF 28-105mm f/3.5-4.5 USM or Tamron Lens',
15610 => 'Tamron SP 70-300mm f/4.0-5.6 Di VC USD',
15620 => 'Tamron SP AF 28-105mm f/2.8 LD Aspherical IF',
16000 => 'Canon EF 20-35mm f/3.5-4.5 USM or Tamron or Tokina Lens',
16010 => 'Tamron AF 19-35mm f/3.5-4.5',
16020 => 'Tokina AT-X 124 AF Pro DX 12-24mm f/4',
16030 => 'Tokina AT-X 107 AF DX 10-17mm f/3.5-4.5 Fisheye',
16040 => 'Tokina AT-X 116 AF Pro DX 11-16mm f/2.8',
16050 => 'Tokina AT-X 11-20 F2.8 PRO DX Aspherical 11-20mm f/2.8',
16100 => 'Canon EF 28-70mm f/2.8L or Sigma or Tamron Lens',
16110 => 'Sigma 24-70mm f/2.8 EX',
16120 => 'Sigma 28-70mm f/2.8 EX',
16130 => 'Sigma 24-60mm f/2.8 EX DG',
16140 => 'Tamron AF 17-50mm f/2.8 Di-II LD Aspherical',
16150 => 'Tamron 90mm f/2.8',
16160 => 'Tamron SP AF 17-35mm f/2.8-4 Di LD Aspherical IF',
16170 => 'Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro',
16200 => 'Canon EF 200mm f/2.8L',
16300 => 'Canon EF 300mm f/4L',
16400 => 'Canon EF 400mm f/5.6L',
16500 => 'Canon EF 70-200mm f/2.8 L',
16600 => 'Canon EF 70-200mm f/2.8 L + 1.4x',
16700 => 'Canon EF 70-200mm f/2.8 L + 2x',
16800 => 'Canon EF 28mm f/1.8 USM or Sigma Lens',
16810 => 'Sigma 50-100mm f/1.8 DC HSM | A',
16900 => 'Canon EF 17-35mm f/2.8L or Sigma Lens',
16910 => 'Sigma 18-200mm f/3.5-6.3 DC OS',
16920 => 'Sigma 15-30mm f/3.5-4.5 EX DG Aspherical',
16930 => 'Sigma 18-50mm f/2.8 Macro',
16940 => 'Sigma 50mm f/1.4 EX DG HSM',
16950 => 'Sigma 85mm f/1.4 EX DG HSM',
16960 => 'Sigma 30mm f/1.4 EX DC HSM',
16970 => 'Sigma 35mm f/1.4 DG HSM',
17000 => 'Canon EF 200mm f/2.8L II',
17100 => 'Canon EF 300mm f/4L',
17200 => 'Canon EF 400mm f/5.6L or Sigma Lens',
17210 => 'Sigma 150-600mm f/5-6.3 DG OS HSM | S',
17300 => 'Canon EF 180mm Macro f/3.5L or Sigma Lens',
17310 => 'Sigma 180mm EX HSM Macro f/3.5',
17320 => 'Sigma APO Macro 150mm f/2.8 EX DG HSM',
17400 => 'Canon EF 135mm f/2L or Other Lens',
17410 => 'Sigma 70-200mm f/2.8 EX DG APO OS HSM',
17420 => 'Sigma 50-500mm f/4.5-6.3 APO DG OS HSM',
17430 => 'Sigma 150-500mm f/5-6.3 APO DG OS HSM',
17440 => 'Zeiss Milvus 100mm f/2 Makro',
17500 => 'Canon EF 400mm f/2.8L',
17600 => 'Canon EF 24-85mm f/3.5-4.5 USM',
17700 => 'Canon EF 300mm f/4L IS',
17800 => 'Canon EF 28-135mm f/3.5-5.6 IS',
17900 => 'Canon EF 24mm f/1.4L',
18000 => 'Canon EF 35mm f/1.4L or Other Lens',
18010 => 'Sigma 50mm f/1.4 DG HSM | A',
18020 => 'Sigma 24mm f/1.4 DG HSM | A',
18030 => 'Zeiss Milvus 50mm f/1.4',
18040 => 'Zeiss Milvus 85mm f/1.4',
18050 => 'Zeiss Otus 28mm f/1.4 ZE',
18100 => 'Canon EF 100-400mm f/4.5-5.6L IS + 1.4x or Sigma Lens',
18110 => 'Sigma 150-600mm f/5-6.3 DG OS HSM | S + 1.4x',
18200 => 'Canon EF 100-400mm f/4.5-5.6L IS + 2x or Sigma Lens',
18210 => 'Sigma 150-600mm f/5-6.3 DG OS HSM | S + 2x',
18300 => 'Canon EF 100-400mm f/4.5-5.6L IS or Sigma Lens',
18310 => 'Sigma 150mm f/2.8 EX DG OS HSM APO Macro',
18320 => 'Sigma 105mm f/2.8 EX DG OS HSM Macro',
18330 => 'Sigma 180mm f/2.8 EX DG OS HSM APO Macro',
18340 => 'Sigma 150-600mm f/5-6.3 DG OS HSM | C',
18350 => 'Sigma 150-600mm f/5-6.3 DG OS HSM | S',
18360 => 'Sigma 100-400mm f/5-6.3 DG OS HSM',
18400 => 'Canon EF 400mm f/2.8L + 2x',
18500 => 'Canon EF 600mm f/4L IS',
18600 => 'Canon EF 70-200mm f/4L',
18700 => 'Canon EF 70-200mm f/4L + 1.4x',
18800 => 'Canon EF 70-200mm f/4L + 2x',
18900 => 'Canon EF 70-200mm f/4L + 2.8x',
19000 => 'Canon EF 100mm f/2.8 Macro USM',
19100 => 'Canon EF 400mm f/4 DO IS',
19300 => 'Canon EF 35-80mm f/4-5.6 USM',
19400 => 'Canon EF 80-200mm f/4.5-5.6 USM',
19500 => 'Canon EF 35-105mm f/4.5-5.6 USM',
19600 => 'Canon EF 75-300mm f/4-5.6 USM',
19700 => 'Canon EF 75-300mm f/4-5.6 IS USM or Sigma Lens',
19710 => 'Sigma 18-300mm f/3.5-6.3 DC Macro OS HS',
19800 => 'Canon EF 50mm f/1.4 USM or Zeiss Lens',
19810 => 'Zeiss Otus 55mm f/1.4 ZE',
19820 => 'Zeiss Otus 85mm f/1.4 ZE',
19900 => 'Canon EF 28-80mm f/3.5-5.6 USM',
20000 => 'Canon EF 75-300mm f/4-5.6 USM',
20100 => 'Canon EF 28-80mm f/3.5-5.6 USM',
20200 => 'Canon EF 28-80mm f/3.5-5.6 USM IV',
20800 => 'Canon EF 22-55mm f/4-5.6 USM',
20900 => 'Canon EF 55-200mm f/4.5-5.6',
21000 => 'Canon EF 28-90mm f/4-5.6 USM',
21100 => 'Canon EF 28-200mm f/3.5-5.6 USM',
21200 => 'Canon EF 28-105mm f/4-5.6 USM',
21300 => 'Canon EF 90-300mm f/4.5-5.6 USM or Tamron Lens',
21310 => 'Tamron SP 150-600mm f/5-6.3 Di VC USD',
21320 => 'Tamron 16-300mm f/3.5-6.3 Di II VC PZD Macro',
21330 => 'Tamron SP 35mm f/1.8 Di VC USD',
21340 => 'Tamron SP 45mm f/1.8 Di VC USD',
21400 => 'Canon EF-S 18-55mm f/3.5-5.6 USM',
21500 => 'Canon EF 55-200mm f/4.5-5.6 II USM',
21700 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD',
22400 => 'Canon EF 70-200mm f/2.8L IS',
22500 => 'Canon EF 70-200mm f/2.8L IS + 1.4x',
22600 => 'Canon EF 70-200mm f/2.8L IS + 2x',
22700 => 'Canon EF 70-200mm f/2.8L IS + 2.8x',
22800 => 'Canon EF 28-105mm f/3.5-4.5 USM',
22900 => 'Canon EF 16-35mm f/2.8L',
23000 => 'Canon EF 24-70mm f/2.8L',
23100 => 'Canon EF 17-40mm f/4L',
23200 => 'Canon EF 70-300mm f/4.5-5.6 DO IS USM',
23300 => 'Canon EF 28-300mm f/3.5-5.6L IS',
23400 => 'Canon EF-S 17-85mm f/4-5.6 IS USM or Tokina Lens',
23410 => 'Tokina AT-X 12-28 PRO DX 12-28mm f/4',
23500 => 'Canon EF-S 10-22mm f/3.5-4.5 USM',
23600 => 'Canon EF-S 60mm f/2.8 Macro USM',
23700 => 'Canon EF 24-105mm f/4L IS',
23800 => 'Canon EF 70-300mm f/4-5.6 IS USM',
23900 => 'Canon EF 85mm f/1.2L II',
24000 => 'Canon EF-S 17-55mm f/2.8 IS USM',
24100 => 'Canon EF 50mm f/1.2L',
24200 => 'Canon EF 70-200mm f/4L IS',
24300 => 'Canon EF 70-200mm f/4L IS + 1.4x',
24400 => 'Canon EF 70-200mm f/4L IS + 2x',
24500 => 'Canon EF 70-200mm f/4L IS + 2.8x',
24600 => 'Canon EF 16-35mm f/2.8L II',
24700 => 'Canon EF 14mm f/2.8L II USM',
24800 => 'Canon EF 200mm f/2L IS or Sigma Lens',
24810 => 'Sigma 24-35mm f/2 DG HSM | A',
24900 => 'Canon EF 800mm f/5.6L IS',
25000 => 'Canon EF 24mm f/1.4L II or Sigma Lens',
25010 => 'Sigma 20mm f/1.4 DG HSM | A',
25100 => 'Canon EF 70-200mm f/2.8L IS II USM',
25200 => 'Canon EF 70-200mm f/2.8L IS II USM + 1.4x',
25300 => 'Canon EF 70-200mm f/2.8L IS II USM + 2x',
25400 => 'Canon EF 100mm f/2.8L Macro IS USM',
25500 => 'Sigma 24-105mm f/4 DG OS HSM | A or Other Sigma Lens',
25510 => 'Sigma 180mm f/2.8 EX DG OS HSM APO Macro',
48800 => 'Canon EF-S 15-85mm f/3.5-5.6 IS USM',
48900 => 'Canon EF 70-300mm f/4-5.6L IS USM',
49000 => 'Canon EF 8-15mm f/4L Fisheye USM',
49100 => 'Canon EF 300mm f/2.8L IS II USM or Tamron Lens',
49110 => 'Tamron SP 70-200mm F/2.8 Di VC USD G2 (A025)',
49120 => 'Tamron 18-400mm F/3.5-6.3 Di II VC HLD (B028)',
49200 => 'Canon EF 400mm f/2.8L IS II USM',
49300 => 'Canon EF 500mm f/4L IS II USM or EF 24-105mm f4L IS USM',
49310 => 'Canon EF 24-105mm f/4L IS USM',
49400 => 'Canon EF 600mm f/4.0L IS II USM',
49500 => 'Canon EF 24-70mm f/2.8L II USM or Sigma Lens',
49510 => 'Sigma 24-70mm F2.8 DG OS HSM | A',
49600 => 'Canon EF 200-400mm f/4L IS USM',
49900 => 'Canon EF 200-400mm f/4L IS USM + 1.4x',
50200 => 'Canon EF 28mm f/2.8 IS USM',
50300 => 'Canon EF 24mm f/2.8 IS USM',
50400 => 'Canon EF 24-70mm f/4L IS USM',
50500 => 'Canon EF 35mm f/2 IS USM',
50600 => 'Canon EF 400mm f/4 DO IS II USM',
50700 => 'Canon EF 16-35mm f/4L IS USM',
50800 => 'Canon EF 11-24mm f/4L USM or Tamron Lens',
50810 => 'Tamron 10-24mm f/3.5-4.5 Di II VC HLD',
74700 => 'Canon EF 100-400mm f/4.5-5.6L IS II USM or Tamron Lens',
74710 => 'Tamron SP 150-600mm F5-6.3 Di VC USD G2',
74800 => 'Canon EF 100-400mm f/4.5-5.6L IS II USM + 1.4x',
75000 => 'Canon EF 35mm f/1.4L II USM',
75100 => 'Canon EF 16-35mm f/2.8L III USM',
75200 => 'Canon EF 24-105mm f/4L IS II USM',
414200 => 'Canon EF-S 18-135mm f/3.5-5.6 IS STM',
414300 => 'Canon EF-M 18-55mm f/3.5-5.6 IS STM or Tamron Lens',
414310 => 'Tamron 18-200mm F/3.5-6.3 Di III VC',
414400 => 'Canon EF 40mm f/2.8 STM',
414500 => 'Canon EF-M 22mm f/2 STM',
414600 => 'Canon EF-S 18-55mm f/3.5-5.6 IS STM',
414700 => 'Canon EF-M 11-22mm f/4-5.6 IS STM',
414800 => 'Canon EF-S 55-250mm f/4-5.6 IS STM',
414900 => 'Canon EF-M 55-200mm f/4.5-6.3 IS STM',
415000 => 'Canon EF-S 10-18mm f/4.5-5.6 IS STM',
415200 => 'Canon EF 24-105mm f/3.5-5.6 IS STM',
415300 => 'Canon EF-M 15-45mm f/3.5-6.3 IS STM',
415400 => 'Canon EF-S 24mm f/2.8 STM',
415500 => 'Canon EF-M 28mm f/3.5 Macro IS STM',
415600 => 'Canon EF 50mm f/1.8 STM',
415700 => 'Canon EF-M 18-150mm 1:3.5-6.3 IS STM',
415800 => 'Canon EF-S 18-55mm f/4-5.6 IS STM',
416000 => 'Canon EF-S 35mm f/2.8 Macro IS STM',
3691000 => 'Canon EF 70-300mm f/4-5.6 IS II USM',
3691200 => 'Canon EF-S 18-135mm f/3.5-5.6 IS USM',
6149400 => 'Canon CN-E 85mm T1.3 L F'
],
PelTag::CANON_CS_FOCUS_CONTINUOUS => [
0 => 'Single',
1 => 'Continuous',
8 => 'Manual'
],
PelTag::CANON_CS_AE_SETTING => [
0 => 'Normal AE',
1 => 'Exposure Compensation',
2 => 'AE Lock',
3 => 'AE Lock + Exposure Comp.',
4 => 'No AE'
],
PelTag::CANON_CS_IMAGE_STABILIZATION => [
0 => 'Off',
1 => 'On',
2 => 'Shoot Only',
3 => 'Panning',
4 => 'Dynamic',
256 => 'Off (2)',
257 => 'On (2)',
258 => 'Shoot Only (2)',
259 => 'Panning (2)',
260 => 'Dynamic (2)'
],
PelTag::CANON_CS_SPOT_METERING_MODE => [
0 => 'Center',
1 => 'AF Point'
],
PelTag::CANON_CS_PHOTO_EFFECT => [
0 => 'Off',
1 => 'Vivid',
2 => 'Neutral',
3 => 'Smooth',
4 => 'Sepia',
5 => 'B&W',
6 => 'Custom',
100 => 'My Color Data'
],
PelTag::CANON_CS_MANUAL_FLASH_OUTPUT => [
0x500 => 'Full',
0x502 => 'Medium',
0x504 => 'Low'
],
PelTag::CANON_CS_COLOR_TONE => [
0 => 'Normal'
],
PelTag::CANON_CS_SRAW_QUALITY => [
1 => 'sRAW1 (mRAW)',
2 => 'sRAW2 (sRAW)'
]
]
];
/**
* Make a new entry that can hold a signed short.
*
* The method accept several integer arguments. The {@link
* getValue} method will always return an array except for when a
* single integer argument is given here.
*
* @param int $tag
* the tag which this entry represents. This
* should be one of the constants defined in {@link PelTag}
* which has format {@link PelFormat::SSHORT}.
* @param int $value...
* the signed short(s) that this entry will
* represent. The argument passed must obey the same rules as the
* argument to {@link setValue}, namely that it should be within
* range of a signed short, that is between -32768 to 32767
* (inclusive). If not, then a {@link PelOverFlowException} will be
* thrown.
*/
public function __construct($tag, $value = null)
{
$this->tag = $tag;
$this->min = - 32768;
$this->max = 32767;
$this->format = PelFormat::SSHORT;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param int $number
* the number that should be converted.
* @param boolean $order
* one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
* @return string bytes representing the number given.
*/
public function numberToBytes($number, $order)
{
return PelConvert::sShortToBytes($number, $order);
}
/**
* Get the value of an entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., instead of returning '2' for a {@link
* PelTag::METERING_MODE} tag, 'Center-Weighted Average' is
* returned.
*
* @param boolean $brief
* some values can be returned in a long or more
* brief form, and this parameter controls that.
* @return string the value as text.
*/
public function getText($brief = false)
{
if (array_key_exists($this->ifd_type, self::TRANSLATIONS) && array_key_exists($this->tag, self::TRANSLATIONS[$this->ifd_type])) {
$val = $this->value[0];
if ($this->ifd_type === PelIfd::CANON_CAMERA_SETTINGS && $this->tag === PelTag::CANON_CS_LENS_TYPE) {
// special handling: lens types must be multtiplied by 100 because digits canÄt be used in arrays
$val = $val * 100;
}
if (array_key_exists($val, self::TRANSLATIONS[$this->ifd_type][$this->tag])) {
return Pel::tra(self::TRANSLATIONS[$this->ifd_type][$this->tag][$val]);
} else {
return $val;
}
}
return parent::getText($brief);
}
}

View File

@ -0,0 +1,409 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to hold shorts, both signed and unsigned.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding signed shorts.
*
* This class can hold shorts, either just a single short or an array
* of shorts. The class will be used to manipulate any of the Exif
* tags which has format {@link PelFormat::SHORT} like in this
* example:
*
* <code>
* $w = $ifd->getEntry(PelTag::EXIF_IMAGE_WIDTH);
* $w->setValue($w->getValue() / 2);
* $h = $ifd->getEntry(PelTag::EXIF_IMAGE_HEIGHT);
* $h->setValue($h->getValue() / 2);
* </code>
*
* Here the width and height is updated to 50% of their original
* values.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryShort extends PelEntryNumber
{
private const IFD_TYPE_TRANSLATIONS = [
PelIfd::CANON_SHOT_INFO => [
PelTag::CANON_SI_WHITE_BALANCE => [
0 => 'Auto',
1 => 'Daylight',
2 => 'Cloudy',
3 => 'Tungsten',
4 => 'Fluorescent',
5 => 'Flash',
6 => 'Custom',
7 => 'Black & White',
8 => 'Shade',
9 => 'Manual Temperature (Kelvin)',
10 => 'PC Set1',
11 => 'PC Set2',
12 => 'PC Set3',
14 => 'Daylight Fluorescent',
15 => 'Custom 1',
16 => 'Custom 2',
17 => 'Underwater',
18 => 'Custom 3',
19 => 'Custom 4',
20 => 'PC Set4',
21 => 'PC Set5',
23 => 'Auto (ambience priority)'
],
PelTag::CANON_SI_SLOW_SHUTTER => [
0 => 'Off',
1 => 'Night Scene',
2 => 'On',
3 => 'None'
],
PelTag::CANON_SI_AF_POINT_USED => [
0x3000 => 'None (MF)',
0x3001 => 'Right',
0x3002 => 'Center',
0x3003 => 'Center+Right',
0x3004 => 'Left',
0x3005 => 'Left+Right',
0x3006 => 'Left+Center',
0x3007 => 'All'
],
PelTag::CANON_SI_AUTO_EXPOSURE_BRACKETING => [
- 1 => 'On',
0 => 'Off',
1 => 'On (shot 1)',
2 => 'On (shot 2)',
3 => 'On (shot 3)'
],
PelTag::CANON_SI_CAMERA_TYPE => [
248 => 'EOS High-end',
250 => 'Compact',
252 => 'EOS Mid-range',
255 => 'DV Camera'
],
PelTag::CANON_SI_AUTO_ROTATE => [
0 => 'None',
1 => 'Rotate 90 CW',
2 => 'Rotate 180',
3 => 'Rotate 270 CW'
],
PelTag::CANON_SI_ND_FILTER => [
0 => 'Off',
1 => 'On'
]
],
PelIfd::CANON_PANORAMA => [
PelTag::CANON_PA_PANORAMA_DIRECTION => [
0 => 'Left to Right',
1 => 'Right to Left',
2 => 'Bottom to Top',
3 => 'Top to Bottom',
4 => '2x2 Matrix (Clockwise)'
]
]
];
private const PEL_TAG_TRANSLATIONS = [
PelTag::METERING_MODE => [
0 => 'Unknown',
1 => 'Average',
2 => 'Center-Weighted Average',
3 => 'Spot',
4 => 'Multi Spot',
5 => 'Pattern',
6 => 'Partial',
255 => 'Other'
],
PelTag::COMPRESSION => [
1 => 'Uncompressed',
6 => 'JPEG compression'
],
PelTag::PLANAR_CONFIGURATION => [
1 => 'chunky format',
2 => 'planar format'
],
PelTag::SENSING_METHOD => [
1 => 'Not defined',
2 => 'One-chip color area sensor',
3 => 'Two-chip color area sensor',
4 => 'Three-chip color area sensor',
5 => 'Color sequential area sensor',
7 => 'Trilinear sensor',
8 => 'Color sequential linear sensor'
],
PelTag::LIGHT_SOURCE => [
0 => 'Unknown',
1 => 'Daylight',
2 => 'Fluorescent',
3 => 'Tungsten (incandescent light)',
4 => 'Flash',
9 => 'Fine weather',
10 => 'Cloudy weather',
11 => 'Shade',
12 => 'Daylight fluorescent',
13 => 'Day white fluorescent',
14 => 'Cool white fluorescent',
15 => 'White fluorescent',
17 => 'Standard light A',
18 => 'Standard light B',
19 => 'Standard light C',
20 => 'D55',
21 => 'D65',
22 => 'D75',
24 => 'ISO studio tungsten',
255 => 'Other'
],
PelTag::FOCAL_PLANE_RESOLUTION_UNIT => [
2 => 'Inch',
3 => 'Centimeter'
],
PelTag::RESOLUTION_UNIT => [
2 => 'Inch',
3 => 'Centimeter'
],
PelTag::EXPOSURE_PROGRAM => [
0 => 'Not defined',
1 => 'Manual',
2 => 'Normal program',
3 => 'Aperture priority',
4 => 'Shutter priority',
5 => 'Creative program (biased toward depth of field)',
6 => 'Action program (biased toward fast shutter speed)',
7 => 'Portrait mode (for closeup photos with the background out of focus',
8 => 'Landscape mode (for landscape photos with the background in focus'
],
PelTag::ORIENTATION => [
1 => 'top - left',
2 => 'top - right',
3 => 'bottom - right',
4 => 'bottom - left',
5 => 'left - top',
6 => 'right - top',
7 => 'right - bottom',
8 => 'left - bottom'
],
PelTag::YCBCR_POSITIONING => [
1 => 'centered',
2 => 'co-sited'
],
PelTag::PHOTOMETRIC_INTERPRETATION => [
2 => 'RGB',
6 => 'YCbCr'
],
PelTag::COLOR_SPACE => [
1 => 'sRGB',
2 => 'Adobe RGB',
0xffff => 'Uncalibrated'
],
PelTag::FLASH => [
0x0000 => 'Flash did not fire.',
0x0001 => 'Flash fired.',
0x0005 => 'Strobe return light not detected.',
0x0007 => 'Strobe return light detected.',
0x0009 => 'Flash fired, compulsory flash mode.',
0x000d => 'Flash fired, compulsory flash mode, return light not detected.',
0x000f => 'Flash fired, compulsory flash mode, return light detected.',
0x0010 => 'Flash did not fire, compulsory flash mode.',
0x0018 => 'Flash did not fire, auto mode.',
0x0019 => 'Flash fired, auto mode.',
0x001d => 'Flash fired, auto mode, return light not detected.',
0x001f => 'Flash fired, auto mode, return light detected.',
0x0020 => 'No flash function.',
0x0041 => 'Flash fired, red-eye reduction mode.',
0x0045 => 'Flash fired, red-eye reduction mode, return light not detected.',
0x0047 => 'Flash fired, red-eye reduction mode, return light detected.',
0x0049 => 'Flash fired, compulsory flash mode, red-eye reduction mode.',
0x004d => 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected.',
0x004f => 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected.',
0x0058 => 'Flash did not fire, auto mode, red-eye reduction mode.',
0x0059 => 'Flash fired, auto mode, red-eye reduction mode.',
0x005d => 'Flash fired, auto mode, return light not detected, red-eye reduction mode.',
0x005f => 'Flash fired, auto mode, return light detected, red-eye reduction mode.'
],
PelTag::CUSTOM_RENDERED => [
0 => 'Normal process',
1 => 'Custom process'
],
PelTag::EXPOSURE_MODE => [
0 => 'Auto exposure',
1 => 'Manual exposure',
2 => 'Auto bracket'
],
PelTag::WHITE_BALANCE => [
0 => 'Auto white balance',
1 => 'Manual white balance'
],
PelTag::SCENE_CAPTURE_TYPE => [
0 => 'Standard',
1 => 'Landscape',
2 => 'Portrait',
3 => 'Night scene'
],
PelTag::GAIN_CONTROL => [
0 => 'Normal',
1 => 'Low gain up',
2 => 'High gain up',
3 => 'Low gain down',
4 => 'High gain down'
],
PelTag::SATURATION => [
0 => 'Normal',
1 => 'Low saturation',
2 => 'High saturation'
],
PelTag::CONTRAST => [
0 => 'Normal',
1 => 'Soft',
2 => 'Hard'
],
PelTag::SHARPNESS => [
0 => 'Normal',
1 => 'Soft',
2 => 'Hard'
],
PelTag::SUBJECT_DISTANCE_RANGE => [
0 => 'Unknown',
1 => 'Macro',
2 => 'Close view',
3 => 'Distant view'
]
];
/**
* Make a new entry that can hold an unsigned short.
*
* The method accept several integer arguments. The {@link
* getValue} method will always return an array except for when a
* single integer argument is given here.
*
* This means that one can conveniently use objects like this:
* <code>
* $a = new PelEntryShort(PelTag::EXIF_IMAGE_HEIGHT, 42);
* $b = $a->getValue() + 314;
* </code>
* where the call to {@link getValue} will return an integer
* instead of an array with one integer element, which would then
* have to be extracted.
*
* @param integer $tag
* the tag which this entry represents. This should be
* one of the constants defined in {@link PelTag}, e.g., {@link
* PelTag::IMAGE_WIDTH}, {@link PelTag::ISO_SPEED_RATINGS},
* or any other tag with format {@link PelFormat::SHORT}.
* @param integer $value...
* the short(s) that this entry will
* represent. The argument passed must obey the same rules as the
* argument to {@link setValue}, namely that it should be within
* range of an unsigned short, that is between 0 and 65535
* (inclusive). If not, then a {@link PelOverFlowException} will be
* thrown.
*/
public function __construct($tag, $value = null)
{
$this->tag = $tag;
$this->min = 0;
$this->max = 65535;
$this->format = PelFormat::SHORT;
$value = func_get_args();
array_shift($value);
$this->setValueArray($value);
}
/**
* Convert a number into bytes.
*
* @param integer $number
* the number that should be converted.
* @param boolean $order
* one of {@link PelConvert::LITTLE_ENDIAN} and
* {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
* @return string bytes representing the number given.
*/
public function numberToBytes($number, $order)
{
return PelConvert::shortToBytes($number, $order);
}
/**
* Get the value of an entry as text.
*
* The value will be returned in a format suitable for presentation,
* e.g., instead of returning '2' for a {@link
* PelTag::METERING_MODE} tag, 'Center-Weighted Average' is
* returned.
*
* @param boolean $brief
* some values can be returned in a long or more
* brief form, and this parameter controls that.
* @return string the value as text.
*/
public function getText($brief = false)
{
if (array_key_exists($this->ifd_type, self::IFD_TYPE_TRANSLATIONS)) {
if (array_key_exists($this->value[0], self::IFD_TYPE_TRANSLATIONS[$this->ifd_type])) {
return Pel::tra(self::IFD_TYPE_TRANSLATIONS[$this->ifd_type][$this->value[0]]);
} else {
return $this->value[0];
}
} elseif ($this->tag === PelTag::YCBCR_SUB_SAMPLING) {
if ($this->value[0] == 2 && $this->value[1] == 1) {
return 'YCbCr4:2:2';
}
if ($this->value[0] == 2 && $this->value[1] == 2) {
return 'YCbCr4:2:0';
}
return $this->value[0] . ', ' . $this->value[1];
} elseif ($this->tag === PelTag::SUBJECT_AREA) {
switch ($this->components) {
case 2:
return Pel::fmt('(x,y) = (%d,%d)', $this->value[0], $this->value[1]);
case 3:
return Pel::fmt('Within distance %d of (x,y) = (%d,%d)', $this->value[0], $this->value[1], $this->value[2]);
case 4:
return Pel::fmt('Within rectangle (width %d, height %d) around (x,y) = (%d,%d)', $this->value[0], $this->value[1], $this->value[2], $this->value[3]);
default:
return Pel::fmt('Unexpected number of components (%d, expected 2, 3, or 4).', $this->components);
}
} elseif (array_key_exists($this->tag, self::PEL_TAG_TRANSLATIONS)) {
if (array_key_exists($this->value[0], self::PEL_TAG_TRANSLATIONS[$this->tag])) {
return Pel::tra(self::PEL_TAG_TRANSLATIONS[$this->tag][$this->value[0]]);
} else {
return $this->value[0];
}
}
return parent::getText($brief);
}
}

View File

@ -0,0 +1,319 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class for holding a date and time.
*
* This class can hold a timestamp, and it will be used as
* in this example where the time is advanced by one week:
* <code>
* $entry = $ifd->getEntry(PelTag::DATE_TIME_ORIGINAL);
* $time = $entry->getValue();
* print('The image was taken on the ' . date('jS', $time));
* $entry->setValue($time + 7 * 24 * 3600);
* </code>
*
* The example used a standard UNIX timestamp, which is the default
* for this class.
*
* But the Exif format defines dates outside the range of a UNIX
* timestamp (about 1970 to 2038) and so you can also get access to
* the timestamp in two other formats: a simple string or a Julian Day
* Count. Please see the Calendar extension in the PHP Manual for more
* information about the Julian Day Count.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryTime extends PelEntryAscii
{
/**
* Constant denoting a UNIX timestamp.
*/
const UNIX_TIMESTAMP = 1;
/**
* Constant denoting a Exif string.
*/
const EXIF_STRING = 2;
/**
* Constant denoting a Julian Day Count.
*/
const JULIAN_DAY_COUNT = 3;
/**
* The Julian Day Count of the timestamp held by this entry.
*
* This is an integer counting the number of whole days since
* January 1st, 4713 B.C. The fractional part of the timestamp held
* by this entry is stored in {@link $seconds}.
*
* @var int
*/
private $day_count;
/**
* The number of seconds into the day of the timestamp held by this
* entry.
*
* The number of whole days is stored in {@link $day_count} and the
* number of seconds left-over is stored here.
*
* @var int
*/
private $seconds;
/**
* Make a new entry for holding a timestamp.
*
* @param integer $tag
* the Exif tag which this entry represents. There are
* only three standard tags which hold timestamp, so this should be
* one of the constants {@link PelTag::DATE_TIME}, {@link
* PelTag::DATE_TIME_ORIGINAL}, or {@link
* PelTag::DATE_TIME_DIGITIZED}.
* @param integer|string|double $timestamp
* the timestamp held by this entry in the correct form
* as indicated by the third argument. For {@link UNIX_TIMESTAMP}
* this is an integer counting the number of seconds since January
* 1st 1970, for {@link EXIF_STRING} this is a string of the form
* 'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
* floating point number where the integer part denotes the day
* count and the fractional part denotes the time of day (0.25 means
* 6:00, 0.75 means 18:00).
* @param integer $type
* the type of the timestamp. This must be one of
* {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
* {@link JULIAN_DAY_COUNT}.
*/
public function __construct($tag, $timestamp, $type = self::UNIX_TIMESTAMP)
{
$this->tag = $tag;
$this->format = PelFormat::ASCII;
$this->setValue($timestamp, $type);
}
/**
* Return the timestamp of the entry.
*
* The timestamp held by this entry is returned in one of three
* formats: as a standard UNIX timestamp (default), as a fractional
* Julian Day Count, or as a string.
*
* @param integer $type
* the type of the timestamp. This must be one of
* {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
* {@link JULIAN_DAY_COUNT}.
* @return integer|string|false the timestamp held by this entry in the correct form
* as indicated by the type argument. For {@link UNIX_TIMESTAMP}
* this is an integer counting the number of seconds since January
* 1st 1970, for {@link EXIF_STRING} this is a string of the form
* 'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
* floating point number where the integer part denotes the day
* count and the fractional part denotes the time of day (0.25 means
* 6:00, 0.75 means 18:00).
*/
public function getValue($type = self::UNIX_TIMESTAMP)
{
switch ($type) {
case self::UNIX_TIMESTAMP:
$seconds = $this->convertJdToUnix($this->day_count);
if ($seconds === false) {
/*
* We get false if the Julian Day Count is outside the range
* of a UNIX timestamp.
*/
return false;
} else {
return $seconds + $this->seconds;
}
break;
case self::EXIF_STRING:
list ($year, $month, $day) = $this->convertJdToGregorian($this->day_count);
$hours = (int) ($this->seconds / 3600);
$minutes = (int) ($this->seconds % 3600 / 60);
$seconds = $this->seconds % 60;
return sprintf('%04d:%02d:%02d %02d:%02d:%02d', $year, $month, $day, $hours, $minutes, $seconds);
case self::JULIAN_DAY_COUNT:
return $this->day_count + $this->seconds / 86400;
default:
throw new PelInvalidArgumentException('Expected UNIX_TIMESTAMP (%d), ' . 'EXIF_STRING (%d), or ' . 'JULIAN_DAY_COUNT (%d) for $type, got %d.', self::UNIX_TIMESTAMP, self::EXIF_STRING, self::JULIAN_DAY_COUNT, $type);
}
}
/**
* Update the timestamp held by this entry.
*
* @param integer|float|string $timestamp
* the timestamp held by this entry in the correct form
* as indicated by the third argument. For {@link UNIX_TIMESTAMP}
* this is an integer counting the number of seconds since January
* 1st 1970, for {@link EXIF_STRING} this is a string of the form
* 'YYYY:MM:DD hh:mm:ss', and for {@link JULIAN_DAY_COUNT} this is a
* floating point number where the integer part denotes the day
* count and the fractional part denotes the time of day (0.25 means
* 6:00, 0.75 means 18:00).
* @param integer $type
* the type of the timestamp. This must be one of
* {@link UNIX_TIMESTAMP}, {@link EXIF_STRING}, or
* {@link JULIAN_DAY_COUNT}.
* @throws PelInvalidArgumentException
*/
public function setValue($timestamp, $type = self::UNIX_TIMESTAMP)
{
if ($type === self::UNIX_TIMESTAMP) {
if (is_int($timestamp) || is_float($timestamp)) {
$this->day_count = $this->convertUnixToJd($timestamp);
$this->seconds = $timestamp % 86400;
} else {
throw new PelInvalidArgumentException('Expected integer value for $type, got %s', gettype($timestamp));
}
} elseif ($type === self::EXIF_STRING) {
/*
* Clean the timestamp: some timestamps are broken other
* separators than ':' and ' '.
*/
$d = preg_split('/[^0-9]+/', $timestamp);
for ($i = 0; $i < 6; $i ++) {
if (empty($d[$i])) {
$d[$i] = 0;
}
}
$this->day_count = $this->convertGregorianToJd($d[0], $d[1], $d[2]);
$this->seconds = $d[3] * 3600 + $d[4] * 60 + $d[5];
} elseif ($type === self::JULIAN_DAY_COUNT) {
if (is_int($timestamp) || is_float($timestamp)) {
$this->day_count = (int) floor($timestamp);
$this->seconds = (int) (86400 * ($timestamp - floor($timestamp)));
} else {
throw new PelInvalidArgumentException('Expected integer value for $type, got %s', gettype($timestamp));
}
} else {
throw new PelInvalidArgumentException('Expected UNIX_TIMESTAMP (%d), ' . 'EXIF_STRING (%d), or ' . 'JULIAN_DAY_COUNT (%d) for $type, got %d.', self::UNIX_TIMESTAMP, self::EXIF_STRING, self::JULIAN_DAY_COUNT, $type);
}
// finally update the string which will be used when this is turned into bytes.
parent::setValue($this->getValue(self::EXIF_STRING));
}
// The following four functions are used for converting back and
// forth between the date formats. They are used in preference to
// the ones from the PHP calendar extension to avoid having to
// fiddle with timezones and to avoid depending on the extension.
//
// See http://www.hermetic.ch/cal_stud/jdn.htm#comp for a reference.
/**
* Converts a date in year/month/day format to a Julian Day count.
*
* @param integer $year
* the year.
* @param integer $month
* the month, 1 to 12.
* @param integer $day
* the day in the month.
* @return integer the Julian Day count.
*/
public function convertGregorianToJd($year, $month, $day)
{
// Special case mapping 0/0/0 -> 0
if ($year == 0 || $month == 0 || $day == 0) {
return 0;
}
$m1412 = ($month <= 2) ? - 1 : 0;
return floor((1461 * ($year + 4800 + $m1412)) / 4) + floor((367 * ($month - 2 - 12 * $m1412)) / 12) - floor((3 * floor(($year + 4900 + $m1412) / 100)) / 4) + $day - 32075;
}
/**
* Converts a Julian Day count to a year/month/day triple.
*
* @param int $jd
* the Julian Day count.
* @return array an array with three entries: year, month, day.
*/
public function convertJdToGregorian($jd)
{
// Special case mapping 0 -> 0/0/0
if ($jd == 0) {
return [
0,
0,
0
];
}
$l = $jd + 68569;
$n = floor((4 * $l) / 146097);
$l = $l - floor((146097 * $n + 3) / 4);
$i = floor((4000 * ($l + 1)) / 1461001);
$l = $l - floor((1461 * $i) / 4) + 31;
$j = floor((80 * $l) / 2447);
$d = $l - floor((2447 * $j) / 80);
$l = floor($j / 11);
$m = $j + 2 - (12 * $l);
$y = 100 * ($n - 49) + $i + $l;
return [
$y,
$m,
$d
];
}
/**
* Converts a UNIX timestamp to a Julian Day count.
*
* @param integer|float $timestamp
* the timestamp.
* @return float the Julian Day count.
*/
public function convertUnixToJd($timestamp)
{
return floor($timestamp / 86400) + 2440588;
}
/**
* Converts a Julian Day count to a UNIX timestamp.
*
* @param integer|float $jd
* the Julian Day count.
* @return mixed $timestamp the integer timestamp or false if the
* day count cannot be represented as a UNIX timestamp.
*/
public function convertJdToUnix($jd)
{
if ($jd > 0) {
$timestamp = ($jd - 2440588) * 86400;
if ($timestamp >= 0) {
return $timestamp;
}
}
return false;
}
}

View File

@ -0,0 +1,172 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes used to hold data for Exif tags of format undefined.
*
* This file contains the base class {@link PelEntryUndefined} and
* the subclasses {@link PelEntryUserComment} which should be used
* to manage the {@link PelTag::USER_COMMENT} tag, and {@link
* PelEntryVersion} which is used to manage entries with version
* information.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for holding data of any kind.
*
* This class can hold bytes of undefined format.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryUndefined extends PelEntry
{
/**
* Make a new PelEntry that can hold undefined data.
*
* @param integer $tag
* which this entry represents. This
* should be one of the constants defined in {@link PelTag},
* e.g., {@link PelTag::SCENE_TYPE}, {@link
* PelTag::MAKER_NOTE} or any other tag with format {@link
* PelFormat::UNDEFINED}.
* @param string $data
* the data that this entry will be holding. Since
* the format is undefined, no checking will be done on the data. If no data are given, a empty string will be stored
*/
public function __construct($tag, $data = '')
{
$this->tag = $tag;
$this->format = PelFormat::UNDEFINED;
$this->setValue($data);
}
/**
* Set the data of this undefined entry.
*
* @param string $data
* the data that this entry will be holding. Since
* the format is undefined, no checking will be done on the data.
*/
public function setValue($data)
{
$this->components = strlen($data);
$this->bytes = $data;
}
/**
* Get the data of this undefined entry.
*
* @return string the data that this entry is holding.
*/
public function getValue()
{
return $this->bytes;
}
/**
* Get the value of this entry as text.
*
* The value will be returned in a format suitable for presentation.
*
* @param boolean $brief
* some values can be returned in a long or more
* brief form, and this parameter controls that.
* @return string the value as text.
*/
public function getText($brief = false)
{
switch ($this->tag) {
case PelTag::FILE_SOURCE:
// CC (e->components, 1, v);
switch (ord($this->bytes[0])) {
case 0x03:
return 'DSC';
default:
return sprintf('0x%02X', ord($this->bytes[0]));
}
break;
case PelTag::SCENE_TYPE:
// CC (e->components, 1, v);
switch (ord($this->bytes[0])) {
case 0x01:
return 'Directly photographed';
default:
return sprintf('0x%02X', ord($this->bytes[0]));
}
break;
case PelTag::COMPONENTS_CONFIGURATION:
// CC (e->components, 4, v);
$v = '';
for ($i = 0; $i < 4; $i ++) {
switch (ord($this->bytes[$i])) {
case 0:
$v .= '-';
break;
case 1:
$v .= 'Y';
break;
case 2:
$v .= 'Cb';
break;
case 3:
$v .= 'Cr';
break;
case 4:
$v .= 'R';
break;
case 5:
$v .= 'G';
break;
case 6:
$v .= 'B';
break;
default:
$v .= 'reserved';
break;
}
if ($i < 3) {
$v .= ' ';
}
}
return $v;
break;
case PelTag::MAKER_NOTE:
// TODO: handle maker notes.
return $this->components . ' bytes unknown MakerNote data';
break;
default:
return '(undefined)';
}
}
}

View File

@ -0,0 +1,140 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class for a user comment.
*
* This class is used to hold user comments, which can come in several
* different character encodings. The Exif standard specifies a
* certain format of the {@link PelTag::USER_COMMENT user comment
* tag}, and this class will make sure that the format is kept.
*
* The most basic use of this class simply stores an ASCII encoded
* string for later retrieval using {@link getValue}:
*
* <code>
* $entry = new PelEntryUserComment('An ASCII string');
* echo $entry->getValue();
* </code>
*
* The string can be encoded with a different encoding, and if so, the
* encoding must be given using the second argument. The Exif
* standard specifies three known encodings: 'ASCII', 'JIS', and
* 'Unicode'. If the user comment is encoded using a character
* encoding different from the tree known encodings, then the empty
* string should be passed as encoding, thereby specifying that the
* encoding is undefined.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryUserComment extends PelEntryUndefined
{
/**
* The user comment.
*
* @var string
*/
private $comment;
/**
* The encoding.
*
* This should be one of 'ASCII', 'JIS', 'Unicode', or ''.
*
* @var string
*/
private $encoding;
/**
* Make a new entry for holding a user comment.
*
* @param string $comment
* the new user comment.
* @param string $encoding
* the encoding of the comment. This should be either
* 'ASCII', 'JIS', 'Unicode', or the empty string specifying an
* undefined encoding.
*/
public function __construct($comment = '', $encoding = 'ASCII')
{
parent::__construct(PelTag::USER_COMMENT);
$this->setValue($comment, $encoding);
}
/**
* Set the user comment.
*
* @param string $comment
* the new user comment.
* @param string $encoding
* the encoding of the comment. This should be either
* 'ASCII', 'JIS', 'Unicode', or the empty string specifying an
* unknown encoding.
*/
public function setValue($comment = '', $encoding = 'ASCII')
{
$this->comment = $comment;
$this->encoding = $encoding;
parent::setValue(str_pad($encoding, 8, chr(0)) . $comment);
}
/**
* Returns the user comment.
*
* The comment is returned with the same character encoding as when
* it was set using {@link setValue} or {@link __construct the
* constructor}.
*
* @return string the user comment.
*/
public function getValue()
{
return $this->comment;
}
/**
* Returns the encoding.
*
* @return string the encoding of the user comment.
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Returns the user comment.
*
* @return string the user comment.
*/
public function getText($brief = false)
{
return $this->comment;
}
}

View File

@ -0,0 +1,166 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class to hold version information.
*
* There are three Exif entries that hold version information: the
* {@link PelTag::EXIF_VERSION}, {@link
* PelTag::FLASH_PIX_VERSION}, and {@link
* PelTag::INTEROPERABILITY_VERSION} tags. This class manages
* those tags.
*
* The class is used in a very straight-forward way:
* <code>
* $entry = new PelEntryVersion(PelTag::EXIF_VERSION, 2.2);
* </code>
* This creates an entry for an file complying to the Exif 2.2
* standard. It is easy to test for standards level of an unknown
* entry:
* <code>
* if ($entry->getTag() == PelTag::EXIF_VERSION &&
* $entry->getValue() > 2.0) {
* echo 'Recent Exif version.';
* }
* </code>
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryVersion extends PelEntry
{
/**
* The version held by this entry.
*
* @var float
*/
private $version;
/**
* Make a new entry for holding a version.
*
* @param integer $tag
* This should be one of {@link
* PelTag::EXIF_VERSION}, {@link PelTag::FLASH_PIX_VERSION},
* or {@link PelTag::INTEROPERABILITY_VERSION}.
* @param float $version
* The size of the entries leave room for
* exactly four digits: two digits on either side of the decimal
* point.
*/
public function __construct($tag, $version = 0.0)
{
$this->tag = $tag;
$this->format = PelFormat::UNDEFINED;
$this->setValue($version);
}
/**
* Set the version held by this entry.
*
* @param float $version
* The size of the entries leave room for
* exactly four digits: two digits on either side of the decimal
* point.
*/
public function setValue($version = 0.0)
{
$this->version = $version;
$major = floor($version);
$minor = ($version - $major) * 100;
$strValue = sprintf('%02.0f%02.0f', $major, $minor);
$this->components = strlen($strValue);
$this->bytes = $strValue;
}
/**
* Return the version held by this entry.
*
* @return float This will be the same as the value
* given to {@link setValue} or {@link __construct the
* constructor}.
*/
public function getValue()
{
return $this->version;
}
/**
* Return a text string with the version.
*
* @param boolean $brief
* controls if the output should be brief. Brief
* output omits the word 'Version' so the result is just 'Exif x.y'
* instead of 'Exif Version x.y' if the entry holds information
* about the Exif version --- the output for FlashPix is similar.
* @return string the version number with the type of the tag,
* either 'Exif' or 'FlashPix'.
*/
public function getText($brief = false)
{
$v = $this->version;
/*
* Versions numbers like 2.0 would be output as just 2 if we don't
* add the '.0' ourselves.
*/
if (floor($this->version) == $this->version) {
$v .= '.0';
}
switch ($this->tag) {
case PelTag::EXIF_VERSION:
if ($brief) {
return Pel::fmt('Exif %s', $v);
} else {
return Pel::fmt('Exif Version %s', $v);
}
break;
case PelTag::FLASH_PIX_VERSION:
if ($brief) {
return Pel::fmt('FlashPix %s', $v);
} else {
return Pel::fmt('FlashPix Version %s', $v);
}
break;
case PelTag::INTEROPERABILITY_VERSION:
if ($brief) {
return Pel::fmt('Interoperability %s', $v);
} else {
return Pel::fmt('Interoperability Version %s', $v);
}
break;
}
if ($brief) {
return $v;
} else {
return Pel::fmt('Version %s', $v);
}
}
}

View File

@ -0,0 +1,162 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class used to manipulate strings in the format Windows XP uses.
*
* When examining the file properties of an image in Windows XP one
* can fill in title, comment, author, keyword, and subject fields.
* Filling those fields and pressing OK will result in the data being
* written into the Exif data in the image.
*
* The data is written in a non-standard format and can thus not be
* loaded directly --- this class is needed to translate it into
* normal strings.
*
* It is important that entries from this class are only created with
* the {@link PelTag::XP_TITLE}, {@link PelTag::XP_COMMENT}, {@link
* PelTag::XP_AUTHOR}, {@link PelTag::XP_KEYWORD}, and {@link
* PelTag::XP_SUBJECT} tags. If another tag is used the data will no
* longer be correctly decoded when reloaded with PEL. (The data will
* be loaded as an {@link PelEntryByte} entry, which isn't as useful.)
*
* This class is to be used as in
* <code>
* $title = $ifd->getEntry(PelTag::XP_TITLE);
* print($title->getValue());
* $title->setValue('My favorite cat');
* </code>
* or if no entry is present one can add a new one with
* <code>
* $title = new PelEntryWindowsString(PelTag::XP_TITLE, 'A cute dog.');
* $ifd->addEntry($title);
* </code>
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelEntryWindowsString extends PelEntry
{
const ZEROES = "\x0\x0";
/**
* The string hold by this entry.
*
* This is the string that was given to the {@link __construct
* constructor} or later to {@link setValue}, without any extra NULL
* characters or any such nonsense.
*
* @var string
*/
private $str;
/**
* Make a new PelEntry that can hold a Windows XP specific string.
*
* @param int $tag
* the tag which this entry represents. This should be
* one of {@link PelTag::XP_TITLE}, {@link PelTag::XP_COMMENT},
* {@link PelTag::XP_AUTHOR}, {@link PelTag::XP_KEYWORD}, and {@link
* PelTag::XP_SUBJECT} tags. If another tag is used, then this
* entry will be incorrectly reloaded as a {@link PelEntryByte}.
* @param string $str
* the string that this entry will represent. It will
* be passed to {@link setValue} and thus has to obey its
* requirements.
* @param bool $from_exif
* internal use only, tells that string is UCS-2LE encoded, as PHP fails to detect this encoding
*/
public function __construct($tag, $str = '', $from_exif = false)
{
$this->tag = $tag;
$this->format = PelFormat::BYTE;
$this->setValue($str, $from_exif);
}
/**
* Give the entry a new value.
*
* This will overwrite the previous value. The value can be
* retrieved later with the {@link getValue} method.
*
* @param string $str
* the new value of the entry.
* @param bool $from_exif
* internal use only, tells that string is UCS-2LE encoded, as PHP fails to detect this encoding
*/
public function setValue($str, $from_exif = false)
{
$zlen = strlen(static::ZEROES);
if (false !== $from_exif) {
$s = $str;
if (substr($str, - $zlen, $zlen) == static::ZEROES) {
$str = substr($str, 0, - $zlen);
}
$str = mb_convert_encoding($str, 'UTF-8', 'UCS-2LE');
} else {
$s = mb_convert_encoding($str, 'UCS-2LE', 'auto');
}
if (substr($s, - $zlen, $zlen) != static::ZEROES) {
$s .= static::ZEROES;
}
$l = strlen($s);
$this->components = $l;
$this->str = $str;
$this->bytes = $s;
}
/**
* Return the string of the entry.
*
* @return string the string held, without any extra NULL
* characters. The string will be the same as the one given to
* {@link setValue} or to the {@link __construct constructor}.
*/
public function getValue()
{
return $this->str;
}
/**
* Return the string of the entry.
*
* This methods returns the same as {@link getValue}.
*
* @param boolean $brief
* not used.
* @return string the string held, without any extra NULL
* characters. The string will be the same as the one given to
* {@link setValue} or to the {@link __construct constructor}.
*/
public function getText($brief = false)
{
return $this->str;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Standard PEL printf() capable exception.
* This class is a simple extension of the standard Exception class in
* PHP, and all the methods defined there retain their original
* meaning.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
* @subpackage PelException
*/
namespace lsolesen\pel;
class PelException extends \Exception
{
/**
* Construct a new PEL exception.
*
* @param string $fmt
* an optional format string can be given. It
* will be used as a format string for vprintf(). The remaining
* arguments will be available for the format string as usual with
* vprintf().
* @param mixed ...$args
* any number of arguments to be used with
* the format string.
*/
public function __construct($fmt, $args = null)
{
$args = func_get_args();
$fmt = array_shift($args);
parent::__construct(vsprintf($fmt, $args));
}
}

View File

@ -0,0 +1,151 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class representing Exif data.
*
* Exif data resides as {@link PelJpegContent data} and consists of a
* header followed by a number of {@link PelJpegIfd IFDs}.
*
* The interesting method in this class is {@link getTiff()} which
* will return the {@link PelTiff} object which really holds the data
* which one normally think of when talking about Exif data. This is
* because Exif data is stored as an extension of the TIFF file
* format.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelExif extends PelJpegContent
{
/**
* Exif header.
*
* The Exif data must start with these six bytes to be considered
* valid.
*/
const EXIF_HEADER = "Exif\0\0";
/**
* The PelTiff object contained within.
*
* @var PelTiff
*/
private $tiff = null;
/**
* Construct a new Exif object.
*
* The new object will be empty --- use the {@link load()} method to
* load Exif data from a {@link PelDataWindow} object, or use the
* {@link setTiff()} to change the {@link PelTiff} object, which is
* the true holder of the Exif {@link PelEntry entries}.
*/
public function __construct()
{
// nothing to be done
}
/**
* 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);
}
/**
* Change the TIFF information.
*
* Exif data is really stored as TIFF data, and this method can be
* used to change this data from one {@link PelTiff} object to
* another.
*
* @param PelTiff $tiff
* the new TIFF object.
*/
public function setTiff(PelTiff $tiff)
{
$this->tiff = $tiff;
}
/**
* Get the underlying TIFF object.
*
* The actual Exif data is stored in a {@link PelTiff} object, and
* this method provides access to it.
*
* @return PelTiff the TIFF object with the Exif data.
*/
public function getTiff()
{
return $this->tiff;
}
/**
* Produce bytes for the Exif data.
*
* @return string bytes representing this object.
*/
public function getBytes()
{
return self::EXIF_HEADER . $this->tiff->getBytes();
}
/**
* Return a string representation of this object.
*
* @return string a string describing this object. This is mostly
* useful for debugging.
*/
public function __toString()
{
return Pel::tra("Dumping Exif data...\n") . $this->tiff->__toString();
}
}

View File

@ -0,0 +1,226 @@
<?php
/*
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
* Copyright (C) 2017 Johannes Weberhofer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Namespace for functions operating on Exif formats.
*
* This class defines the constants that are to be used whenever one
* has to refer to the format of an Exif tag. They will be
* collectively denoted by the pseudo-type PelFormat throughout the
* documentation.
*
* All the methods defined here are static, and they all operate on a
* single argument which should be one of the class constants.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @author Johannes Weberhofer <jweberhofer@weberhofer.at>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package
*
*/
namespace lsolesen\pel;
class PelFormat
{
/**
* Unsigned byte.
*
* Each component will be an unsigned 8-bit integer with a value
* between 0 and 255.
*
* Modelled with the {@link PelEntryByte} class.
*/
const BYTE = 1;
/**
* ASCII string.
*
* Each component will be an ASCII character.
*
* Modelled with the {@link PelEntryAscii} class.
*/
const ASCII = 2;
/**
* Unsigned short.
*
* Each component will be an unsigned 16-bit integer with a value
* between 0 and 65535.
*
* Modelled with the {@link PelEntryShort} class.
*/
const SHORT = 3;
/**
* Unsigned long.
*
* Each component will be an unsigned 32-bit integer with a value
* between 0 and 4294967295.
*
* Modelled with the {@link PelEntryLong} class.
*/
const LONG = 4;
/**
* Unsigned rational number.
*
* Each component will consist of two unsigned 32-bit integers
* denoting the enumerator and denominator. Each integer will have
* a value between 0 and 4294967295.
*
* Modelled with the {@link PelEntryRational} class.
*/
const RATIONAL = 5;
/**
* Signed byte.
*
* Each component will be a signed 8-bit integer with a value
* between -128 and 127.
*
* Modelled with the {@link PelEntrySByte} class.
*/
const SBYTE = 6;
/**
* Undefined byte.
*
* Each component will be a byte with no associated interpretation.
*
* Modelled with the {@link PelEntryUndefined} class.
*/
const UNDEFINED = 7;
/**
* Signed short.
*
* Each component will be a signed 16-bit integer with a value
* between -32768 and 32767.
*
* Modelled with the {@link PelEntrySShort} class.
*/
const SSHORT = 8;
/**
* Signed long.
*
* Each component will be a signed 32-bit integer with a value
* between -2147483648 and 2147483647.
*
* Modelled with the {@link PelEntrySLong} class.
*/
const SLONG = 9;
/**
* Signed rational number.
*
* Each component will consist of two signed 32-bit integers
* denoting the enumerator and denominator. Each integer will have
* a value between -2147483648 and 2147483647.
*
* Modelled with the {@link PelEntrySRational} class.
*/
const SRATIONAL = 10;
/**
* Floating point number.
*
* Entries with this format are not currently implemented.
*/
const FLOAT = 11;
/**
* Double precision floating point number.
*
* Entries with this format are not currently implemented.
*/
const DOUBLE = 12;
/**
* Values for format's short names
*/
protected static $formatName = [
self::ASCII => 'Ascii',
self::BYTE => 'Byte',
self::SHORT => 'Short',
self::LONG => 'Long',
self::RATIONAL => 'Rational',
self::SBYTE => 'SByte',
self::SSHORT => 'SShort',
self::SLONG => 'SLong',
self::SRATIONAL => 'SRational',
self::FLOAT => 'Float',
self::DOUBLE => 'Double',
self::UNDEFINED => 'Undefined'
];
protected static $formatLength = [
self::ASCII => 1,
self::BYTE => 1,
self::SHORT => 2,
self::LONG => 4,
self::RATIONAL => 8,
self::SBYTE => 1,
self::SSHORT => 2,
self::SLONG => 4,
self::SRATIONAL => 8,
self::FLOAT => 4,
self::DOUBLE => 8,
self::UNDEFINED => 1
];
/**
* Returns the name of a format like 'Ascii' for the {@link ASCII} format
*
* @param integer $type
* as defined in {@link PelFormat}
* @return string
*/
public static function getName($type)
{
if (array_key_exists($type, self::$formatName)) {
return self::$formatName[$type];
}
throw new PelIllegalFormatException($type);
}
/**
* Return the size of components in a given format in bytes needed to store one component with the
* given format.
*
* @param integer $type
* as defined in {@link PelFormat}
* @return integer|string
*/
public static function getSize($type)
{
if (array_key_exists($type, self::$formatLength)) {
return self::$formatLength[$type];
}
throw new PelIllegalFormatException($type);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007, 2008 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with Exif IFDs.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Exception indicating a general problem with the IFD.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelIfdException extends PelException
{
// do nothing
}

View File

@ -0,0 +1,51 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Exception indicating that an unexpected format was found.
*
* The documentation for each tag in {@link PelTag} will detail any
* constrains.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelIllegalFormatException extends PelException
{
/**
* Construct a new exception indicating an illegal format.
*
* @param int $type
* the type of IFD.
*/
public function __construct($type)
{
parent::__construct('Unknown format: 0x%X', $type);
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Standard PEL exception.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Exception throw if an invalid argument is passed.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelInvalidArgumentException extends PelException
{
}

View File

@ -0,0 +1,46 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Standard PEL exception.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Exception throw if invalid data is found.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelInvalidDataException extends PelException
{
}

View File

@ -0,0 +1,659 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class for handling JPEG data.
*
* The {@link PelJpeg} class defined here provides an abstraction for
* dealing with a JPEG file. The file will be contain a number of
* sections containing some {@link PelJpegContent content} identified
* by a {@link PelJpegMarker marker}.
*
* The {@link getExif()} method is used get hold of the {@link
* PelJpegMarker::APP1 APP1} section which stores Exif data. So if
* the name of the JPEG file is stored in $filename, then one would
* get hold of the Exif data by saying:
*
* <code>
* $jpeg = new PelJpeg($filename);
* $exif = $jpeg->getExif();
* $tiff = $exif->getTiff();
* $ifd0 = $tiff->getIfd();
* $exif = $ifd0->getSubIfd(PelIfd::EXIF);
* $ifd1 = $ifd0->getNextIfd();
* </code>
*
* The $idf0 and $ifd1 variables will then be two {@link PelTiff TIFF}
* {@link PelIfd Image File Directories}, in which the data is stored
* under the keys found in {@link PelTag}.
*
* Should one have some image data (in the form of a {@link
* PelDataWindow}) of an unknown type, then the {@link
* PelJpeg::isValid()} function is handy: it will quickly test if the
* data could be valid JPEG data. The {@link PelTiff::isValid()}
* function does the same for TIFF images.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelJpeg
{
/**
* The sections in the JPEG data.
*
* A JPEG file is built up as a sequence of sections, each section
* is identified with a {@link PelJpegMarker}. Some sections can
* occur more than once in the JPEG stream (the {@link
* PelJpegMarker::DQT DQT} and {@link PelJpegMarker::DHT DTH}
* markers for example) and so this is an array of ({@link
* PelJpegMarker}, {@link PelJpegContent}) pairs.
*
* The content can be either generic {@link PelJpegContent JPEG
* content} or {@link PelExif Exif data}.
*
* @var array
*/
protected $sections = [];
/**
* The JPEG image data.
*
* @var PelDataWindow
*/
private $jpeg_data = null;
/**
* Construct a new JPEG object.
*
* The new object will be empty unless an argument is given from
* which it can initialize itself. This can either be the filename
* of a JPEG image, a {@link PelDataWindow} object or a PHP image
* resource handle.
*
* New Exif data (in the form of a {@link PelExif} object) can be
* inserted with the {@link setExif()} method:
*
* <code>
* $jpeg = new PelJpeg($data);
* // Create container for the Exif information:
* $exif = new PelExif();
* // Now Add a PelTiff object with a PelIfd object with one or more
* // PelEntry objects to $exif... Finally add $exif to $jpeg:
* $jpeg->setExif($exif);
* </code>
*
* @param boolean|string|PelDataWindow|resource|\GDImage $data
* the data that this JPEG. This can either be a
* filename, a {@link PelDataWindow} object, or a PHP image resource
* handle.
* @throws PelInvalidArgumentException
*/
public function __construct($data = false)
{
if ($data === false) {
return;
} elseif (is_string($data)) {
Pel::debug('Initializing PelJpeg object from %s', $data);
$this->loadFile($data);
} elseif ($data instanceof PelDataWindow) {
Pel::debug('Initializing PelJpeg object from PelDataWindow.');
$this->load($data);
} elseif ((is_resource($data) && get_resource_type($data) == 'gd') || (PHP_VERSION_ID >= 80000 && is_object($data) && $data instanceof \GDImage)) {
Pel::debug('Initializing PelJpeg object from image resource.');
$this->load(new PelDataWindow($data));
} else {
throw new PelInvalidArgumentException('Bad type for $data: %s', gettype($data));
}
}
/**
* JPEG sections start with 0xFF.
* The first byte that is not
* 0xFF is a marker (hopefully).
*
* @param PelDataWindow $d
*
* @return integer
*/
protected static function getJpgSectionStart($d)
{
for ($i = 0; $i < 7; $i ++) {
if ($d->getByte($i) != 0xFF) {
break;
}
}
return $i;
}
/**
* 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 $d
* the data that will be turned into JPEG
* sections.
*/
public 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) {
$i = $this->getJpgSectionStart($d);
$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(0x00, $content);
}
/* Done with the loop. */
break;
}
}
}
} /* while ($d->getSize() > 0) */
}
/**
* Load data from a file into a JPEG object.
*
* @param string $filename.
* This must be a readable file.
* @return void
* @throws PelException if file could not be loaded
*/
public function loadFile($filename)
{
$content = @file_get_contents($filename);
if ($content === false) {
throw new PelException('Can not open file "%s"', $filename);
} else {
$this->load(new PelDataWindow($content));
}
}
/**
* Set Exif data.
*
* Use this to set the Exif data in the image. This will overwrite
* any old Exif information in the image.
*
* @param PelExif $exif
* the Exif data.
*/
public function setExif(PelExif $exif)
{
$app0_offset = 1;
$app1_offset = - 1;
/* Search through all sections looking for APP0 or APP1. */
$sections_count = count($this->sections);
for ($i = 0; $i < $sections_count; $i ++) {
if (! empty($this->sections[$i][0])) {
$section = $this->sections[$i];
if ($section[0] == PelJpegMarker::APP0) {
$app0_offset = $i;
} elseif (($section[0] == PelJpegMarker::APP1) && ($section[1] instanceof PelExif)) {
$app1_offset = $i;
break;
}
}
}
/*
* Store the Exif data at the appropriate place, either where the
* old Exif data was stored ($app1_offset) or right after APP0
* ($app0_offset+1).
*/
if ($app1_offset > 0) {
$this->sections[$app1_offset][1] = $exif;
} else {
$this->insertSection(PelJpegMarker::APP1, $exif, $app0_offset + 1);
}
}
/**
* Set ICC data.
*
* Use this to set the ICC data in the image. This will overwrite
* any old ICC information in the image.
*
* @param PelJpegContent $icc
* the ICC data.
*/
public function setICC(PelJpegContent $icc)
{
$app1_offset = 1;
$app2_offset = - 1;
/* Search through all sections looking for APP0 or APP1. */
$count_sections = count($this->sections);
for ($i = 0; $i < $count_sections; $i ++) {
if (! empty($this->sections[$i][0])) {
if ($this->sections[$i][0] == PelJpegMarker::APP1) {
$app1_offset = $i;
} elseif ($this->sections[$i][0] == PelJpegMarker::APP2) {
$app2_offset = $i;
break;
}
}
}
/*
* Store the Exif data at the appropriate place, either where the
* old Exif data was stored ($app1_offset) or right after APP0
* ($app0_offset+1).
*/
if ($app2_offset > 0) {
$this->sections[$app1_offset][1] = $icc;
} else {
$this->insertSection(PelJpegMarker::APP2, $icc, $app1_offset + 1);
}
}
/**
* Get first valid APP1 Exif section data.
*
* Use this to get the @{link PelExif Exif data} stored.
*
* @return PelExif|null the Exif data found or null if the image has no
* Exif data.
*/
public function getExif()
{
$sections_count = count($this->sections);
for ($i = 0; $i < $sections_count; $i ++) {
$section = $this->getSection(PelJpegMarker::APP1, $i);
if ($section instanceof PelExif) {
return $section;
}
}
return null;
}
/**
* Get ICC data.
*
* Use this to get the @{link PelJpegContent ICC data} stored.
*
* @return PelJpegContent|null the ICC data found or null if the image has no
* ICC data.
*/
public function getICC()
{
$icc = $this->getSection(PelJpegMarker::APP2);
return $icc;
}
/**
* Clear any Exif data.
*
* This method will only clear @{link PelJpegMarker::APP1} EXIF sections found.
*/
public function clearExif()
{
$idx = 0;
while ($idx < count($this->sections)) {
$s = $this->sections[$idx];
if (($s[0] == PelJpegMarker::APP1) && ($s[1] instanceof PelExif)) {
array_splice($this->sections, $idx, 1);
$idx --;
} else {
++ $idx;
}
}
}
/**
* Append a new section.
*
* Used only when loading an image. If it used again later, then the
* section will end up after the @{link PelJpegMarker::EOI EOI
* marker} and will probably not be useful.
*
* Please use @{link setExif()} instead if you intend to add Exif
* information to an image as that function will know the right
* place to insert the data.
*
* @param integer $marker
* the marker identifying the new section.
* @param PelJpegContent $content
* the content of the new section.
*/
public function appendSection($marker, PelJpegContent $content)
{
$this->sections[] = [
$marker,
$content
];
}
/**
* Insert a new section.
*
* Please use @{link setExif()} instead if you intend to add Exif
* information to an image as that function will know the right
* place to insert the data.
*
* @param integer $marker
* the marker for the new section.
* @param PelJpegContent $content
* the content of the new section.
* @param integer $offset
* the offset where the new section will be inserted ---
* use 0 to insert it at the very beginning, use 1 to insert it
* between sections 1 and 2, etc.
*/
public function insertSection($marker, PelJpegContent $content, $offset)
{
array_splice($this->sections, $offset, 0, [
[
$marker,
$content
]
]);
}
/**
* Get a section corresponding to a particular marker.
*
* Please use the {@link getExif()} if you just need the Exif data.
*
* This will search through the sections of this JPEG object,
* looking for a section identified with the specified {@link
* PelJpegMarker marker}. The {@link PelJpegContent content} will
* then be returned. The optional argument can be used to skip over
* some of the sections. So if one is looking for the, say, third
* {@link PelJpegMarker::DHT DHT} section one would do:
*
* <code>
* $dht3 = $jpeg->getSection(PelJpegMarker::DHT, 2);
* </code>
*
* @param integer $marker
* the marker identifying the section.
* @param integer $skip
* the number of sections to be skipped. This must be a
* non-negative integer.
* @return PelJpegContent|\lsolesen\pel\PelExif the content found, or null if there is no
* content available.
*/
public function getSection($marker, $skip = 0)
{
foreach ($this->sections as $s) {
if ($s[0] == $marker) {
if ($skip > 0) {
$skip --;
} else {
return $s[1];
}
}
}
return null;
}
/**
* Get all sections.
*
* @return array an array of ({@link PelJpegMarker}, {@link
* PelJpegContent}) pairs. Each pair is an array with the {@link
* PelJpegMarker} as the first element and the {@link
* PelJpegContent} as the second element, so the return type is an
* array of arrays.
* So to loop through all the sections in a given JPEG image do
* this:
* <code>
* foreach ($jpeg->getSections() as $section) {
* $marker = $section[0];
* $content = $section[1];
* // Use $marker and $content here.
* }
* </code>
* instead of this:
* <code>
* foreach ($jpeg->getSections() as $marker => $content) {
* // Does not work the way you would think...
* }
* </code>
* The problem is that there could be several sections with the same
* marker, and thus a simple associative array does not suffice.
*/
public function getSections()
{
return $this->sections;
}
/**
* Turn this JPEG object into bytes.
*
* The bytes returned by this method is ready to be stored in a file
* as a valid JPEG image. Use the {@link saveFile()} convenience
* method to do this.
*
* @return string bytes representing this JPEG object, including all
* its sections and their associated data.
*/
public function getBytes()
{
$bytes = '';
foreach ($this->sections as $section) {
$m = $section[0];
$c = $section[1];
/* Write the marker */
$bytes .= "\xFF" . PelJpegMarker::getBytes($m);
/* Skip over empty markers. */
if ($m == PelJpegMarker::SOI || $m == PelJpegMarker::EOI) {
continue;
}
$data = $c->getBytes();
$size = strlen($data) + 2;
$bytes .= PelConvert::shortToBytes($size, PelConvert::BIG_ENDIAN);
$bytes .= $data;
/* In case of SOS, we need to write the JPEG data. */
if ($m == PelJpegMarker::SOS) {
$bytes .= $this->jpeg_data->getBytes();
}
}
return $bytes;
}
/**
* Save the JPEG object as a JPEG image in a file.
*
* @param string $filename
* the filename to save in. An existing file with the
* same name will be overwritten!
* @return integer|FALSE The number of bytes that were written to the
* file, or FALSE on failure.
*/
public function saveFile($filename)
{
return file_put_contents($filename, $this->getBytes());
}
/**
* Make a string representation of this JPEG object.
*
* This is mainly usefull for debugging. It will show the structure
* of the image, and its sections.
*
* @return string debugging information about this JPEG object.
*/
public function __toString()
{
$str = Pel::tra("Dumping JPEG data...\n");
$count_sections = count($this->sections);
for ($i = 0; $i < $count_sections; $i ++) {
$m = $this->sections[$i][0];
$c = $this->sections[$i][1];
$str .= Pel::fmt("Section %d (marker 0x%02X - %s):\n", $i, $m, PelJpegMarker::getName($m));
$str .= Pel::fmt(" Description: %s\n", PelJpegMarker::getDescription($m));
if ($m == PelJpegMarker::SOI || $m == PelJpegMarker::EOI) {
continue;
}
if ($c instanceof PelExif) {
$str .= Pel::tra(" Content : Exif data\n");
$str .= $c->__toString() . "\n";
} elseif ($c instanceof PelJpegComment) {
$str .= Pel::fmt(" Content : %s\n", $c->getValue());
} else {
$str .= Pel::tra(" Content : Unknown\n");
}
}
return $str;
}
/**
* Test data to see if it could be a valid JPEG image.
*
* The function will only look at the first few bytes of the data,
* and try to determine if it could be a valid JPEG image based on
* those bytes. This means that the check is more like a heuristic
* than a rigorous check.
*
* @param PelDataWindow $d
* the bytes that will be checked.
* @return boolean true if the bytes look like the beginning of a
* JPEG image, false otherwise.
* @see PelTiff::isValid()
*/
public static function isValid(PelDataWindow $d)
{
/* JPEG data is stored in big-endian format. */
$d->setByteOrder(PelConvert::BIG_ENDIAN);
$i = self::getJpgSectionStart($d);
return $d->getByte($i) == PelJpegMarker::SOI;
}
}

View File

@ -0,0 +1,119 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2005, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class for dealing with JPEG comments.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class representing JPEG comments.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelJpegComment extends PelJpegContent
{
/**
* The comment.
*
* @var string
*/
private $comment = '';
/**
* Construct a new JPEG comment.
*
* The new comment will contain the string given.
*
* @param string $comment
*/
public function __construct($comment = '')
{
$this->comment = $comment;
}
/**
* Load and parse data.
*
* This will load the comment from the data window passed.
*
* @param PelDataWindow $d
*/
public function load(PelDataWindow $d)
{
$this->comment = $d->getBytes();
}
/**
* Update the value with a new comment.
*
* Any old comment will be overwritten.
*
* @param string $comment
* the new comment.
*/
public function setValue($comment)
{
$this->comment = $comment;
}
/**
* Get the comment.
*
* @return string the comment.
*/
public function getValue()
{
return $this->comment;
}
/**
* Turn this comment into bytes.
*
* @return string bytes representing this comment.
*/
public function getBytes()
{
return $this->comment;
}
/**
* Return a string representation of this object.
*
* @return string the same as {@link getValue()}.
*/
public function __toString()
{
return $this->getValue();
}
}

View File

@ -0,0 +1,77 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Class representing content in a JPEG file.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class representing content in a JPEG file.
*
* A JPEG file consists of a sequence of each of which has an
* associated {@link PelJpegMarker marker} and some content. This
* class represents the content, and this basic type is just a simple
* holder of such content, represented by a {@link PelDataWindow}
* object. The {@link PelExif} class is an example of more
* specialized JPEG content.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelJpegContent
{
private $data = null;
/**
* Make a new piece of JPEG content.
*
* @param PelDataWindow $data
* the content.
*/
public function __construct(PelDataWindow $data)
{
$this->data = $data;
}
/**
* Return the bytes of the content.
*
* @return string bytes representing this JPEG content. These bytes
* will match the bytes given to {@link __construct the
* constructor}.
*/
public function getBytes()
{
return $this->data->getBytes();
}
}

View File

@ -0,0 +1,55 @@
<?php
/*
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006, 2007 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Exception thrown when an invalid marker is found.
*
* This exception is thrown when PEL expects to find a {@link
* PelJpegMarker} and instead finds a byte that isn't a known marker.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License (GPL)
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelJpegInvalidMarkerException extends PelException
{
/**
* Construct a new invalid marker exception.
* The exception will contain a message describing the error,
* including the byte found and the offset of the offending byte.
*
* @param int $marker
* the byte found.
* @param int $offset
* the offset in the data.
*/
public function __construct($marker, $offset)
{
parent::__construct('Invalid marker found at offset %d: 0x%2X', $offset, $marker);
}
}

View File

@ -0,0 +1,534 @@
<?php
/*
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2006 Martin Geisler.
* Copyright (C) 2017 Johannes Weberhofer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with JPEG markers.
*
* This class defines the constants to be used whenever one refers to
* a JPEG marker. All the methods defined are static, and they all
* operate on one argument which should be one of the class constants.
* They will all be denoted by PelJpegMarker in the documentation.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @author Johannes Weberhofer <jweberhofer@weberhofer.at>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
namespace lsolesen\pel;
class PelJpegMarker
{
/**
* Encoding (baseline)
*/
const SOF0 = 0xC0;
/**
* Encoding (extended sequential)
*/
const SOF1 = 0xC1;
/**
* Encoding (progressive)
*/
const SOF2 = 0xC2;
/**
* Encoding (lossless)
*/
const SOF3 = 0xC3;
/**
* Define Huffman table
*/
const DHT = 0xC4;
/**
* Encoding (differential sequential)
*/
const SOF5 = 0xC5;
/**
* Encoding (differential progressive)
*/
const SOF6 = 0xC6;
/**
* Encoding (differential lossless)
*/
const SOF7 = 0xC7;
/**
* Extension
*/
const JPG = 0xC8;
/**
* Encoding (extended sequential, arithmetic)
*/
const SOF9 = 0xC9;
/**
* Encoding (progressive, arithmetic)
*/
const SOF10 = 0xCA;
/**
* Encoding (lossless, arithmetic)
*/
const SOF11 = 0xCB;
/**
* Define arithmetic coding conditioning
*/
const DAC = 0xCC;
/**
* Encoding (differential sequential, arithmetic)
*/
const SOF13 = 0xCD;
/**
* Encoding (differential progressive, arithmetic)
*/
const SOF14 = 0xCE;
/**
* Encoding (differential lossless, arithmetic)
*/
const SOF15 = 0xCF;
/**
* Restart 0
*/
const RST0 = 0xD0;
/**
* Restart 1
*/
const RST1 = 0xD1;
/**
* Restart 2
*/
const RST2 = 0xD2;
/**
* Restart 3
*/
const RST3 = 0xD3;
/**
* Restart 4
*/
const RST4 = 0xD4;
/**
* Restart 5
*/
const RST5 = 0xD5;
/**
* Restart 6
*/
const RST6 = 0xD6;
/**
* Restart 7
*/
const RST7 = 0xD7;
/**
* Start of image
*/
const SOI = 0xD8;
/**
* End of image
*/
const EOI = 0xD9;
/**
* Start of scan
*/
const SOS = 0xDA;
/**
* Define quantization table
*/
const DQT = 0xDB;
/**
* Define number of lines
*/
const DNL = 0xDC;
/**
* Define restart interval
*/
const DRI = 0xDD;
/**
* Define hierarchical progression
*/
const DHP = 0xDE;
/**
* Expand reference component
*/
const EXP = 0xDF;
/**
* Application segment 0
*/
const APP0 = 0xE0;
/**
* Application segment 1
*
* When a JPEG image contains Exif data, the data will normally be
* stored in this section and a call to {@link PelJpeg::getExif()}
* will return a {@link PelExif} object representing it.
*/
const APP1 = 0xE1;
/**
* Application segment 2
*/
const APP2 = 0xE2;
/**
* Application segment 3
*/
const APP3 = 0xE3;
/**
* Application segment 4
*/
const APP4 = 0xE4;
/**
* Application segment 5
*/
const APP5 = 0xE5;
/**
* Application segment 6
*/
const APP6 = 0xE6;
/**
* Application segment 7
*/
const APP7 = 0xE7;
/**
* Application segment 8
*/
const APP8 = 0xE8;
/**
* Application segment 9
*/
const APP9 = 0xE9;
/**
* Application segment 10
*/
const APP10 = 0xEA;
/**
* Application segment 11
*/
const APP11 = 0xEB;
/**
* Application segment 12
*/
const APP12 = 0xEC;
/**
* Application segment 13
*/
const APP13 = 0xED;
/**
* Application segment 14
*/
const APP14 = 0xEE;
/**
* Application segment 15
*/
const APP15 = 0xEF;
/**
* Extension 0
*/
const JPG0 = 0xF0;
/**
* Extension 1
*/
const JPG1 = 0xF1;
/**
* Extension 2
*/
const JPG2 = 0xF2;
/**
* Extension 3
*/
const JPG3 = 0xF3;
/**
* Extension 4
*/
const JPG4 = 0xF4;
/**
* Extension 5
*/
const JPG5 = 0xF5;
/**
* Extension 6
*/
const JPG6 = 0xF6;
/**
* Extension 7
*/
const JPG7 = 0xF7;
/**
* Extension 8
*/
const JPG8 = 0xF8;
/**
* Extension 9
*/
const JPG9 = 0xF9;
/**
* Extension 10
*/
const JPG10 = 0xFA;
/**
* Extension 11
*/
const JPG11 = 0xFB;
/**
* Extension 12
*/
const JPG12 = 0xFC;
/**
* Extension 13
*/
const JPG13 = 0xFD;
/**
* Comment
*/
const COM = 0xFE;
/**
* Values for marker's short names
*/
protected static $jpegMarkerShort = [
self::SOF0 => 'SOF0',
self::SOF1 => 'SOF1',
self::SOF2 => 'SOF2',
self::SOF3 => 'SOF3',
self::SOF5 => 'SOF5',
self::SOF6 => 'SOF6',
self::SOF7 => 'SOF7',
self::SOF9 => 'SOF9',
self::SOF10 => 'SOF10',
self::SOF11 => 'SOF11',
self::SOF13 => 'SOF13',
self::SOF14 => 'SOF14',
self::SOF15 => 'SOF15',
self::SOI => 'SOI',
self::EOI => 'EOI',
self::SOS => 'SOS',
self::COM => 'COM',
self::DHT => 'DHT',
self::JPG => 'JPG',
self::DAC => 'DAC',
self::RST0 => 'RST0',
self::RST1 => 'RST1',
self::RST2 => 'RST2',
self::RST3 => 'RST3',
self::RST4 => 'RST4',
self::RST5 => 'RST5',
self::RST6 => 'RST6',
self::RST7 => 'RST7',
self::DQT => 'DQT',
self::DNL => 'DNL',
self::DRI => 'DRI',
self::DHP => 'DHP',
self::EXP => 'EXP',
self::APP0 => 'APP0',
self::APP1 => 'APP1',
self::APP2 => 'APP2',
self::APP3 => 'APP3',
self::APP4 => 'APP4',
self::APP5 => 'APP5',
self::APP6 => 'APP6',
self::APP7 => 'APP7',
self::APP8 => 'APP8',
self::APP9 => 'APP9',
self::APP10 => 'APP10',
self::APP11 => 'APP11',
self::APP12 => 'APP12',
self::APP13 => 'APP13',
self::APP14 => 'APP14',
self::APP15 => 'APP15',
self::JPG0 => 'JPG0',
self::JPG1 => 'JPG1',
self::JPG2 => 'JPG2',
self::JPG3 => 'JPG3',
self::JPG4 => 'JPG4',
self::JPG5 => 'JPG5',
self::JPG6 => 'JPG6',
self::JPG7 => 'JPG7',
self::JPG8 => 'JPG8',
self::JPG9 => 'JPG9',
self::JPG10 => 'JPG10',
self::JPG11 => 'JPG11',
self::JPG12 => 'JPG12',
self::JPG13 => 'JPG13',
self::COM => 'COM'
];
/**
* Values for marker's descriptions names.
*/
protected static $jpegMarkerDescriptions = [
self::SOF0 => 'Encoding (baseline)',
self::SOF1 => 'Encoding (extended sequential)',
self::SOF2 => 'Encoding (progressive)',
self::SOF3 => 'Encoding (lossless)',
self::SOF5 => 'Encoding (differential sequential)',
self::SOF6 => 'Encoding (differential progressive)',
self::SOF7 => 'Encoding (differential lossless)',
self::SOF9 => 'Encoding (extended sequential, arithmetic)',
self::SOF10 => 'Encoding (progressive, arithmetic)',
self::SOF11 => 'Encoding (lossless, arithmetic)',
self::SOF13 => 'Encoding (differential sequential, arithmetic)',
self::SOF14 => 'Encoding (differential progressive, arithmetic)',
self::SOF15 => 'Encoding (differential lossless, arithmetic)',
self::SOI => 'Start of image',
self::EOI => 'End of image',
self::SOS => 'Start of scan',
self::COM => 'Comment',
self::DHT => 'Define Huffman table',
self::JPG => 'Extension',
self::DAC => 'Define arithmetic coding conditioning',
'RST' => 'Restart %d',
self::DQT => 'Define quantization table',
self::DNL => 'Define number of lines',
self::DRI => 'Define restart interval',
self::DHP => 'Define hierarchical progression',
self::EXP => 'Expand reference component',
'APP' => 'Application segment %d',
'JPG' => 'Extension %d',
self::COM => 'Comment'
];
/**
* Check if a byte is a valid JPEG marker.
* If the byte is recognized true is returned, otherwise false will be returned.
*
* @param integer $marker
* the marker as defined in {@link PelJpegMarker}
* @return boolean
*/
public static function isValid($marker)
{
return ($marker >= self::SOF0 && $marker <= self::COM);
}
/**
* Turn a JPEG marker into bytes.
* This will be a string with just a single byte since all JPEG markers are simply single bytes.
*
* @param integer $marker
* the marker as defined in {@link PelJpegMarker}
* @return string
*/
public static function getBytes($marker)
{
return chr($marker);
}
/**
* Return the short name for a marker, e.g., 'SOI' for the Start
* of Image marker.
*
* @param integer $marker
* the marker as defined in {@link PelJpegMarker}
* @return string
*/
public static function getName($marker)
{
if (array_key_exists($marker, self::$jpegMarkerShort)) {
return self::$jpegMarkerShort[$marker];
} else {
return Pel::fmt('Unknown marker: 0x%02X', $marker);
}
}
/**
* Returns a description of a JPEG marker.
*
* @param integer $marker
* the marker as defined in {@link PelJpegMarker}
* @return string
*/
public static function getDescription($marker)
{
if (array_key_exists($marker, self::$jpegMarkerShort)) {
if (array_key_exists($marker, self::$jpegMarkerDescriptions)) {
return self::$jpegMarkerDescriptions[$marker];
} else {
$splitted = preg_split("/(\d+)/", self::$jpegMarkerShort[$marker], - 1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
if ((count($splitted) == 2) && array_key_exists($splitted[0], self::$jpegMarkerDescriptions)) {
return Pel::fmt(self::$jpegMarkerDescriptions[$splitted[0]], $splitted[1]);
}
}
}
return Pel::fmt('Unknown marker: 0x%02X', $marker);
}
}

View File

@ -0,0 +1,79 @@
<?php
/*
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005 Martin Geisler.
* Copyright (C) 2017 Johannes Weberhofer.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Namespace for functions operating on Exif formats.
*
* This class defines the constants that are to be used whenever one
* has to refer to the format of an Exif tag. They will be
* collectively denoted by the pseudo-type PelFormat throughout the
* documentation.
*
* All the methods defined here are static, and they all operate on a
* single argument which should be one of the class constants.
*
* @author Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package
*
*/
namespace lsolesen\pel;
abstract class PelMakerNotes
{
protected $type;
protected $parent;
protected $data;
protected $components;
protected $offset;
public static function createMakerNotesFromManufacturer($man, $parent, $data, $size, $offset)
{
switch ($man) {
case 'Canon':
return new PelCanonMakerNotes($parent, $data, $size, $offset);
default:
return null;
}
}
public function __construct($parent, $data, $size, $offset)
{
$this->parent = $parent;
$this->data = $data;
$this->size = $size;
$this->offset = $offset;
$this->components = 0;
Pel::debug('Creating MakerNotes with %d bytes at offset %d.', $size, $offset);
}
abstract public function load();
}

View File

@ -0,0 +1,51 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with Exif entries.
*
* This file defines two exception classes and the abstract class
* {@link PelEntry} which provides the basic methods that all Exif
* entries will have. All Exif entries will be represented by
* descendants of the {@link PelEntry} class --- the class itself is
* abstract and so it cannot be instantiated.
*
* @author Vinzenz Rosenkranz <vinzenz.rosenkranz@gmail.com>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* An exception thrown when the makernotes IFD is malformed.
*
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelMakerNotesMalformedException extends PelException
{
}

View File

@ -0,0 +1,67 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with Exif entries.
*
* This file defines two exception classes and the abstract class
* {@link PelEntry} which provides the basic methods that all Exif
* entries will have. All Exif entries will be represented by
* descendants of the {@link PelEntry} class --- the class itself is
* abstract and so it cannot be instantiated.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Exception cast when numbers overflow.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelOverflowException extends PelException
{
/**
* Construct a new overflow exception.
*
* @param int $v
* the value that is out of range.
* @param int $min
* the minimum allowed value.
* @param int $max
* the maximum allowed value.
*/
public function __construct($v, $min, $max)
{
parent::__construct('Value %.0f out of range [%.0f, %.0f]', $v, $min, $max);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,310 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with TIFF data.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Class for handling TIFF data.
*
* Exif data is actually an extension of the TIFF file format. TIFF
* images consist of a number of {@link PelIfd Image File Directories}
* (IFDs), each containing a number of {@link PelEntry entries}. The
* IFDs are linked to each other --- one can get hold of the first one
* with the {@link getIfd()} method.
*
* To parse a TIFF image for Exif data one would do:
*
* <code>
* $tiff = new PelTiff($data);
* $ifd0 = $tiff->getIfd();
* $exif = $ifd0->getSubIfd(PelIfd::EXIF);
* $ifd1 = $ifd0->getNextIfd();
* </code>
*
* Should one have some image data of an unknown type, then the {@link
* PelTiff::isValid()} function is handy: it will quickly test if the
* data could be valid TIFF data. The {@link PelJpeg::isValid()}
* function does the same for JPEG images.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
*/
namespace lsolesen\pel;
class PelTiff
{
/**
* TIFF header.
*
* This must follow after the two bytes indicating the byte order.
*/
const TIFF_HEADER = 0x002A;
/**
* The first Image File Directory, if any.
*
* If set, then the type of the IFD must be {@link PelIfd::IFD0}.
*
* @var PelIfd
*/
private $ifd = null;
/**
* Construct a new object for holding TIFF data.
*
* The new object will be empty (with no {@link PelIfd}) unless an
* argument is given from which it can initialize itself. This can
* either be the filename of a TIFF image or a {@link PelDataWindow}
* object.
*
* Use {@link setIfd()} to explicitly set the IFD.
*
* @param boolean|string|PelDataWindow $data;
*/
public function __construct($data = false)
{
if ($data === false) {
return;
}
if (is_string($data)) {
Pel::debug('Initializing PelTiff object from %s', $data);
$this->loadFile($data);
} elseif ($data instanceof PelDataWindow) {
Pel::debug('Initializing PelTiff object from PelDataWindow.');
$this->load($data);
} else {
throw new PelInvalidArgumentException('Bad type for $data: %s', gettype($data));
}
}
/**
* 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 $d
* 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.
*/
public 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 from a file into a TIFF object.
*
* @param string $filename
* the filename. This must be a readable file.
*/
public function loadFile($filename)
{
$this->load(new PelDataWindow(file_get_contents($filename)));
}
/**
* Set the first IFD.
*
* @param PelIfd $ifd
* the new first IFD, which must be of type {@link
* PelIfd::IFD0}.
*/
public function setIfd(PelIfd $ifd)
{
if ($ifd->getType() != PelIfd::IFD0) {
throw new PelInvalidDataException('Invalid type of IFD: %d, expected %d.', $ifd->getType(), PelIfd::IFD0);
}
$this->ifd = $ifd;
}
/**
* Return the first IFD.
*
* @return PelIfd the first IFD contained in the TIFF data, if any.
* If there is no IFD null will be returned.
*/
public function getIfd()
{
return $this->ifd;
}
/**
* Turn this object into bytes.
*
* TIFF images can have {@link PelConvert::LITTLE_ENDIAN
* little-endian} or {@link PelConvert::BIG_ENDIAN big-endian} byte
* order, and so this method takes an argument specifying that.
*
* @param boolean $order
* the desired byte order of the TIFF data.
* This should be one of {@link PelConvert::LITTLE_ENDIAN} or {@link
* PelConvert::BIG_ENDIAN}.
* @return string the bytes representing this object.
*/
public function getBytes($order = PelConvert::LITTLE_ENDIAN)
{
if ($order == PelConvert::LITTLE_ENDIAN) {
$bytes = 'II';
} else {
$bytes = 'MM';
}
/* TIFF magic number --- fixed value. */
$bytes .= PelConvert::shortToBytes(self::TIFF_HEADER, $order);
if ($this->ifd !== null) {
/*
* IFD 0 offset. We will always start IDF 0 at an offset of 8
* bytes (2 bytes for byte order, another 2 bytes for the TIFF
* header, and 4 bytes for the IFD 0 offset make 8 bytes
* together).
*/
$bytes .= PelConvert::longToBytes(8, $order);
/*
* The argument specifies the offset of this IFD. The IFD will
* use this to calculate offsets from the entries to their data,
* all those offsets are absolute offsets counted from the
* beginning of the data.
*/
$bytes .= $this->ifd->getBytes(8, $order);
} else {
$bytes .= PelConvert::longToBytes(0, $order);
}
return $bytes;
}
/**
* Save the TIFF object as a TIFF image in a file.
*
* @param string $filename
* the filename to save in. An existing file with the
* same name will be overwritten!
* @return integer|FALSE The number of bytes that were written to the
* file, or FALSE on failure.
*/
public function saveFile($filename)
{
return file_put_contents($filename, $this->getBytes());
}
/**
* Return a string representation of this object.
*
* @return string a string describing this object. This is mostly useful
* for debugging.
*/
public function __toString()
{
$str = Pel::fmt("Dumping TIFF data...\n");
if ($this->ifd !== null) {
$str .= $this->ifd->__toString();
}
return $str;
}
/**
* 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;
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Classes for dealing with Exif entries.
*
* This file defines two exception classes and the abstract class
* {@link PelEntry} which provides the basic methods that all Exif
* entries will have. All Exif entries will be represented by
* descendants of the {@link PelEntry} class --- the class itself is
* abstract and so it cannot be instantiated.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @license http://www.gnu.org/licenses/gpl.html GNU General Public
* License (GPL)
* @package PEL
*/
/**
* Exception indicating that an unexpected format was found.
*
* The documentation for each tag in {@link PelTag} will detail any
* constrains.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
class PelUnexpectedFormatException extends PelEntryException
{
/**
* Construct a new exception indicating an invalid format.
*
* @param int $type
* the type of IFD.
* @param int $tag
* the tag for which the violation was found as defined in {@link PelTag}
* @param int $found
* the format found as defined in {@link PelFormat}
* @param int $expected
* the expected as defined in {@link PelFormat}
*/
public function __construct($type, $tag, $found, $expected)
{
parent::__construct('Unexpected format found for %s tag: PelFormat::%s. Expected PelFormat::%s instead.', PelTag::getName($type, $tag), strtoupper(PelFormat::getName($found)), strtoupper(PelFormat::getName($expected)));
$this->tag = $tag;
$this->type = $type;
}
}

View File

@ -0,0 +1,65 @@
<?php
/**
* PEL: PHP Exif Library.
* A library with support for reading and
* writing all Exif headers in JPEG and TIFF images using PHP.
*
* Copyright (C) 2004, 2005, 2006 Martin Geisler.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program in the file COPYING; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* Exception indicating that an unexpected number of components was
* found.
*
* Some tags have strict limits as to the allowed number of
* components, and this exception is thrown if the data violates such
* a constraint. The documentation for each tag in {@link PelTag}
* explains the expected number of components.
*
* @author Martin Geisler <mgeisler@users.sourceforge.net>
* @package PEL
* @subpackage Exception
*/
namespace lsolesen\pel;
use lsolesen\pel\PelTag;
class PelWrongComponentCountException extends \lsolesen\pel\PelEntryException
{
/**
* Construct a new exception indicating a wrong number of
* components.
*
* @param int $type
* the type of IFD.
* @param int $tag
* the tag for which the violation was found.
* @param int $found
* the number of components found.
* @param int $expected
* the expected number of components.
*/
public function __construct($type, $tag, $found, $expected)
{
parent::__construct('Wrong number of components found for %s tag: %d. ' . 'Expected %d.', PelTag::getName($type, $tag), $found, $expected);
$this->tag = $tag;
$this->type = $type;
}
}