<?php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org>               //
//  available at http://getid3.sourceforge.net                 //
//            or http://www.getid3.org                         //
//          also https://github.com/JamesHeinrich/getID3       //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details                             //
/////////////////////////////////////////////////////////////////
//                                                             //
// module.graphic.png.php                                      //
// module for analyzing PNG Image files                        //
// dependencies: NONE                                          //
//                                                            ///
/////////////////////////////////////////////////////////////////


class getid3_png extends getid3_handler
{
    public 
$max_data_bytes 10000000// if data chunk is larger than this do not read it completely (getID3 only needs the first few dozen bytes for parsing)

    
public function Analyze() {

        
$info = &$this->getid3->info;

        
// shortcut
        
$info['png'] = array();
        
$thisfile_png = &$info['png'];

        
$info['fileformat']          = 'png';
        
$info['video']['dataformat'] = 'png';
        
$info['video']['lossless']   = false;

        
$this->fseek($info['avdataoffset']);
        
$PNGfiledata $this->fread($this->getid3->fread_buffer_size());
        
$offset 0;

        
$PNGidentifier substr($PNGfiledata$offset8); // $89 $50 $4E $47 $0D $0A $1A $0A
        
$offset += 8;

        if (
$PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") {
            
$info['error'][] = 'First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier';
            unset(
$info['fileformat']);
            return 
false;
        }

        while (((
$this->ftell() - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) {
            
$chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata$offset4));
            if (
$chunk['data_length'] === false) {
                
$info['error'][] = 'Failed to read data_length at offset '.$offset;
                return 
false;
            }
            
$offset += 4;
            
$truncated_data false;
            while (((
strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && ($this->ftell() < $info['filesize'])) {
                if (
strlen($PNGfiledata) < $this->max_data_bytes) {
                    
$PNGfiledata .= $this->fread($this->getid3->fread_buffer_size());
                } else {
                    
$info['warning'][] = 'At offset '.$offset.' chunk "'.substr($PNGfiledata$offset4).'" exceeded max_data_bytes value of '.$this->max_data_bytes.', data chunk will be truncated at '.(strlen($PNGfiledata) - 8).' bytes';
                    break;
                }
            }
            
$chunk['type_text']   =                           substr($PNGfiledata$offset4);
            
$offset += 4;
            
$chunk['type_raw']    = getid3_lib::BigEndian2Int($chunk['type_text']);
            
$chunk['data']        =                           substr($PNGfiledata$offset$chunk['data_length']);
            
$offset += $chunk['data_length'];
            
$chunk['crc']         = getid3_lib::BigEndian2Int(substr($PNGfiledata$offset4));
            
$offset += 4;

            
$chunk['flags']['ancilliary']   = (bool) ($chunk['type_raw'] & 0x20000000);
            
$chunk['flags']['private']      = (bool) ($chunk['type_raw'] & 0x00200000);
            
$chunk['flags']['reserved']     = (bool) ($chunk['type_raw'] & 0x00002000);
            
$chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020);

            
// shortcut
            
$thisfile_png[$chunk['type_text']] = array();
            
$thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']];

            switch (
$chunk['type_text']) {

                case 
'IHDR'// Image Header
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    
$thisfile_png_chunk_type_text['width']                     = getid3_lib::BigEndian2Int(substr($chunk['data'],  04));
                    
$thisfile_png_chunk_type_text['height']                    = getid3_lib::BigEndian2Int(substr($chunk['data'],  44));
                    
$thisfile_png_chunk_type_text['raw']['bit_depth']          = getid3_lib::BigEndian2Int(substr($chunk['data'],  81));
                    
$thisfile_png_chunk_type_text['raw']['color_type']         = getid3_lib::BigEndian2Int(substr($chunk['data'],  91));
                    
$thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 101));
                    
$thisfile_png_chunk_type_text['raw']['filter_method']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 111));
                    
$thisfile_png_chunk_type_text['raw']['interlace_method']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 121));

                    
$thisfile_png_chunk_type_text['compression_method_text']   = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']);
                    
$thisfile_png_chunk_type_text['color_type']['palette']     = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01);
                    
$thisfile_png_chunk_type_text['color_type']['true_color']  = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02);
                    
$thisfile_png_chunk_type_text['color_type']['alpha']       = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04);

                    
$info['video']['resolution_x']    = $thisfile_png_chunk_type_text['width'];
                    
$info['video']['resolution_y']    = $thisfile_png_chunk_type_text['height'];

                    
$info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']);
                    break;


                case 
'PLTE'// Palette
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    
$paletteoffset 0;
                    for (
$i 0$i <= 255$i++) {
                        
//$thisfile_png_chunk_type_text['red'][$i]   = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                        //$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                        //$thisfile_png_chunk_type_text['blue'][$i]  = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                        
$red   getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                        
$green getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                        
$blue  getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1));
                        
$thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue));
                    }
                    break;


                case 
'tRNS'// Transparency
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    switch (
$thisfile_png['IHDR']['raw']['color_type']) {
                        case 
0:
                            
$thisfile_png_chunk_type_text['transparent_color_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 02));
                            break;

                        case 
2:
                            
$thisfile_png_chunk_type_text['transparent_color_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 02));
                            
$thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 22));
                            
$thisfile_png_chunk_type_text['transparent_color_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 42));
                            break;

                        case 
3:
                            for (
$i 0$i strlen($chunk['data']); $i++) {
                                
$thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i1));
                            }
                            break;

                        case 
4:
                        case 
6:
                            
$info['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];

                        default:
                            
$info['warning'][] = 'Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type'];
                            break;
                    }
                    break;


                case 
'gAMA'// Image Gamma
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    
$thisfile_png_chunk_type_text['gamma']  = getid3_lib::BigEndian2Int($chunk['data']) / 100000;
                    break;


                case 
'cHRM'// Primary Chromaticities
                    
$thisfile_png_chunk_type_text['header']  = $chunk;
                    
$thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'],  04)) / 100000;
                    
$thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'],  44)) / 100000;
                    
$thisfile_png_chunk_type_text['red_y']   = getid3_lib::BigEndian2Int(substr($chunk['data'],  84)) / 100000;
                    
$thisfile_png_chunk_type_text['red_y']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 124)) / 100000;
                    
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 164)) / 100000;
                    
$thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 204)) / 100000;
                    
$thisfile_png_chunk_type_text['blue_y']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 244)) / 100000;
                    
$thisfile_png_chunk_type_text['blue_y']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 284)) / 100000;
                    break;


                case 
'sRGB'// Standard RGB Color Space
                    
$thisfile_png_chunk_type_text['header']                 = $chunk;
                    
$thisfile_png_chunk_type_text['reindering_intent']      = getid3_lib::BigEndian2Int($chunk['data']);
                    
$thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']);
                    break;


                case 
'iCCP'// Embedded ICC Profile
                    
$thisfile_png_chunk_type_text['header']                  = $chunk;
                    list(
$profilename$compressiondata)                     = explode("\x00"$chunk['data'], 2);
                    
$thisfile_png_chunk_type_text['profile_name']            = $profilename;
                    
$thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($compressiondata01));
                    
$thisfile_png_chunk_type_text['compression_profile']     = substr($compressiondata1);

                    
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
                    break;


                case 
'tEXt'// Textual Data
                    
$thisfile_png_chunk_type_text['header']  = $chunk;
                    list(
$keyword$text) = explode("\x00"$chunk['data'], 2);
                    
$thisfile_png_chunk_type_text['keyword'] = $keyword;
                    
$thisfile_png_chunk_type_text['text']    = $text;

                    
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
                    break;


                case 
'zTXt'// Compressed Textual Data
                    
$thisfile_png_chunk_type_text['header']                  = $chunk;
                    list(
$keyword$otherdata)                               = explode("\x00"$chunk['data'], 2);
                    
$thisfile_png_chunk_type_text['keyword']                 = $keyword;
                    
$thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($otherdata01));
                    
$thisfile_png_chunk_type_text['compressed_text']         = substr($otherdata1);
                    
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
                    switch (
$thisfile_png_chunk_type_text['compression_method']) {
                        case 
0:
                            
$thisfile_png_chunk_type_text['text']            = gzuncompress($thisfile_png_chunk_type_text['compressed_text']);
                            break;

                        default:
                            
// unknown compression method
                            
break;
                    }

                    if (isset(
$thisfile_png_chunk_type_text['text'])) {
                        
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
                    }
                    break;


                case 
'iTXt'// International Textual Data
                    
$thisfile_png_chunk_type_text['header']                  = $chunk;
                    list(
$keyword$otherdata)                               = explode("\x00"$chunk['data'], 2);
                    
$thisfile_png_chunk_type_text['keyword']                 = $keyword;
                    
$thisfile_png_chunk_type_text['compression']             = (bool) getid3_lib::BigEndian2Int(substr($otherdata01));
                    
$thisfile_png_chunk_type_text['compression_method']      = getid3_lib::BigEndian2Int(substr($otherdata11));
                    
$thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']);
                    list(
$languagetag$translatedkeyword$text)                        = explode("\x00"substr($otherdata2), 3);
                    
$thisfile_png_chunk_type_text['language_tag']            = $languagetag;
                    
$thisfile_png_chunk_type_text['translated_keyword']      = $translatedkeyword;

                    if (
$thisfile_png_chunk_type_text['compression']) {

                        switch (
$thisfile_png_chunk_type_text['compression_method']) {
                            case 
0:
                                
$thisfile_png_chunk_type_text['text']        = gzuncompress($text);
                                break;

                            default:
                                
// unknown compression method
                                
break;
                        }

                    } else {

                        
$thisfile_png_chunk_type_text['text']                = $text;

                    }

                    if (isset(
$thisfile_png_chunk_type_text['text'])) {
                        
$thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text'];
                    }
                    break;


                case 
'bKGD'// Background Color
                    
$thisfile_png_chunk_type_text['header']                   = $chunk;
                    switch (
$thisfile_png['IHDR']['raw']['color_type']) {
                        case 
0:
                        case 
4:
                            
$thisfile_png_chunk_type_text['background_gray']  = getid3_lib::BigEndian2Int($chunk['data']);
                            break;

                        case 
2:
                        case 
6:
                            
$thisfile_png_chunk_type_text['background_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
                            
$thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
                            
$thisfile_png_chunk_type_text['background_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth']));
                            break;

                        case 
3:
                            
$thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']);
                            break;

                        default:
                            break;
                    }
                    break;


                case 
'pHYs'// Physical Pixel Dimensions
                    
$thisfile_png_chunk_type_text['header']                 = $chunk;
                    
$thisfile_png_chunk_type_text['pixels_per_unit_x']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 04));
                    
$thisfile_png_chunk_type_text['pixels_per_unit_y']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 44));
                    
$thisfile_png_chunk_type_text['unit_specifier']         = getid3_lib::BigEndian2Int(substr($chunk['data'], 81));
                    
$thisfile_png_chunk_type_text['unit']                   = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
                    break;


                case 
'sBIT'// Significant Bits
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    switch (
$thisfile_png['IHDR']['raw']['color_type']) {
                        case 
0:
                            
$thisfile_png_chunk_type_text['significant_bits_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 01));
                            break;

                        case 
2:
                        case 
3:
                            
$thisfile_png_chunk_type_text['significant_bits_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 01));
                            
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11));
                            
$thisfile_png_chunk_type_text['significant_bits_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 21));
                            break;

                        case 
4:
                            
$thisfile_png_chunk_type_text['significant_bits_gray']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 01));
                            
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11));
                            break;

                        case 
6:
                            
$thisfile_png_chunk_type_text['significant_bits_red']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 01));
                            
$thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11));
                            
$thisfile_png_chunk_type_text['significant_bits_blue']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 21));
                            
$thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 31));
                            break;

                        default:
                            break;
                    }
                    break;


                case 
'sPLT'// Suggested Palette
                    
$thisfile_png_chunk_type_text['header']                           = $chunk;
                    list(
$palettename$otherdata)                                    = explode("\x00"$chunk['data'], 2);
                    
$thisfile_png_chunk_type_text['palette_name']                     = $palettename;
                    
$sPLToffset 0;
                    
$thisfile_png_chunk_type_text['sample_depth_bits']                = getid3_lib::BigEndian2Int(substr($otherdata$sPLToffset1));
                    
$sPLToffset += 1;
                    
$thisfile_png_chunk_type_text['sample_depth_bytes']               = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8;
                    
$paletteCounter 0;
                    while (
$sPLToffset strlen($otherdata)) {
                        
$thisfile_png_chunk_type_text['red'][$paletteCounter]       = getid3_lib::BigEndian2Int(substr($otherdata$sPLToffset$thisfile_png_chunk_type_text['sample_depth_bytes']));
                        
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                        
$thisfile_png_chunk_type_text['green'][$paletteCounter]     = getid3_lib::BigEndian2Int(substr($otherdata$sPLToffset$thisfile_png_chunk_type_text['sample_depth_bytes']));
                        
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                        
$thisfile_png_chunk_type_text['blue'][$paletteCounter]      = getid3_lib::BigEndian2Int(substr($otherdata$sPLToffset$thisfile_png_chunk_type_text['sample_depth_bytes']));
                        
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                        
$thisfile_png_chunk_type_text['alpha'][$paletteCounter]     = getid3_lib::BigEndian2Int(substr($otherdata$sPLToffset$thisfile_png_chunk_type_text['sample_depth_bytes']));
                        
$sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes'];
                        
$thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata$sPLToffset2));
                        
$sPLToffset += 2;
                        
$paletteCounter++;
                    }
                    break;


                case 
'hIST'// Palette Histogram
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    
$hISTcounter 0;
                    while (
$hISTcounter strlen($chunk['data'])) {
                        
$thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter 22));
                        
$hISTcounter += 2;
                    }
                    break;


                case 
'tIME'// Image Last-Modification Time
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    
$thisfile_png_chunk_type_text['year']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 02));
                    
$thisfile_png_chunk_type_text['month']  = getid3_lib::BigEndian2Int(substr($chunk['data'], 21));
                    
$thisfile_png_chunk_type_text['day']    = getid3_lib::BigEndian2Int(substr($chunk['data'], 31));
                    
$thisfile_png_chunk_type_text['hour']   = getid3_lib::BigEndian2Int(substr($chunk['data'], 41));
                    
$thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 51));
                    
$thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 61));
                    
$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']);
                    break;


                case 
'oFFs'// Image Offset
                    
$thisfile_png_chunk_type_text['header']         = $chunk;
                    
$thisfile_png_chunk_type_text['position_x']     = getid3_lib::BigEndian2Int(substr($chunk['data'], 04), falsetrue);
                    
$thisfile_png_chunk_type_text['position_y']     = getid3_lib::BigEndian2Int(substr($chunk['data'], 44), falsetrue);
                    
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 81));
                    
$thisfile_png_chunk_type_text['unit']           = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
                    break;


                case 
'pCAL'// Calibration Of Pixel Values
                    
$thisfile_png_chunk_type_text['header']             = $chunk;
                    list(
$calibrationname$otherdata)                              = explode("\x00"$chunk['data'], 2);
                    
$thisfile_png_chunk_type_text['calibration_name']   = $calibrationname;
                    
$pCALoffset 0;
                    
$thisfile_png_chunk_type_text['original_zero']      = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset4), falsetrue);
                    
$pCALoffset += 4;
                    
$thisfile_png_chunk_type_text['original_max']       = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset4), falsetrue);
                    
$pCALoffset += 4;
                    
$thisfile_png_chunk_type_text['equation_type']      = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset1));
                    
$pCALoffset += 1;
                    
$thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']);
                    
$thisfile_png_chunk_type_text['parameter_count']    = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset1));
                    
$pCALoffset += 1;
                    
$thisfile_png_chunk_type_text['parameters']         = explode("\x00"substr($chunk['data'], $pCALoffset));
                    break;


                case 
'sCAL'// Physical Scale Of Image Subject
                    
$thisfile_png_chunk_type_text['header']         = $chunk;
                    
$thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 01));
                    
$thisfile_png_chunk_type_text['unit']           = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']);
                    list(
$pixelwidth$pixelheight)                             = explode("\x00"substr($chunk['data'], 1));
                    
$thisfile_png_chunk_type_text['pixel_width']    = $pixelwidth;
                    
$thisfile_png_chunk_type_text['pixel_height']   = $pixelheight;
                    break;


                case 
'gIFg'// GIF Graphic Control Extension
                    
$gIFgCounter 0;
                    if (isset(
$thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
                        
$gIFgCounter count($thisfile_png_chunk_type_text);
                    }
                    
$thisfile_png_chunk_type_text[$gIFgCounter]['header']          = $chunk;
                    
$thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 01));
                    
$thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11));
                    
$thisfile_png_chunk_type_text[$gIFgCounter]['delay_time']      = getid3_lib::BigEndian2Int(substr($chunk['data'], 22));
                    break;


                case 
'gIFx'// GIF Application Extension
                    
$gIFxCounter 0;
                    if (isset(
$thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) {
                        
$gIFxCounter count($thisfile_png_chunk_type_text);
                    }
                    
$thisfile_png_chunk_type_text[$gIFxCounter]['header']                 = $chunk;
                    
$thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'],  08);
                    
$thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code']    = substr($chunk['data'],  83);
                    
$thisfile_png_chunk_type_text[$gIFxCounter]['application_data']       = substr($chunk['data'], 11);
                    break;


                case 
'IDAT'// Image Data
                    
$idatinformationfieldindex 0;
                    if (isset(
$thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) {
                        
$idatinformationfieldindex count($thisfile_png['IDAT']);
                    }
                    unset(
$chunk['data']);
                    
$thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk;
                    break;


                case 
'IEND'// Image Trailer
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    break;


                default:
                    
//unset($chunk['data']);
                    
$thisfile_png_chunk_type_text['header'] = $chunk;
                    
$info['warning'][] = 'Unhandled chunk type: '.$chunk['type_text'];
                    break;
            }
        }

        return 
true;
    }

    public function 
PNGsRGBintentLookup($sRGB) {
        static 
$PNGsRGBintentLookup = array(
            
=> 'Perceptual',
            
=> 'Relative colorimetric',
            
=> 'Saturation',
            
=> 'Absolute colorimetric'
        
);
        return (isset(
$PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid');
    }

    public function 
PNGcompressionMethodLookup($compressionmethod) {
        static 
$PNGcompressionMethodLookup = array(
            
=> 'deflate/inflate'
        
);
        return (isset(
$PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid');
    }

    public function 
PNGpHYsUnitLookup($unitid) {
        static 
$PNGpHYsUnitLookup = array(
            
=> 'unknown',
            
=> 'meter'
        
);
        return (isset(
$PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid');
    }

    public function 
PNGoFFsUnitLookup($unitid) {
        static 
$PNGoFFsUnitLookup = array(
            
=> 'pixel',
            
=> 'micrometer'
        
);
        return (isset(
$PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid');
    }

    public function 
PNGpCALequationTypeLookup($equationtype) {
        static 
$PNGpCALequationTypeLookup = array(
            
=> 'Linear mapping',
            
=> 'Base-e exponential mapping',
            
=> 'Arbitrary-base exponential mapping',
            
=> 'Hyperbolic mapping'
        
);
        return (isset(
$PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid');
    }

    public function 
PNGsCALUnitLookup($unitid) {
        static 
$PNGsCALUnitLookup = array(
            
=> 'meter',
            
=> 'radian'
        
);
        return (isset(
$PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid');
    }

    public function 
IHDRcalculateBitsPerSample($color_type$bit_depth) {
        switch (
$color_type) {
            case 
0// Each pixel is a grayscale sample.
                
return $bit_depth;
                break;

            case 
2// Each pixel is an R,G,B triple
                
return $bit_depth;
                break;

            case 
3// Each pixel is a palette index; a PLTE chunk must appear.
                
return $bit_depth;
                break;

            case 
4// Each pixel is a grayscale sample, followed by an alpha sample.
                
return $bit_depth;
                break;

            case 
6// Each pixel is an R,G,B triple, followed by an alpha sample.
                
return $bit_depth;
                break;
        }
        return 
false;
    }

}