You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							165 lines
						
					
					
						
							5.9 KiB
						
					
					
				
			
		
		
	
	
							165 lines
						
					
					
						
							5.9 KiB
						
					
					
				<?php
 | 
						|
 | 
						|
/**
 | 
						|
 * Php library to Bake the PNG Images
 | 
						|
 * 
 | 
						|
 */
 | 
						|
class PNGImageBaker
 | 
						|
{
 | 
						|
    private $_contents;
 | 
						|
    private $_size;
 | 
						|
    private $_chunks;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Prepares file for handling metadata.
 | 
						|
     * Verifies that this file is a valid PNG file.
 | 
						|
     * Unpacks file chunks and reads them into an array.
 | 
						|
     *
 | 
						|
     * @param string $contents File content as a string
 | 
						|
     */
 | 
						|
    public function __construct($contents) {
 | 
						|
        $this->_contents = $contents;
 | 
						|
        $png_signature = pack("C8", 137, 80, 78, 71, 13, 10, 26, 10);
 | 
						|
        // Read 8 bytes of PNG header and verify.
 | 
						|
        $header = substr($this->_contents, 0, 8);
 | 
						|
        if ($header != $png_signature) {
 | 
						|
            echo 'This is not a valid PNG image';
 | 
						|
        }
 | 
						|
        $this->_size = strlen($this->_contents);
 | 
						|
        $this->_chunks = array();
 | 
						|
        // Skip 8 bytes of IHDR image header.
 | 
						|
        $position = 8;
 | 
						|
        do {
 | 
						|
            $chunk = @unpack('Nsize/a4type', substr($this->_contents, $position, 8));
 | 
						|
            $this->_chunks[$chunk['type']][] = substr($this->_contents, $position + 8, $chunk['size']);
 | 
						|
            // Skip 12 bytes chunk overhead.
 | 
						|
            $position += $chunk['size'] + 12;
 | 
						|
        } while ($position < $this->_size);
 | 
						|
    }
 | 
						|
  
 | 
						|
    /**
 | 
						|
     * Checks if a key already exists in the chunk of said type.
 | 
						|
     * We need to avoid writing same keyword into file chunks.
 | 
						|
     *
 | 
						|
     * @param string $type Chunk type, like iTXt, tEXt, etc.
 | 
						|
     * @param string $check Keyword that needs to be checked.
 | 
						|
     *
 | 
						|
     * @return boolean (true|false) True if file is safe to write this keyword, false otherwise.
 | 
						|
     */
 | 
						|
    public function checkChunks($type, $check) {
 | 
						|
        if (array_key_exists($type, $this->_chunks)) {
 | 
						|
            foreach (array_keys($this->_chunks[$type]) as $typekey) {
 | 
						|
                list($key, $data) = explode("\0", $this->_chunks[$type][$typekey]);
 | 
						|
                if (strcmp($key, $check) == 0) {
 | 
						|
                    echo 'Key "' . $check . '" already exists in "' . $type . '" chunk.';
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Add a chunk by type with given key and text
 | 
						|
     *
 | 
						|
     * @param string $chunkType Chunk type, like iTXt, tEXt, etc.
 | 
						|
     * @param string $key Keyword that needs to be added.
 | 
						|
     * @param string $value Currently an assertion URL that is added to an image metadata.
 | 
						|
     *
 | 
						|
     * @return string $result File content with a new chunk as a string.
 | 
						|
     */
 | 
						|
    public function addChunk($chunkType, $key, $value) {
 | 
						|
        
 | 
						|
        $chunkData = $key . "\0" . $value;
 | 
						|
        $crc = pack("N", crc32($chunkType . $chunkData));
 | 
						|
        $len = pack("N", strlen($chunkData));
 | 
						|
        
 | 
						|
        $newChunk = $len . $chunkType . $chunkData . $crc;
 | 
						|
        $result = substr($this->_contents, 0, $this->_size - 12)
 | 
						|
                . $newChunk
 | 
						|
                . substr($this->_contents, $this->_size - 12, 12);
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * removes a chunk by type with given key and text
 | 
						|
     *
 | 
						|
     * @param string $chunkType Chunk type, like iTXt, tEXt, etc.
 | 
						|
     * @param string $key Keyword that needs to be deleted.
 | 
						|
     * @param string $png the png image.
 | 
						|
     *
 | 
						|
     * @return string $result New File content.
 | 
						|
     */
 | 
						|
    public function removeChunks($chunkType, $key, $png) {
 | 
						|
        // Read the magic bytes and verify
 | 
						|
        $retval = substr($png,0,8);
 | 
						|
        $ipos = 8;
 | 
						|
        if ($retval != "\x89PNG\x0d\x0a\x1a\x0a")
 | 
						|
            throw new Exception('Is not a valid PNG image');
 | 
						|
        // Loop through the chunks. Byte 0-3 is length, Byte 4-7 is type
 | 
						|
        $chunkHeader = substr($png,$ipos,8);
 | 
						|
        $ipos = $ipos + 8;
 | 
						|
        while ($chunkHeader) {
 | 
						|
            // Extract length and type from binary data
 | 
						|
            $chunk = @unpack('Nsize/a4type', $chunkHeader);
 | 
						|
            $skip = false;
 | 
						|
            if ( $chunk['type'] == $chunkType ) {
 | 
						|
                $data = substr($png,$ipos,$chunk['size']);
 | 
						|
                $sections = explode("\0", $data);
 | 
						|
                print_r($sections);
 | 
						|
                if ( $sections[0] == $key ) $skip = true;
 | 
						|
            }
 | 
						|
            // Extract the data and the CRC
 | 
						|
            $data = substr($png,$ipos,$chunk['size']+4);
 | 
						|
            $ipos = $ipos + $chunk['size'] + 4;
 | 
						|
            // Add in the header, data, and CRC
 | 
						|
            if ( ! $skip ) $retval = $retval . $chunkHeader . $data;
 | 
						|
            // Read next chunk header
 | 
						|
            $chunkHeader = substr($png,$ipos,8);
 | 
						|
            $ipos = $ipos + 8;
 | 
						|
        }
 | 
						|
        return $retval;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Extracts the baked PNG info by the Key
 | 
						|
     * 
 | 
						|
     * @param string $png the png image
 | 
						|
     * @param string $key Keyword that needs to be searched.
 | 
						|
     * 
 | 
						|
     * @return mixed - If there is an error - boolean false is returned
 | 
						|
     * If there is PNG information that matches the key an array is returned
 | 
						|
     * 
 | 
						|
     */
 | 
						|
    public function extractBadgeInfo($png, $key='openbadges') {
 | 
						|
        // Read the magic bytes and verify
 | 
						|
        $retval = substr($png,0,8);
 | 
						|
        $ipos = 8;
 | 
						|
        if ($retval != "\x89PNG\x0d\x0a\x1a\x0a") {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Loop through the chunks. Byte 0-3 is length, Byte 4-7 is type
 | 
						|
        $chunkHeader = substr($png,$ipos,8);
 | 
						|
        $ipos = $ipos + 8;
 | 
						|
        while ($chunkHeader) {
 | 
						|
            // Extract length and type from binary data
 | 
						|
            $chunk = @unpack('Nsize/a4type', $chunkHeader);
 | 
						|
            $skip = false;
 | 
						|
            if ($chunk['type'] == 'tEXt') {
 | 
						|
                $data = substr($png,$ipos,$chunk['size']);
 | 
						|
                $sections = explode("\0", $data);
 | 
						|
                if ($sections[0] == $key) {
 | 
						|
                   return $sections;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            // Extract the data and the CRC
 | 
						|
            $data = substr($png,$ipos,$chunk['size']+4);
 | 
						|
            $ipos = $ipos + $chunk['size'] + 4;
 | 
						|
 | 
						|
            // Read next chunk header
 | 
						|
            $chunkHeader = substr($png,$ipos,8);
 | 
						|
            $ipos = $ipos + 8;
 | 
						|
        }
 | 
						|
    }
 | 
						|
} |