File indexing completed on 2024-05-12 17:26:00

0001 <?php
0002 /////////////////////////////////////////////////////////////////
0003 /// getID3() by James Heinrich <info@getid3.org>               //
0004 //  available at http://getid3.sourceforge.net                 //
0005 //            or http://www.getid3.org                         //
0006 //          also https://github.com/JamesHeinrich/getID3       //
0007 /////////////////////////////////////////////////////////////////
0008 // See readme.txt for more details                             //
0009 /////////////////////////////////////////////////////////////////
0010 //                                                             //
0011 // module.graphic.png.php                                      //
0012 // module for analyzing PNG Image files                        //
0013 // dependencies: NONE                                          //
0014 //                                                            ///
0015 /////////////////////////////////////////////////////////////////
0016 
0017 
0018 class getid3_png extends getid3_handler
0019 {
0020 
0021   public function Analyze() {
0022     $info = &$this->getid3->info;
0023 
0024     // shortcut
0025     $info['png'] = array();
0026     $thisfile_png = &$info['png'];
0027 
0028     $info['fileformat']          = 'png';
0029     $info['video']['dataformat'] = 'png';
0030     $info['video']['lossless']   = false;
0031 
0032     $this->fseek($info['avdataoffset']);
0033     $PNGfiledata = $this->fread($this->getid3->fread_buffer_size());
0034     $offset = 0;
0035 
0036     $PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A
0037     $offset += 8;
0038 
0039     if ($PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") {
0040       $info['error'][] = 'First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier';
0041       unset($info['fileformat']);
0042       return false;
0043     }
0044 
0045     while ((($this->ftell() - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
0046       $chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
0047       $offset += 4;
0048       while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && ($this->ftell() < $info['filesize'])) {
0049         $PNGfiledata .= $this->fread($this->getid3->fread_buffer_size());
0050       }
0051       $chunk['type_text']   =               substr($PNGfiledata, $offset, 4);
0052       $offset += 4;
0053       $chunk['type_raw']    = getid3_lib::BigEndian2Int($chunk['type_text']);
0054       $chunk['data']        =               substr($PNGfiledata, $offset, $chunk['data_length']);
0055       $offset += $chunk['data_length'];
0056       $chunk['crc']         = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4));
0057       $offset += 4;
0058 
0059       $chunk['flags']['ancilliary']   = (bool) ($chunk['type_raw'] & 0x20000000);
0060       $chunk['flags']['private']      = (bool) ($chunk['type_raw'] & 0x00200000);
0061       $chunk['flags']['reserved']     = (bool) ($chunk['type_raw'] & 0x00002000);
0062       $chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020);
0063 
0064       // shortcut
0065       $thisfile_png[$chunk['type_text']] = array();
0066       $thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']];
0067 
0068       switch ($chunk['type_text']) {
0069 
0070         case 'IHDR': // Image Header
0071           $thisfile_png_chunk_type_text['header'] = $chunk;
0072           $thisfile_png_chunk_type_text['width']                     = getid3_lib::BigEndian2Int(substr($chunk['data'],  0, 4));
0073           $thisfile_png_chunk_type_text['height']                    = getid3_lib::BigEndian2Int(substr($chunk['data'],  4, 4));
0074           $thisfile_png_chunk_type_text['raw']['bit_depth']          = getid3_lib::BigEndian2Int(substr($chunk['data'],  8, 1));
0075           $thisfile_png_chunk_type_text['raw']['color_type']         = getid3_lib::BigEndian2Int(substr($chunk['data'],  9, 1));
0076           $thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 10, 1));
0077           $thisfile_png_chunk_type_text['raw']['filter_method']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 11, 1));
0078           $thisfile_png_chunk_type_text['raw']['interlace_method']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 1));
0079 
0080           $thisfile_png_chunk_type_text['compression_method_text']   = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']);
0081           $thisfile_png_chunk_type_text['color_type']['palette']     = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01);
0082           $thisfile_png_chunk_type_text['color_type']['true_color']  = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02);
0083           $thisfile_png_chunk_type_text['color_type']['alpha']       = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04);
0084 
0085           $info['video']['resolution_x']    = $thisfile_png_chunk_type_text['width'];
0086           $info['video']['resolution_y']    = $thisfile_png_chunk_type_text['height'];
0087 
0088           $info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']);
0089           break;
0090 
0091 
0092         case 'PLTE': // Palette
0093           $thisfile_png_chunk_type_text['header'] = $chunk;
0094           $paletteoffset = 0;
0095           for ($i = 0; $i <= 255; $i++) {
0096             //$thisfile_png_chunk_type_text['red'][$i]   = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
0097             //$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
0098             //$thisfile_png_chunk_type_text['blue'][$i]  = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
0099             $red   = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
0100             $green = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
0101             $blue  = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
0102             $thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue));
0103           }
0104           break;
0105 
0106 
0107         case 'tRNS': // Transparency
0108           $thisfile_png_chunk_type_text['header'] = $chunk;
0109           switch ($thisfile_png['IHDR']['raw']['color_type']) {
0110             case 0:
0111               $thisfile_png_chunk_type_text['transparent_color_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
0112               break;
0113 
0114             case 2:
0115               $thisfile_png_chunk_type_text['transparent_color_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
0116               $thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
0117               $thisfile_png_chunk_type_text['transparent_color_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 2));
0118               break;
0119 
0120             case 3:
0121               for ($i = 0; $i < strlen($chunk['data']); $i++) {
0122                 $thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i, 1));
0123               }
0124               break;
0125 
0126             case 4:
0127             case 6:
0128               $info['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
0129 
0130             default:
0131               $info['warning'][] = 'Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
0132               break;
0133           }
0134           break;
0135 
0136 
0137         case 'gAMA': // Image Gamma
0138           $thisfile_png_chunk_type_text['header'] = $chunk;
0139           $thisfile_png_chunk_type_text['gamma']  = getid3_lib::BigEndian2Int($chunk['data']) / 100000;
0140           break;
0141 
0142 
0143         case 'cHRM': // Primary Chromaticities
0144           $thisfile_png_chunk_type_text['header']  = $chunk;
0145           $thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'],  0, 4)) / 100000;
0146           $thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'],  4, 4)) / 100000;
0147           $thisfile_png_chunk_type_text['red_y']   = getid3_lib::BigEndian2Int(substr($chunk['data'],  8, 4)) / 100000;
0148           $thisfile_png_chunk_type_text['red_y']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000;
0149           $thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000;
0150           $thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000;
0151           $thisfile_png_chunk_type_text['blue_y']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000;
0152           $thisfile_png_chunk_type_text['blue_y']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000;
0153           break;
0154 
0155 
0156         case 'sRGB': // Standard RGB Color Space
0157           $thisfile_png_chunk_type_text['header']                 = $chunk;
0158           $thisfile_png_chunk_type_text['reindering_intent']      = getid3_lib::BigEndian2Int($chunk['data']);
0159           $thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']);
0160           break;
0161 
0162 
0163         case 'iCCP': // Embedded ICC Profile
0164           $thisfile_png_chunk_type_text['header']                  = $chunk;
0165           list($profilename, $compressiondata)                                 = explode("\x00", $chunk['data'], 2);
0166           $thisfile_png_chunk_type_text['profile_name']            = $profilename;
0167           $thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1));
0168           $thisfile_png_chunk_type_text['compression_profile']     = substr($compressiondata, 1);
0169 
0170           $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
0171           break;
0172 
0173 
0174         case 'tEXt': // Textual Data
0175           $thisfile_png_chunk_type_text['header']  = $chunk;
0176           list($keyword, $text)                                = explode("\x00", $chunk['data'], 2);
0177           $thisfile_png_chunk_type_text['keyword'] = $keyword;
0178           $thisfile_png_chunk_type_text['text']    = $text;
0179 
0180           $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
0181           break;
0182 
0183 
0184         case 'zTXt': // Compressed Textual Data
0185           $thisfile_png_chunk_type_text['header']                  = $chunk;
0186           list($keyword, $otherdata)                                           = explode("\x00", $chunk['data'], 2);
0187           $thisfile_png_chunk_type_text['keyword']                 = $keyword;
0188           $thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
0189           $thisfile_png_chunk_type_text['compressed_text']         = substr($otherdata, 1);
0190           $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
0191           switch ($thisfile_png_chunk_type_text['compression_method']) {
0192             case 0:
0193               $thisfile_png_chunk_type_text['text']            = gzuncompress($thisfile_png_chunk_type_text['compressed_text']);
0194               break;
0195 
0196             default:
0197               // unknown compression method
0198               break;
0199           }
0200 
0201           if (isset($thisfile_png_chunk_type_text['text'])) {
0202             $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
0203           }
0204           break;
0205 
0206 
0207         case 'iTXt': // International Textual Data
0208           $thisfile_png_chunk_type_text['header']                  = $chunk;
0209           list($keyword, $otherdata)                                           = explode("\x00", $chunk['data'], 2);
0210           $thisfile_png_chunk_type_text['keyword']                 = $keyword;
0211           $thisfile_png_chunk_type_text['compression']             = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1));
0212           $thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1));
0213           $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
0214           list($languagetag, $translatedkeyword, $text)                        = explode("\x00", substr($otherdata, 2), 3);
0215           $thisfile_png_chunk_type_text['language_tag']            = $languagetag;
0216           $thisfile_png_chunk_type_text['translated_keyword']      = $translatedkeyword;
0217 
0218           if ($thisfile_png_chunk_type_text['compression']) {
0219 
0220             switch ($thisfile_png_chunk_type_text['compression_method']) {
0221               case 0:
0222                 $thisfile_png_chunk_type_text['text']        = gzuncompress($text);
0223                 break;
0224 
0225               default:
0226                 // unknown compression method
0227                 break;
0228             }
0229 
0230           } else {
0231 
0232             $thisfile_png_chunk_type_text['text']                = $text;
0233 
0234           }
0235 
0236           if (isset($thisfile_png_chunk_type_text['text'])) {
0237             $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
0238           }
0239           break;
0240 
0241 
0242         case 'bKGD': // Background Color
0243           $thisfile_png_chunk_type_text['header']                   = $chunk;
0244           switch ($thisfile_png['IHDR']['raw']['color_type']) {
0245             case 0:
0246             case 4:
0247               $thisfile_png_chunk_type_text['background_gray']  = getid3_lib::BigEndian2Int($chunk['data']);
0248               break;
0249 
0250             case 2:
0251             case 6:
0252               $thisfile_png_chunk_type_text['background_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
0253               $thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
0254               $thisfile_png_chunk_type_text['background_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
0255               break;
0256 
0257             case 3:
0258               $thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']);
0259               break;
0260 
0261             default:
0262               break;
0263           }
0264           break;
0265 
0266 
0267         case 'pHYs': // Physical Pixel Dimensions
0268           $thisfile_png_chunk_type_text['header']                 = $chunk;
0269           $thisfile_png_chunk_type_text['pixels_per_unit_x']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4));
0270           $thisfile_png_chunk_type_text['pixels_per_unit_y']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4));
0271           $thisfile_png_chunk_type_text['unit_specifier']         = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
0272           $thisfile_png_chunk_type_text['unit']                   = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
0273           break;
0274 
0275 
0276         case 'sBIT': // Significant Bits
0277           $thisfile_png_chunk_type_text['header'] = $chunk;
0278           switch ($thisfile_png['IHDR']['raw']['color_type']) {
0279             case 0:
0280               $thisfile_png_chunk_type_text['significant_bits_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
0281               break;
0282 
0283             case 2:
0284             case 3:
0285               $thisfile_png_chunk_type_text['significant_bits_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
0286               $thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
0287               $thisfile_png_chunk_type_text['significant_bits_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
0288               break;
0289 
0290             case 4:
0291               $thisfile_png_chunk_type_text['significant_bits_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
0292               $thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
0293               break;
0294 
0295             case 6:
0296               $thisfile_png_chunk_type_text['significant_bits_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
0297               $thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
0298               $thisfile_png_chunk_type_text['significant_bits_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
0299               $thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
0300               break;
0301 
0302             default:
0303               break;
0304           }
0305           break;
0306 
0307 
0308         case 'sPLT': // Suggested Palette
0309           $thisfile_png_chunk_type_text['header']                           = $chunk;
0310           list($palettename, $otherdata)                                                = explode("\x00", $chunk['data'], 2);
0311           $thisfile_png_chunk_type_text['palette_name']                     = $palettename;
0312           $sPLToffset = 0;
0313           $thisfile_png_chunk_type_text['sample_depth_bits']                = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1));
0314           $sPLToffset += 1;
0315           $thisfile_png_chunk_type_text['sample_depth_bytes']               = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8;
0316           $paletteCounter = 0;
0317           while ($sPLToffset < strlen($otherdata)) {
0318             $thisfile_png_chunk_type_text['red'][$paletteCounter]       = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
0319             $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
0320             $thisfile_png_chunk_type_text['green'][$paletteCounter]     = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
0321             $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
0322             $thisfile_png_chunk_type_text['blue'][$paletteCounter]      = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
0323             $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
0324             $thisfile_png_chunk_type_text['alpha'][$paletteCounter]     = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes']));
0325             $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
0326             $thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 2));
0327             $sPLToffset += 2;
0328             $paletteCounter++;
0329           }
0330           break;
0331 
0332 
0333         case 'hIST': // Palette Histogram
0334           $thisfile_png_chunk_type_text['header'] = $chunk;
0335           $hISTcounter = 0;
0336           while ($hISTcounter < strlen($chunk['data'])) {
0337             $thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2));
0338             $hISTcounter += 2;
0339           }
0340           break;
0341 
0342 
0343         case 'tIME': // Image Last-Modification Time
0344           $thisfile_png_chunk_type_text['header'] = $chunk;
0345           $thisfile_png_chunk_type_text['year']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2));
0346           $thisfile_png_chunk_type_text['month']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1));
0347           $thisfile_png_chunk_type_text['day']    = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1));
0348           $thisfile_png_chunk_type_text['hour']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 1));
0349           $thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 5, 1));
0350           $thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 6, 1));
0351           $thisfile_png_chunk_type_text['unix']   = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']);
0352           break;
0353 
0354 
0355         case 'oFFs': // Image Offset
0356           $thisfile_png_chunk_type_text['header']         = $chunk;
0357           $thisfile_png_chunk_type_text['position_x']     = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4), false, true);
0358           $thisfile_png_chunk_type_text['position_y']     = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4), false, true);
0359           $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1));
0360           $thisfile_png_chunk_type_text['unit']           = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
0361           break;
0362 
0363 
0364         case 'pCAL': // Calibration Of Pixel Values
0365           $thisfile_png_chunk_type_text['header']             = $chunk;
0366           list($calibrationname, $otherdata)                              = explode("\x00", $chunk['data'], 2);
0367           $thisfile_png_chunk_type_text['calibration_name']   = $calibrationname;
0368           $pCALoffset = 0;
0369           $thisfile_png_chunk_type_text['original_zero']      = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
0370           $pCALoffset += 4;
0371           $thisfile_png_chunk_type_text['original_max']       = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true);
0372           $pCALoffset += 4;
0373           $thisfile_png_chunk_type_text['equation_type']      = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
0374           $pCALoffset += 1;
0375           $thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']);
0376           $thisfile_png_chunk_type_text['parameter_count']    = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1));
0377           $pCALoffset += 1;
0378           $thisfile_png_chunk_type_text['parameters']         = explode("\x00", substr($chunk['data'], $pCALoffset));
0379           break;
0380 
0381 
0382         case 'sCAL': // Physical Scale Of Image Subject
0383           $thisfile_png_chunk_type_text['header']         = $chunk;
0384           $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
0385           $thisfile_png_chunk_type_text['unit']           = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
0386           list($pixelwidth, $pixelheight)                             = explode("\x00", substr($chunk['data'], 1));
0387           $thisfile_png_chunk_type_text['pixel_width']    = $pixelwidth;
0388           $thisfile_png_chunk_type_text['pixel_height']   = $pixelheight;
0389           break;
0390 
0391 
0392         case 'gIFg': // GIF Graphic Control Extension
0393           $gIFgCounter = 0;
0394           if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
0395             $gIFgCounter = count($thisfile_png_chunk_type_text);
0396           }
0397           $thisfile_png_chunk_type_text[$gIFgCounter]['header']          = $chunk;
0398           $thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1));
0399           $thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1));
0400           $thisfile_png_chunk_type_text[$gIFgCounter]['delay_time']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2));
0401           break;
0402 
0403 
0404         case 'gIFx': // GIF Application Extension
0405           $gIFxCounter = 0;
0406           if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
0407             $gIFxCounter = count($thisfile_png_chunk_type_text);
0408           }
0409           $thisfile_png_chunk_type_text[$gIFxCounter]['header']                 = $chunk;
0410           $thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'],  0, 8);
0411           $thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code']    = substr($chunk['data'],  8, 3);
0412           $thisfile_png_chunk_type_text[$gIFxCounter]['application_data']       = substr($chunk['data'], 11);
0413           break;
0414 
0415 
0416         case 'IDAT': // Image Data
0417           $idatinformationfieldindex = 0;
0418           if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) {
0419             $idatinformationfieldindex = count($thisfile_png['IDAT']);
0420           }
0421           unset($chunk['data']);
0422           $thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk;
0423           break;
0424 
0425 
0426         case 'IEND': // Image Trailer
0427           $thisfile_png_chunk_type_text['header'] = $chunk;
0428           break;
0429 
0430 
0431         default:
0432           //unset($chunk['data']);
0433           $thisfile_png_chunk_type_text['header'] = $chunk;
0434           $info['warning'][] = 'Unhandled chunk type: '.$chunk['type_text'];
0435           break;
0436       }
0437     }
0438 
0439     return true;
0440   }
0441 
0442   public function PNGsRGBintentLookup($sRGB) {
0443     static $PNGsRGBintentLookup = array(
0444       0 => 'Perceptual',
0445       1 => 'Relative colorimetric',
0446       2 => 'Saturation',
0447       3 => 'Absolute colorimetric'
0448     );
0449     return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid');
0450   }
0451 
0452   public function PNGcompressionMethodLookup($compressionmethod) {
0453     static $PNGcompressionMethodLookup = array(
0454       0 => 'deflate/inflate'
0455     );
0456     return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid');
0457   }
0458 
0459   public function PNGpHYsUnitLookup($unitid) {
0460     static $PNGpHYsUnitLookup = array(
0461       0 => 'unknown',
0462       1 => 'meter'
0463     );
0464     return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid');
0465   }
0466 
0467   public function PNGoFFsUnitLookup($unitid) {
0468     static $PNGoFFsUnitLookup = array(
0469       0 => 'pixel',
0470       1 => 'micrometer'
0471     );
0472     return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid');
0473   }
0474 
0475   public function PNGpCALequationTypeLookup($equationtype) {
0476     static $PNGpCALequationTypeLookup = array(
0477       0 => 'Linear mapping',
0478       1 => 'Base-e exponential mapping',
0479       2 => 'Arbitrary-base exponential mapping',
0480       3 => 'Hyperbolic mapping'
0481     );
0482     return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid');
0483   }
0484 
0485   public function PNGsCALUnitLookup($unitid) {
0486     static $PNGsCALUnitLookup = array(
0487       0 => 'meter',
0488       1 => 'radian'
0489     );
0490     return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid');
0491   }
0492 
0493   public function IHDRcalculateBitsPerSample($color_type, $bit_depth) {
0494     switch ($color_type) {
0495       case 0: // Each pixel is a grayscale sample.
0496         return $bit_depth;
0497         break;
0498 
0499       case 2: // Each pixel is an R,G,B triple
0500         return 3 * $bit_depth;
0501         break;
0502 
0503       case 3: // Each pixel is a palette index; a PLTE chunk must appear.
0504         return $bit_depth;
0505         break;
0506 
0507       case 4: // Each pixel is a grayscale sample, followed by an alpha sample.
0508         return 2 * $bit_depth;
0509         break;
0510 
0511       case 6: // Each pixel is an R,G,B triple, followed by an alpha sample.
0512         return 4 * $bit_depth;
0513         break;
0514     }
0515     return false;
0516   }
0517 
0518 }