source: extensions/AMetaData/JpegMetaData/Readers/NikonReader.class.php @ 5237

Last change on this file since 5237 was 5228, checked in by grum, 15 years ago

fix bug to determine the lens on Nikon D200 (and probably other...)

  • Property svn:executable set to *
File size: 20.9 KB
Line 
1<?php
2/*
3 * --:: JPEG MetaDatas ::-------------------------------------------------------
4 *
5 *  Author    : Grum
6 *   email    : grum at piwigo.org
7 *   website  : http://photos.grum.fr
8 *
9 *   << May the Little SpaceFrog be with you ! >>
10 *
11 *
12 * +-----------------------------------------------------------------------+
13 * | JpegMetaData - a PHP based Jpeg Metadata manager                      |
14 * +-----------------------------------------------------------------------+
15 * | Copyright(C) 2010  Grum - http://www.grum.fr                          |
16 * +-----------------------------------------------------------------------+
17 * | This program is free software; you can redistribute it and/or modify  |
18 * | it under the terms of the GNU General Public License as published by  |
19 * | the Free Software Foundation                                          |
20 * |                                                                       |
21 * | This program is distributed in the hope that it will be useful, but   |
22 * | WITHOUT ANY WARRANTY; without even the implied warranty of            |
23 * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
24 * | General Public License for more details.                              |
25 * |                                                                       |
26 * | You should have received a copy of the GNU General Public License     |
27 * | along with this program; if not, write to the Free Software           |
28 * | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
29 * | USA.                                                                  |
30 * +-----------------------------------------------------------------------+
31 *
32 *
33 * -----------------------------------------------------------------------------
34 *
35 * The NikonReader class is the dedicated to read the specific Nikon tags
36 *
37 * ====> See MakerNotesReader.class.php to know more about the structure <======
38 *
39 * -----------------------------------------------------------------------------
40 *
41 * .. Notes ..
42 *
43 *
44 * ****             All known tags are not implemented !!                   ****
45 *
46 *
47 * The NikonReader class is derived from the MakerNotesReader class.
48 *
49 * =====> See MakerNotesReader.class.php to know more about common methods <====
50 *
51 * -----------------------------------------------------------------------------
52 */
53
54
55
56  require_once(JPEG_METADATA_DIR."TagDefinitions/NikonTags.class.php");
57  require_once(JPEG_METADATA_DIR."Readers/MakerNotesReader.class.php");
58
59  class NikonReader extends MakerNotesReader
60  {
61    /* these 2 specific metadata are used to decrypt some information, like the
62     * data lens
63     */
64    protected $serialNumber="";
65    protected $shutterCount=-1;
66
67    protected $toDecode=Array();
68
69    /**
70     * The constructor needs, like the ancestor, the datas to be parsed
71     *
72     * Some datas are offset on extra data, and this offset can be (some time)
73     * absolute inside the IFD, or relative. So, the offset of the IFD structure
74     * is needed
75     *
76     * The byte order can be different from the TIFF byte order !
77     *
78     * The constructor need the maker signature (see the MakerNotesSignatures
79     * class for a list of known signatures)
80     *
81     * @param String $data
82     * @param ULong $offset : offset of IFD block in the jpeg file
83     * @param String $byteOrder
84     * @param String $makerSignature :
85     */
86    function __construct($data, $offset, $byteOrder, $makerSignature)
87    {
88      $this->maker = MAKER_NIKON;
89      switch($makerSignature)
90      {
91        case MakerNotesSignatures::Nikon2Header:
92          $this->header = MakerNotesSignatures::Nikon2Header;
93          $this->headerSize = MakerNotesSignatures::Nikon2HeaderSize;
94          break;
95        case MakerNotesSignatures::Nikon3Header:
96          $this->header = MakerNotesSignatures::Nikon3Header;
97          $this->headerSize = MakerNotesSignatures::Nikon3HeaderSize;
98          break;
99      }
100
101      // offset inside Nikon maker note are relative
102      $offset=-10;
103
104      parent::__construct($data, $offset, $byteOrder);
105
106      $this->processEncryptedTags();
107    }
108
109    function __destruct()
110    {
111      parent::__destruct();
112    }
113
114    /**
115     * initialize the definition for Pentax exif tags
116     */
117    protected function initializeTagDef()
118    {
119      $this->tagDef = new NikonTags();
120    }
121
122    /**
123     * skip the IFD header
124     */
125    protected function skipHeader($headerSize=0)
126    {
127      parent::skipHeader($headerSize);
128      if($this->header == MakerNotesSignatures::Nikon3Header)
129      {
130        /*
131         * the nikon3header is made of 7 char, and then 3 next char ?????
132         */
133        $header=$this->data->readASCII(3);
134
135
136        $header=$this->data->readASCII(2);
137        /*
138         * The Nikon3Header is formatted as a TIFF header, but the class is not
139         * derived from TiffReader, because we can think there is no more than
140         * one IFD in the maker notes.
141         * By this way, it's easier to skip the header and start reading the
142         * entries.
143         *
144         * begins wih "II" or "MM" (indicate the byte order)
145         * next value is an USHORT, must equals 0x2a
146         *
147         * all data have to be read with the byte order defined in header
148         */
149        if($header=="II" or $header="MM")
150        {
151          $this->byteOrder=$header;
152          $this->data->setByteOrder($this->byteOrder);
153
154          $header=$this->data->readUShort();
155          if($header==0x002a)
156          {
157            $this->isValid=true;
158            $header=$this->data->readULong();
159          }
160        }
161      }
162    }
163
164    /**
165     * encrypted values are processed in one shot when all the tags are processed
166     * with this method, we are sure the "SerialNumber" (0x001d) and the
167     * "ShutterCount" (0x00a7) tags are initialized
168     */
169    protected function processEncryptedTags()
170    {
171      foreach($this->toDecode as $key=>$val)
172      {
173        $tagIndex=$this->getTagIndexById($key);
174        if($tagIndex>-1)
175        {
176          $this->entries[$tagIndex]->getTag()->setLabel($this->processSpecialTag($key, $val[0], $val[1]));
177          //echo sprintf("%04x * %s => %s<br>",$key,ConvertData::toHexDump($val[0], ByteType::ASCII),$this->processSpecialTag($key, $val[0], $val[1]));
178        }
179      }
180    }
181
182    /**
183     * this function do the interpretation of specials tags
184     *
185     * the function return the interpreted value for the tag
186     *
187     * @param $tagId             : the id of the tag
188     * @param $values            : 'raw' value to be interpreted
189     * @param UByte $type        : if needed (for IFD structure) the type of data
190     * @param ULong $valueOffset : if needed, the offset of data in the jpeg file
191     * @return String or Array or DateTime or Integer or Float...
192     */
193    protected function processSpecialTag($tagId, $values, $type, $valuesOffset=0)
194    {
195      switch($tagId)
196      {
197        case 0x0001: // "MakerNoteVersion"
198          // 0x30323030 => String "0200" => 2.00
199          $major=substr($values,0,2);
200          if(substr($values,0,1)=="0")
201          {
202            $major=substr($values,1,1);
203          }
204          else
205          {
206            $major=substr($values,0,2);
207          }
208          $minor=substr($values,2);
209          $returned=sprintf("%s.%s", $major, $minor);
210          break;
211        case 0x001d: // "SerialNumber"
212          $returned=ConvertData::toStrings($values);
213          $this->serialNumber=$returned;
214          break;
215        case 0x0003: // "ColorMode"
216        case 0x0004: // "Quality"
217        case 0x0005: // "WhiteBalance"
218        case 0x0006: // "Sharpness"
219        case 0x0007: // "FocusMode"
220        case 0x0008: // "FlashSetting"
221        case 0x0009: // "FlashType"
222        case 0x000f: // "ISOSelection"
223        case 0x0080: // "ImageAdjustment"
224        case 0x0081: // "ToneComp"
225        case 0x0082: // "AuxiliaryLens"
226        case 0x008D: // "ColorHue"
227        case 0x008f: // "SceneMode"
228        case 0x0090: // "LightSource"
229        case 0x0095: // "NoiseReduction"
230        case 0x009c: // "SceneAssist"
231        case 0x00a0: // "SerialNumber"
232        case 0x00a9: // "ImageOptimization"
233        case 0x00aa: // "Saturation"
234        case 0x00ab: // "VariProgram"
235        case 0x0e09: // "NikonCaptureVersion"
236          /*
237           * null terminated strings
238           */
239          $returned=ConvertData::toStrings($values);
240          break;
241        case 0x092: // "HueAdjustment"
242        case 0x00a2: // "ImageDataSize"
243          $returned=$values;
244          break;
245        case 0x0a7: // "ShutterCount"
246          $this->shutterCount=$values;
247          $returned=$values;
248          break;
249        case 0x001f: // "VRInfo"
250          $returned=(ord($values{4})==1)?"On":"Off";
251          break;
252        case 0x0083: // "LensType"
253          $tag=$this->tagDef->getTagById(0x0083);
254
255          $returned=Array();
256          if(($values & 0x0001) == 0x0001)
257            $returned[]=$tag['tagValues.specialValues'][0x0001];
258
259          if(($values & 0x0002) == 0x0002)
260            $returned[]=$tag['tagValues.specialValues'][0x0002];
261
262          if(($values & 0x0004) == 0x0004)
263            $returned[]=$tag['tagValues.specialValues'][0x0004];
264
265          if(($values & 0x0008) == 0x0008)
266            $returned[]=$tag['tagValues.specialValues'][0x0008];
267          unset($tag);
268          break;
269        case 0x0084: // "Lens"
270          /* array of 4 rationnal
271           * - short focal
272           * - long focal
273           * - aperture at short focal
274           * - aperture at long focal
275           *
276           * ==> 18-70mm f/3.5-4.5
277           */
278          $result=array();
279          foreach($values as $val)
280          {
281            if($val[1]==0) $val[1]==1;
282            $result[]=$val[0]/$val[1];
283          }
284
285          if($result[0]!=$result[1])
286          {
287            $returned=sprintf("%.0f-%.0fmm ", $result[0], $result[1]);
288          }
289          else
290          {
291            $returned=sprintf("%.0fmm ", $result[0]);
292          }
293
294          if($result[2]!=$result[3])
295          {
296            $returned.=sprintf("f/%.1f-%.1f", $result[2], $result[3]);
297          }
298          else
299          {
300            $returned.=sprintf("f/%.1f", $result[2]);
301          }
302          break;
303        case 0x0086: // "DigitalZoom"
304          if($values[1]==0) $values[1]=1;
305          $returned=sprintf("x%.1f", $values[0]/$values[1]);
306          break;
307        case 0x0088: // "AFInfo"
308          /* - shortInt : AFAreaMode
309           * - shortInt : AFPoint
310           * - longInt  : AFPointsInFocus
311           */
312          $tag=$this->tagDef->getTagById(0x0088);
313
314          $values.="\0\0\0\0";
315
316          $returned=Array();
317
318          $tmp=ord($values{0});
319          $returned['AFAreaMode'] = $tag['tagValues.specialValues'][0][$tmp];
320
321          $tmp=ord($values{1});
322          $returned['AFPoint'] = $tag['tagValues.specialValues'][1][$tmp];
323
324          if($values=="\x00\x07\xff\xff")
325          {
326            $returned['AFPointsInFocus'] = $tag['tagValues.specialValues'][2][$values];
327          }
328          else
329          {
330            $tmp=ord($values{2}) * 256 + ord($values{3});
331            $returned['AFPointsInFocus']=Array();
332            foreach($tag['tagValues.specialValues'][2] as $key => $val)
333            {
334              if(($tmp & $key) == $key)
335                $returned['AFPointsInFocus'][]=$val;
336            }
337          }
338          unset($tag);
339          break;
340        case 0x0089: // "ShootingMode"
341          $returned=Array();
342          $tag=$this->tagDef->getTagById(0x0089);
343
344          if(!($values & 0x87))
345          {
346            $returned[]=$tag['tagValues.specialValues'][0x00];
347          }
348
349          if(preg_match("/.*d70.*/i",GlobalTags::getExifMaker()))
350          {
351            $bit5=1;
352          }
353          else
354          {
355            $bit5=0;
356          }
357
358          if($values)
359          {
360            foreach($tag['tagValues.specialValues'] as $key => $val)
361            {
362              if((($values & $key) == $key) && ($key!=0x00))
363              {
364                if($key==0x20)
365                {
366                  $returned[]=$val[$bit5];
367                }
368                else
369                {
370                  $returned[]=$val;
371                }
372              }
373            }
374          }
375          unset($tag);
376          break;
377        case 0x0098: // "LensData"
378          if(($this->shutterCount==-1 or $this->serialNumber=="") and
379            ( substr($values,0,2)=="02" ))
380          {
381            $this->toDecode[0x0098]=Array($values, $type);
382          }
383          $returned=$this->readLensData($values);
384          break;
385        case 0x0099: // "RawImageCenter"
386          $returned=Array(
387            'x' => $values[0],
388            'y' => $values[1],
389          );
390          break;
391        case 0x009a: // "SensorPixelSize"
392          if($values[0][1]==0) $values[0][1]=1;
393          if($values[1][1]==0) $values[1][1]=1;
394
395          $returned=sprintf("%.1f x %.1f µm", ($values[0][0]/$values[0][1]), ($values[1][0]/$values[1][1]));
396          break;
397        default:
398          $returned="Not yet implemented;".ConvertData::toHexDump($tagId, ByteType::USHORT)." => ".ConvertData::toHexDump($values, $type);
399          break;
400      }
401      return($returned);
402    }
403
404    /**
405     * this function is used to decrypt datas from the Nikon "LensData" tag
406     *
407     * @param String $data : data from the exif.Nikon.LensData metadata
408     * @return Array : list of properties + lens name (computed)
409     */
410    private function readLensData($data)
411    {
412      $returned="";
413      $nfo=Array();
414      $dataReader=new Data($data, $this->byteOrder);
415
416      $nfo['LensDataVersion']=$dataReader->readASCII(4);
417
418      if(substr($nfo['LensDataVersion'],0,2)=="02")
419      {
420        // in this case, data are encrypted
421        $decrypted=$nfo['LensDataVersion'].$this->decryptData($this->serialNumberInteger(), $this->shutterCount,$dataReader->readASCII(-1,4));
422        $dataReader->setData($decrypted);
423      }
424
425      switch($nfo['LensDataVersion'])
426      {
427        case '0100' :
428            $nfo['LensIDNumber']=$dataReader->readUByte(6);
429            $nfo['LensFStops']=$dataReader->readUByte(7);
430            $nfo['MinFocalLength']=$dataReader->readUByte(8);
431            $nfo['MaxFocalLength']=$dataReader->readUByte(9);
432            $nfo['MaxApertureAtMinFocal']=$dataReader->readUByte(10);
433            $nfo['MaxApertureAtMaxFocal']=$dataReader->readUByte(11);
434            $nfo['MCUVersion']=$dataReader->readUByte(12);
435          break;
436        case '0101' :
437        case '0201' :
438        case '0202' :
439        case '0203' :
440            $nfo['LensIDNumber']=$dataReader->readUByte(11);
441            $nfo['LensFStops']=$dataReader->readUByte(12);
442            $nfo['MinFocalLength']=$dataReader->readUByte(13);
443            $nfo['MaxFocalLength']=$dataReader->readUByte(14);
444            $nfo['MaxApertureAtMinFocal']=$dataReader->readUByte(15);
445            $nfo['MaxApertureAtMaxFocal']=$dataReader->readUByte(16);
446            $nfo['MCUVersion']=$dataReader->readUByte(17);
447          break;
448        case '0204' :
449            $nfo['LensIDNumber']=$dataReader->readUByte(12);
450            $nfo['LensFStops']=$dataReader->readUByte(13);
451            $nfo['MinFocalLength']=$dataReader->readUByte(14);
452            $nfo['MaxFocalLength']=$dataReader->readUByte(15);
453            $nfo['MaxApertureAtMinFocal']=$dataReader->readUByte(16);
454            $nfo['MaxApertureAtMaxFocal']=$dataReader->readUByte(17);
455            $nfo['MCUVersion']=$dataReader->readUByte(18);
456          break;
457      }
458
459      $keyLens = sprintf("%02X %02X %02X %02X %02X %02X %02X %02X",
460        $nfo['LensIDNumber'],
461        $nfo['LensFStops'],
462        $nfo['MinFocalLength'],
463        $nfo['MaxFocalLength'],
464        $nfo['MaxApertureAtMinFocal'],
465        $nfo['MaxApertureAtMaxFocal'],
466        $nfo['MCUVersion'],
467        $this->getTagById(0x0083)->getValue()
468      );
469
470      $tag=$this->tagDef->getTagById(0x0098);
471      if(array_key_exists($keyLens, $tag['tagValues.lenses']))
472      {
473        $returned = $tag['tagValues.lenses'][$keyLens];
474      }
475      else
476      {
477        $returned = $tag['tagValues.lenses']['unknown']." (".$keyLens." / ".$nfo['LensDataVersion'].")";
478      }
479
480      if(is_array($returned))
481        $returned=$returned[0];
482
483      unset($data);
484      unset($nfo);
485      return($returned);
486    }
487
488    /**
489     * Nikon encrypt some data
490     * This function is used to decrypt them. Don't ask anything about "how does
491     * it work" abd "what's it doing", I just translated the C++ & Perl code
492     * from Exiv2, Exiftool & Raw Photo Parser (Copyright 2004-2006 Dave Coffin)
493     *
494     * @param Integer $serialNumber : the camera serial number, in Integer
495     *                                format (from the 0x001d tag, not the 0x00a0)
496     * @param Integer $shutterCount : shutterCount value in the file
497     * @param String $data : data to decrypt
498     * @param Integer $decryptedLength : number of byte to decrypt
499     * @return String : the decrypted data
500     */
501    private function decryptData($serialNumber, $shutterCount, $data, $decryptedLength=0)
502    {
503      $xlat = Array(
504                Array(0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d,
505                      0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d,
506                      0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f,
507                      0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f,
508                      0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1,
509                      0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17,
510                      0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89,
511                      0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f,
512                      0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b,
513                      0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb,
514                      0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3,
515                      0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f,
516                      0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35,
517                      0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43,
518                      0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5,
519                      0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7),
520                Array(0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c,
521                      0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34,
522                      0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad,
523                      0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05,
524                      0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee,
525                      0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d,
526                      0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b,
527                      0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b,
528                      0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc,
529                      0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33,
530                      0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8,
531                      0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6,
532                      0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c,
533                      0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49,
534                      0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb,
535                      0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f)
536              );
537      $returned="";
538
539      if($decryptedLength==0 or $decryptedLength>strlen($data))
540        $decryptedLength=strlen($data);
541
542      $key = 0;
543      for($i=0; $i < 4; $i++)
544      {
545        $key = $key ^ (($shutterCount >> ($i*8)) & 0xff);
546      }
547      $ci = $xlat[0][$serialNumber & 0xff];
548      $cj = $xlat[1][$key];
549      $ck = 0x60;
550
551      for($i=0;$i<$decryptedLength;++$i)
552      {
553        $cj+=$ci*$ck++;
554        $returned.= chr(ord($data{$i}) ^ $cj);
555      }
556      return($returned);
557    }
558
559    /**
560     * return the serialNumber as an integer
561     */
562    private function serialNumberInteger()
563    {
564      if(trim($this->serialNumber)!="")
565      {
566        return(0+$this->serialNumber);
567      }
568      elseif(preg_match("/.*d50.*/i",GlobalTags::getExifMaker()))
569      {
570        //D50
571        return(0x22);
572      }
573      else
574      {
575        //D200, D40X, ...
576        return(0x60);
577      }
578    }
579  }
580
581
582?>
Note: See TracBrowser for help on using the repository browser.