Apple PNG Image Decompression - php

I have run into a problem with Apple's unfortunate decision to create a PNG file format that isn't actually a PNG file format. I pulled a PNG image file from an app IPA file and attempted to display it on a web browser and found that web browsers don't know how to display them and give an error. It took me some time to discover that the original, unzipped image was even the problem in the first place.
After researching the issue and doing a lot of poking around, I finally found this script as I don't have the knowledge to create a class to do what I need:
https://gist.github.com/juban/8397183
The author says this is a PHP scripted version that will turn an apple PNG file into a standard PNG file so that it can display properly. For added information, I am running PHP 5.5+.
My process of pulling out the image file goes like this:
if ($zip->open($ipaFile) === TRUE) {
if($zip->locateName($iconFilePath.$iconFile) !== FALSE) {
if ($iconData = $zip->getFromName($iconFilePath.$iconFile)) {
$iOSNormalizer = new iOSPNGNormalizer();
$iconData = $iOSNormalizer->getNormalizedPNG($iconData);
file_put_contents($iconSaveFile.$newIconFile, $iconData);
}
}
}
The iOSNormalizer is a class you can look at by clicking on the link I gave.
When I run it through the class I get hung up with the following errors:
Warning: zlib_decode(): data error in mypage.php on line 524
Notice: Uninitialized string offset: 12840 in mypage.php on line 532
Notice: Uninitialized string offset: 12840 in mypage.php on line 532
...These last two notices are repeated a ton of times for a lot of different lines. What happens is the apple PNG file has its original widths and heights restored, runs into the zlib_decode() error, and then stops working. The outputted file is a blank white image with its original height and width. zlib_decode() is not documented well for PHP and I'm not sure how to fix this problem. I'm hoping someone can look at the class in the link and better understand why this may be happening. Thanks!
EDIT: To ensure it isn't anything to do with how I am pulling out the icon file from the IPA file, I tested the following code on the image attached at at the end of my question and I still have the same problem (again, see the PHP class in my link to see what the function getNormalizedPNG() does):
$iconFile = "/path/AppIcon40x40#2x.png";
$newIconFile = "/path/converted.png";
$iOSNormalizer = new iOSPNGNormalizer();
$iconData = $iOSNormalizer->getNormalizedPNG($iconFile);
file_put_contents($newIconFile, $iconData);
Example PNG

Related

Unzipped image doesn't display in browsers

fI have the following code:
$ipaFile= '/path/file.ipa';
$iconFilePath = "Payload/myapp.app/AppIcon40x40#2x.png"; // the pathway to my image file if the ipa file is unzipped.
$iconFile = "AppIcon40x40#2x.png";
$iconSaveFile = '/path/';
if ($zip->open($ipaFile) === TRUE) {
if($zip->locateName($iconFilePath) !== FALSE) {
if($iconData = $zip->getFromName($iconFilePath)) {
file_put_contents($iconSaveFile.$IconFile, $iconData);
}
}
}
This code successfully pulls an image out of an ipa (zipped) file and puts it where I want it to be. The image displays properly in image viewing programs. However, when I want to view the image in a browser, the browser tells me that the image cannot be displayed because it contains errors.
Doing further research, I get that the file is somehow not being unzipped incorrectly. There are a lot of issues regarding images not displaying in browsers, but there are a wide variety of reasons and I'm just not sure which one is mine. I've tested a variety of ways to try and fix the problem (fread method of getting file, using PHP's image functions, using headers, etc) and I can't seem to make it work. Any help would be appreciated, thanks.
For any who will wonder, when Xcode (Apple) compiles an app, it modifies the PNG files within them and a standard browser will not render them as is.
http://echoone.com/filejuicer/formats/ipa
https://theiphonewiki.com/wiki/IPA_File_Format

With PHP, how can I check if a PDF file has errors

I have a DB system built in PHP/MySql. I'm fairly new at this. The system allows the user to upload an invoice. Others give permission to pay the invoice. The accounting person uploads the check. After check is uploaded, it generates a PDF as a cover, then uses PDFTK (using Ben Squire's PDFTK-PHP-Library) to combine all of the files together and present the user with a single PDF to download.
Some users upload PDF files which cause PDFTK to hang indefinitely when it tries to combine the PDF with others (but most of the time it works fine). No returned error, just hangs. In order to get back onto the sytem, user must clear cache and re-log in. There are no error messages logged by the server, it just freezes. The only difference I can find in the files that do or do not work in looking at them with Acrobat is that the bad files are legal sized (8.5 x 14) ... but if I create my own legal sized file and try that, it works fine.
Using Putty I've gone to command line and replicated the same problem, PDFTK can't read the file, it hangs on the command line as well. I tried using PDFMerge which uses FPDF to combine the files and get an error with the file as well (The error I get back from this is: FPDF error: Unable to find object (4, 0) at expected location). On the command line I was able to use ImageMagick to convert PDF to JPG, but it gives me an error: "Warning: File has an invalid xref entry: 2. Rebuilding xref table." and then it converts it to a jpg but gives a few other less helpful warnings.
If I could get PHP to check the PDF file to determine if is valid without hanging the system, I could use ImageMagick to convert the file and then convert it back to a PDF, but I don't want to do this to all files. How can I get it to check the validity of the file when uploaded to see if it needs to be converted without causing the system to hang?
Here is a link to a file that is causing problems: http://www.cssc-testing.org/accounting/school_9/20130604-a1atransportation-1.pdf
Thanks in advance for any guidance you can offer!
My Code (which I'm guessing is not very clean, as I'm new):
$pdftk = new pdftk();
if($create_cover) { $pdftk->setInputFile(array("filename" => $cover_page['server'])); }
// Load a list of attachments
$sql = "SELECT * FROM actg_attachments WHERE trans_id = {$trans_id}";
$attachments = Attachment::find_by_sql($sql);
foreach($attachments as $attachment) {
// Check if the file exists from the attachments
$attachment->set_variables();
$file = $attachment->abs_path . DS . $attachment->filename;
if(file_exists($file)){
// Use the pdftk tool to attach the documents to this PDF
$pdftk->setInputFile(array("filename" => $file));
}
}
$pdftk->setOutputFile($save_file);
$pdftk->_renderPdf();
the $pdftk class it is calling is from: https://github.com/bensquire/php-pdtfk-toolkit
You could possibly use Ghostscript using exec() to check the file.
The non-accepted answer here may help:
How can you find a problem with a programmatically generated PDF?
I wont say this is an appropriate/best fix, but it may resolve your problem,
In: pdf_parser.php, comment out the line:
$this->error("Unable to find object ({$obj_spec[1]}, {$obj_spec[2]}) at expected location");
It should be near line 544.
You'll also likely need to replace:
if (!is_array($kids))
$this->error('Cannot find /Kids in current /Page-Dictionary');
with:
if (!is_array($kids)){
// $this->error('Cannot find /Kids in current /Page-Dictionary');
return;
}
in the fpdi_pdf_parser.php file
Hope that helps. It worked for me.

Why would a PHP image copy and resize script cause a browser to return "Content Encoding Error"?

I have a PHP script that takes an images, checks type and filesize, then creates 2 resized copies of the master image, all 3 images are saved to the server. I was under the impression everything worked fine. I was testing out script and on one jpg image I got thrown the error "Content Encoding Error" by firefox. Doing some reading suggested this was a Firefox issue but testing in IE and Chrome resulted in similar errors.
The odd thing is that some .jpg files work, others don't. For those that don't work the error is occurring when the script comes to encode the second resized copy as the master, and first copy are outputted to specified folder. I have checked to see that the image itself isn't corrupt after doing some more reading. The only difference I could note between a .jpg that would allow the script to complete fully and one that wouldn't was that, when viewing the properties of the failing one within Windows it appeared to carry more data, such as camera used to, model number, etc.
Does anyone know what might be causing this error to be thrown?
EDIT
Here's the code I'm using.
$imgsrc = imagecreatefromjpeg($file);
imagecopyresampled($thbout,$imgsrc,0,0,0,0,$thbwid,$thbhei,$width,$height);
imagejpeg($thbout,$thbpath,80);
imagedestroy($thbout);
imagecopyresampled($optout,$imgsrc,0,0,0,0,$optwid,$opthei,$width,$height);
imagejpeg($optout,$optpath,80);
imagedestroy($optout);
Having played about a bit tonight I got it working, by switching the code to this. (Switch to create larger file first)
$imgsrc = imagecreatefromjpeg($file);
imagecopyresampled($optout,$imgsrc,0,0,0,0,$optwid,$opthei,$width,$height);
imagejpeg($optout,$optpath,80);
imagedestroy($optout);
imagecopyresampled($thbout,$imgsrc,0,0,0,0,$thbwid,$thbhei,$width,$height);
imagejpeg($thbout,$thbpath,80);
imagedestroy($thbout);
So I guess my new question becomes, why does it behave like this?

PHP test for corrupt (but apparently fine) images

I have a simple image upload script that uses SimpleImage.php
(http://www.white-hat-web-design.co.uk/blog/resizing-images-with-php/)
to resize and save 2 copies of an uploaded image.
There isn't a massive amount of validation, just checking that it exists and that the file extension is fine, and also an exif_imagetype(); call.
This has worked with no problems so far until I tried to upload a seemingly normal jpeg which turned out to be invisibly (and untestably?) corrupt. There was something not right about it, but I know very little about image corruption - it looked fine and opened no problem on anything, but when I tried to save a scaled copy in my script I got a white page.
The problem is definitely that specific image, I've tested exhastively with other images both from my local stock and from stock image sites, and only that one image breaks it.
I resized a copy using Photoshop (the predicted file size thingy gave me some wierd numbers - 45meg for top quality jpeg) and that uploaded with no issues.
So my question is, how do I test for this?
The image in question is here: http://chinawin.co.uk/broken.jpg //beware, 700k
notes: I've tested with similar resolutions, image sizes and names, everything else worked apart from this image.
UPDATE:
Through trial and error I've narrowed down where the script breaks to the line where I load the image into a var for SimpleImage. Strangely this is the second line that does so (the first being to create the large copy, this one to create a thumbnail).
Commenting it out means the rest works ok... perhaps some refactoring will avoid this problem.
2nd Update:
Here's a snippet of code and some context from the line that fails:
//check if our image is OK
if ($image && $imageThumb)
{
//check if image is a jpeg
if (exif_imagetype($_FILES[$k]['tmp_name']) == IMAGETYPE_JPEG)
{
list($width, $height, $type, $attr) = getimagesize($_FILES[$k]['tmp_name']);
//echo 1;
$image = new SimpleImage();
//echo 2;
$image->load($_FILES[$k]['tmp_name']);
//echo 3;
$imageThumb = new SimpleImage();
//echo 4;
//this next line topples my script, but only for that one image - why?:
$imageThumb->load($_FILES[$k]['tmp_name']);
//echo '5<br/><br/>-------<br/>';
//do stuff, save & update db, etc
}
}
Final edit:
Turns out my script was running out of memory, and with good reason - 4900x3900 image with 240 ppi turns out to be around 48 meg when loaded into memory, twice - so I was using probably > 90meg of ram, per image.
Hats off to #Pekka for spotting this.
Refactoring the script to only have the image loaded once, and then this variable used instead of it's sibling, fixed my script. Still having (different) issues with upoading larger (2.5meg) images but this is for another question.
This is most likely a memory issue: Your JPG is very large (more than 4000 x 4000 pixels) and, uncompressed, will indeed eat up around 48 Megabytes of RAM.
Activate error reporting to make sure. If it's the reason, see e.g. here on what to do: Uploading images with PHP and hitting the script memory limit

Image SRC From PHP Script on IIS - Not Displaying Consistently

Last week I converted my page img src values from pointing at image files to using a PHP script to serve up the images. The primary reason was to accommodate both files and database BLOBs as the actual source.
Now when a user goes to a page, sometimes images show and sometimes not. If not, and the page is refreshed\reloaded, then the image appears. When images do not appear, sometimes it is an image the user has already accessed previously today.
I am stumped.
Here is the img tag:
<img src="../somedir/image_script.php?i=1234">
The image_script.php file figures out where to get the image from, then finishes up with:
header("Content-type: image/jpeg");
if($from_db){
print $image_blob;
} else {
$im = imagecreatefromjpeg($image_file);
imagejpeg($im,null,100);
imagedestroy($im)
}
I am using PHP 5.2.8 on IIS 6 using FastCGI. There are no cache headers on the image_script.php file nor on the directory it is in. Currently 99.9% of the images are file based, so I do not know if there is a difference in result between db-based and file-based images. When I go directly to image_script.php in my browser it returns the requested image (i=????) 100% of the time.
a> Any clue as to why the hit and miss with images being displayed? and,
b> what would be a proper way to actually cache the images served up by the PHP script? (they are very static)
Scott
Hmm. Can't tell for sure, but maybe your imagecreatefromjpeg is occasionally running out of memory? In that case, you'd serve an error message out as JPEG data and never see it, right?
Incidentally, wouldn't just grabbing the image file in as a string and shovelling it out without going through imagecreatefromjpeg/imagejpeg/imagedestroy be more efficient? It looks like you're reading a JPEG file, creating an internal PHP memory image from it, then reconverting it to a JPEG (at hefty 100% quality) then serving that data out, when you could simply read the JPEG file data in and print it, like you do from the database.
What happens if you do, say...
...
} else {
header ('Content-length: ' .filesize($image_file));
readfile ($image_file);
}

Categories