<?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
 */

/* $Id: PelEntryShort.php 13759 2012-07-04 04:31:41Z giangnd $ */


/**
 * Classes used to hold shorts, both signed and unsigned.
 *
 * @author Martin Geisler <mgeisler@users.sourceforge.net>
 * @version $Revision: 419 $
 * @date $Date: 2006-02-20 17:22:36 +0100 (Mon, 20 Feb 2006) $
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public
 * License (GPL)
 * @package PEL
 */

/**#@+ Required class definitions. */
require_once('PelEntryNumber.php');
require_once('PelConvert.php');
require_once('Pel.php');
/**#@-*/


/**
 * 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
 */
class PelEntryShort extends PelEntryNumber {

	/**
	 * 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 PelTag 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 int $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.
	 */
	function __construct($tag /* $value... */) {
		$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 int the number that should be converted.
	 *
	 * @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
	 * {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
	 *
	 * @return string bytes representing the number given.
	 */
	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 some values can be returned in a long or more
	 * brief form, and this parameter controls that.
	 *
	 * @return string the value as text.
	 */
	function getText($brief = false) {
		switch ($this->tag) {
			case PelTag::METERING_MODE:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Unknown');
					case 1:
						return Pel::tra('Average');
					case 2:
						return Pel::tra('Center-Weighted Average');
					case 3:
						return Pel::tra('Spot');
					case 4:
						return Pel::tra('Multi Spot');
					case 5:
						return Pel::tra('Pattern');
					case 6:
						return Pel::tra('Partial');
					case 255:
						return Pel::tra('Other');
					default:
						return $this->value[0];
				}

			case PelTag::COMPRESSION:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 1:
						return Pel::tra('Uncompressed');
					case 6:
						return Pel::tra('JPEG compression');
					default:
						return $this->value[0];

				}

			case PelTag::PLANAR_CONFIGURATION:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 1:
						return Pel::tra('chunky format');
					case 2:
						return Pel::tra('planar format');
					default:
						return $this->value[0];
				}

			case PelTag::SENSING_METHOD:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 1:
						return Pel::tra('Not defined');
					case 2:
						return Pel::tra('One-chip color area sensor');
					case 3:
						return Pel::tra('Two-chip color area sensor');
					case 4:
						return Pel::tra('Three-chip color area sensor');
					case 5:
						return Pel::tra('Color sequential area sensor');
					case 7:
						return Pel::tra('Trilinear sensor');
					case 8:
						return Pel::tra('Color sequential linear sensor');
					default:
						return $this->value[0];
				}

			case PelTag::LIGHT_SOURCE:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Unknown');
					case 1:
						return Pel::tra('Daylight');
					case 2:
						return Pel::tra('Fluorescent');
					case 3:
						return Pel::tra('Tungsten (incandescent light)');
					case 4:
						return Pel::tra('Flash');
					case 9:
						return Pel::tra('Fine weather');
					case 10:
						return Pel::tra('Cloudy weather');
					case 11:
						return Pel::tra('Shade');
					case 12:
						return Pel::tra('Daylight fluorescent');
					case 13:
						return Pel::tra('Day white fluorescent');
					case 14:
						return Pel::tra('Cool white fluorescent');
					case 15:
						return Pel::tra('White fluorescent');
					case 17:
						return Pel::tra('Standard light A');
					case 18:
						return Pel::tra('Standard light B');
					case 19:
						return Pel::tra('Standard light C');
					case 20:
						return Pel::tra('D55');
					case 21:
						return Pel::tra('D65');
					case 22:
						return Pel::tra('D75');
					case 24:
						return Pel::tra('ISO studio tungsten');
					case 255:
						return Pel::tra('Other');
					default:
						return $this->value[0];
				}

			case PelTag::FOCAL_PLANE_RESOLUTION_UNIT:
			case PelTag::RESOLUTION_UNIT:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 2:
						return Pel::tra('Inch');
					case 3:
						return Pel::tra('Centimeter');
					default:
						return $this->value[0];
				}

			case PelTag::EXPOSURE_PROGRAM:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Not defined');
					case 1:
						return Pel::tra('Manual');
					case 2:
						return Pel::tra('Normal program');
					case 3:
						return Pel::tra('Aperture priority');
					case 4:
						return Pel::tra('Shutter priority');
					case 5:
						return Pel::tra('Creative program (biased toward depth of field)');
					case 6:
						return Pel::tra('Action program (biased toward fast shutter speed)');
					case 7:
						return Pel::tra('Portrait mode (for closeup photos with the background out of focus');
					case 8:
						return Pel::tra('Landscape mode (for landscape photos with the background in focus');
					default:
						return $this->value[0];
				}
				 
			case PelTag::ORIENTATION:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 1:
						return Pel::tra('top - left');
					case 2:
						return Pel::tra('top - right');
					case 3:
						return Pel::tra('bottom - right');
					case 4:
						return Pel::tra('bottom - left');
					case 5:
						return Pel::tra('left - top');
					case 6:
						return Pel::tra('right - top');
					case 7:
						return Pel::tra('right - bottom');
					case 8:
						return Pel::tra('left - bottom');
					default:
						return $this->value[0];
				}

			case PelTag::YCBCR_POSITIONING:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 1:
						return Pel::tra('centered');
					case 2:
						return Pel::tra('co-sited');
					default:
						return $this->value[0];
				}

			case PelTag::YCBCR_SUB_SAMPLING:
				//CC (e->components, 2, v);
				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];
				 
			case PelTag::PHOTOMETRIC_INTERPRETATION:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 2:
						return 'RGB';
					case 6:
						return 'YCbCr';
					default:
						return $this->value[0];
				}
				 
			case PelTag::COLOR_SPACE:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 1:
						return 'sRGB';
					case 2:
						return 'Adobe RGB';
					case 0xffff:
						return Pel::tra('Uncalibrated');
					default:
						return $this->value[0];
				}

			case PelTag::FLASH:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0x0000:
						return Pel::tra('Flash did not fire.');
					case 0x0001:
						return Pel::tra('Flash fired.');
					case 0x0005:
						return Pel::tra('Strobe return light not detected.');
					case 0x0007:
						return Pel::tra('Strobe return light detected.');
					case 0x0009:
						return Pel::tra('Flash fired, compulsory flash mode.');
					case 0x000d:
						return Pel::tra('Flash fired, compulsory flash mode, return light not detected.');
					case 0x000f:
						return Pel::tra('Flash fired, compulsory flash mode, return light detected.');
					case 0x0010:
						return Pel::tra('Flash did not fire, compulsory flash mode.');
					case 0x0018:
						return Pel::tra('Flash did not fire, auto mode.');
					case 0x0019:
						return Pel::tra('Flash fired, auto mode.');
					case 0x001d:
						return Pel::tra('Flash fired, auto mode, return light not detected.');
					case 0x001f:
						return Pel::tra('Flash fired, auto mode, return light detected.');
					case 0x0020:
						return Pel::tra('No flash function.');
					case 0x0041:
						return Pel::tra('Flash fired, red-eye reduction mode.');
					case 0x0045:
						return Pel::tra('Flash fired, red-eye reduction mode, return light not detected.');
					case 0x0047:
						return Pel::tra('Flash fired, red-eye reduction mode, return light detected.');
					case 0x0049:
						return Pel::tra('Flash fired, compulsory flash mode, red-eye reduction mode.');
					case 0x004d:
						return Pel::tra('Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected.');
					case 0x004f:
						return Pel::tra('Flash fired, compulsory flash mode, red-eye reduction mode, return light detected.');
					case 0x0058:
						return Pel::tra('Flash did not fire, auto mode, red-eye reduction mode.');
					case 0x0059:
						return Pel::tra('Flash fired, auto mode, red-eye reduction mode.');
					case 0x005d:
						return Pel::tra('Flash fired, auto mode, return light not detected, red-eye reduction mode.');
					case 0x005f:
						return Pel::tra('Flash fired, auto mode, return light detected, red-eye reduction mode.');
					default:
						return $this->value[0];
				}

			case PelTag::CUSTOM_RENDERED:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Normal process');
					case 1:
						return Pel::tra('Custom process');
					default:
						return $this->value[0];
				}

			case PelTag::EXPOSURE_MODE:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Auto exposure');
					case 1:
						return Pel::tra('Manual exposure');
					case 2:
						return Pel::tra('Auto bracket');
					default:
						return $this->value[0];
				}
				 
			case PelTag::WHITE_BALANCE:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Auto white balance');
					case 1:
						return Pel::tra('Manual white balance');
					default:
						return $this->value[0];
				}

			case PelTag::SCENE_CAPTURE_TYPE:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Standard');
					case 1:
						return Pel::tra('Landscape');
					case 2:
						return Pel::tra('Portrait');
					case 3:
						return Pel::tra('Night scene');
					default:
						return $this->value[0];
				}

			case PelTag::GAIN_CONTROL:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Normal');
					case 1:
						return Pel::tra('Low gain up');
					case 2:
						return Pel::tra('High gain up');
					case 3:
						return Pel::tra('Low gain down');
					case 4:
						return Pel::tra('High gain down');
					default:
						return $this->value[0];
				}

			case PelTag::SATURATION:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Normal');
					case 1:
						return Pel::tra('Low saturation');
					case 2:
						return Pel::tra('High saturation');
					default:
						return $this->value[0];
				}

			case PelTag::CONTRAST:
			case PelTag::SHARPNESS:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Normal');
					case 1:
						return Pel::tra('Soft');
					case 2:
						return Pel::tra('Hard');
					default:
						return $this->value[0];
				}

			case PelTag::SUBJECT_DISTANCE_RANGE:
				//CC (e->components, 1, v);
				switch ($this->value[0]) {
					case 0:
						return Pel::tra('Unknown');
					case 1:
						return Pel::tra('Macro');
					case 2:
						return Pel::tra('Close view');
					case 3:
						return Pel::tra('Distant view');
					default:
						return $this->value[0];
				}

			case 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);
				}

			default:
				return parent::getText($brief);
		}
	}
}


/**
 * 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
 */
class PelEntrySShort extends PelEntryNumber {

	/**
	 * 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 PelTag 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.
	 */
	function __construct($tag /* $value... */) {
		$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 the number that should be converted.
	 *
	 * @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
	 * {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
	 *
	 * @return string bytes representing the number given.
	 */
	function numberToBytes($number, $order) {
		return PelConvert::sShortToBytes($number, $order);
	}
}


?>