Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Badge Baker Offline Feature - Refs #7978
- Loading branch information
1 parent
4e1ac21
commit 5ce8a6e
Showing
3 changed files
with
211 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
<?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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters