Skip to content

Instantly share code, notes, and snippets.

@juban
Last active February 15, 2021 07:20
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save juban/8397183 to your computer and use it in GitHub Desktop.
Save juban/8397183 to your computer and use it in GitHub Desktop.
PHP iOS PNG normalizer. This PHP class can be used to convert an iOS compressed PNG (CgBI format files) back to the standard format. Requires PHP 5.4 or greater. Credit goes to Axel E. Brzostowski for the original Python version of this script: http://www.axelbrz.com.ar/?mod=iphone-png-images-normalizer
<?php
class iOSPNGNormalizer
{
public static function fix($filename, $destfilename = null)
{
try {
$handle = fopen($filename, "rb");
$oldPNG = fread($handle, filesize($filename));
fclose($handle);
$newPng = self::getNormalizedPNG($oldPNG);
if (is_null($destfilename))
$destfilename = $filename;
file_put_contents($destfilename, $newPng);
} catch (Exception $exc) {
return $exc->getMessage();
}
return true;
}
public static function getNormalizedPNG($oldPNG)
{
// Check if the orginal png needs to be processed
$im = @imagecreatefromstring($oldPNG);
if($im !== false)
return $oldPNG;
$pngheader = "\x89PNG\r\n\x1a\n";
if (substr($oldPNG, 0, 8) != $pngheader)
return;
$newPNG = substr($oldPNG, 0, 8);
$chunkPos = 8;
while ($chunkPos < strlen($oldPNG)) {
// Reading chunk
$chunkLength = unpack("N", substr($oldPNG, $chunkPos, $chunkPos + 4));
$chunkLength = array_shift($chunkLength);
$chunkType = substr($oldPNG, $chunkPos + 4, 4);
$chunkData = substr($oldPNG, $chunkPos + 8, $chunkLength);
$chunkCRC = unpack("N", substr($oldPNG, $chunkPos + $chunkLength + 8, 4));
$chunkCRC = array_shift($chunkCRC);
$chunkPos += $chunkLength + 12;
// Reading header chunk
if ($chunkType == 'IHDR') {
$width = unpack("N", substr($chunkData, 0, 4));
$width = array_shift($width);
$height = unpack("N", substr($chunkData, 4, 8));
$height = array_shift($height);
}
// Reading image chunk
if ($chunkType == 'IDAT') {
try {
// Uncompressing the image chunk
$bufSize = $width * $height * 4 + $height;
$chunkData = zlib_decode($chunkData, $bufSize);
} catch (Exception $exc) {
return $oldPNG; // already optimized
}
// Swapping red & blue bytes for each pixel
$newdata = "";
for ($y = 0; $y < $height; $y++) {
$i = strlen($newdata);
$newdata .= $chunkData[$i];
for ($x = 0; $x < $width; $x++) {
$i = strlen($newdata);
$newdata .= $chunkData[$i + 2];
$newdata .= $chunkData[$i + 1];
$newdata .= $chunkData[$i + 0];
$newdata .= $chunkData[$i + 3];
}
}
// Compressing the image chunk
$chunkData = $newdata;
$chunkData = zlib_encode($chunkData, ZLIB_ENCODING_DEFLATE);
$chunkLength = strlen($chunkData);
$chunkCRC = crc32($chunkType . $chunkData);
$chunkCRC = ($chunkCRC + 0x100000000) % 0x100000000;
}
if ($chunkType != 'CgBI') {
$newPNG .= pack("N", $chunkLength);
$newPNG .= $chunkType;
if ($chunkLength > 0)
$newPNG .= $chunkData;
$newPNG .= pack("N", $chunkCRC);
}
// Reading header chunk
if ($chunkType == 'IEND') {
break;
}
}
return $newPNG;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment