I have a folder that will consist of hundreds of PNG files and I want to write a script to make them all interlaced. Now, images will be added to that folder over time and processing all the images in the folder (wether their interlaced or progressive) seems kinda silly.
So I was wondering, is there any way to use PHP to detect if an image is interlaced or not that way I can choose wether to process it or not.
Thanks heaps!
You can also take the low-level approach - no need of loading the full image, or to use extra tools or libraries. If we look at the spec, we see that the "interlaced" flag it's just the byte 13 of the iHDR chunk, so we have to skip 8 bytes from the signature, plus 8 bytes of the iHDR Chunk identifier+length, plus 12 bytes of the chunk... That gives 28 bytes to be skipped, and if the next byte is 0 then the image is not interlaced.
The implementation takes just 4 lines of code:
function isInterlaced( $filename ) {
$handle = fopen($filename, "r");
$contents = fread($handle, 32);
fclose($handle);
return( ord($contents[28]) != 0 );
}
BTW, are you sure you want to use interlaced PNG? (see eg)
I think ImageMagick could solve your problem.
http://php.net/manual/en/imagick.identifyimage.php
Don't know if all the attributes are returned, but if you look at the ImageMagick tool documentation you can find that they can spot if an image is interlaced or not.
http://www.imagemagick.org/script/identify.php
At worst you can run the command for ImageMagick via PHP if the ImageMagick extension is not installed and parse the output for the "Interlace" parameter.
Related
I'm attempting to read a zip file in PHP that I know has a CRC error. Unfortunately, it looks like I can only get 31 bytes of the file to read. Using just $zip->getFromName() gives no errors but just reads 31 bytes
$zip = new ZipArchive;
$zip->open("path/to/corrupted.zip");
// $contents will become just 31 bytes
$contents = $zip->getFromName("file/in/zip.txt");
Trying to read from the stream $zip->getStream() will give a CRC error, and again will only read 31 bytes
$fp = $zip->getStream("file/in/zip.txt");
$contents = "";
while (!feof($fp)) {
// Gives the error "fread(): Zip stream error: CRC error in ..."
// Using 1 instead of 2 still only reads 31 bytes but gives no error
$contents .= fread($fp, 2);
}
fclose($fp);
So, is there any way I could ignore this CRC error, and read the file anyways?
A little background: my website pre-processes .jar files users upload before they're downloaded by others. Users will occasionally upload a valid .jar file with CRC errors in an attempt to deter people from decompiling it. However, I still want to be able to pre-process these files for download.
I have a different pre-processor written in Python, and I was able to pretty easily disable the CRC check by modifying the zipfile library and commenting out the line that does the crc check. Is there any easy way I could do a similar thing in PHP without needing to make my own ZipFile library? I suppose worst case that's what I'll need to do.
You can switch to a pure php zip library, so you can remove the crc check without having to rewrite the whole library on your own, and you also haven't to compile native code. Here is an example:
https://www.phpclasses.org/package/3864-PHP-Create-and-extract-ZIP-archives-in-purely-in-PHP.html
I'm trying to use PHP to parse a custom gzip archive file format that was created in Delphi (not my code!). The format is basically:
4-byte integer: count of files in archive
for each compressed file:
4-byte integer: filename length [n]
[n] bytes: filename
4-byte integer: uncompressed file length [m]
[????] bytes: gzipped content
I can read the file and actually decode the first compressed file correctly by using zlib_decode() with a max uncompressed length of [m] bytes on the remainder of the file after I know the length ([m]), but then I'm stuck because I don't know how far into the substring I should go to find the next filename -- zlib_decode() doesn't return the number of compressed bytes that it processed before stopping. Since this is a custom format, it doesn't seem like I can use the normal gzopen()/gzread() functions because the entire file isn't compressed (I tried, it doesn't work).
This code works in Delphi because apparently you can pass a file handle back and forth between normal file reading functions and the System.ZLib decoding functions -- you can read [m] uncompressed bytes and the pointer will remain at the last compressed byte -- but PHP doesn't seem to support switching between read-as-normal and read-as-gzip on the fly that way.
Am I missing an obvious way in PHP to deal with a mixed-content file format like this, where metadata and compressed data are stacked together this way? Or am I out of luck without knowing the compressed data length?
A dirty workaround is to recompress the content of each file as I am able to parse it, use that to calculate the compressed length, and adjust the file pointer in the original file manually as follows:
$current_pos = ftell($handle);
$skip_length = strlen(gzencode($uncompressed_text,9,FORCE_DEFLATE));
fseek($handle, $skip_length+$current_pos);
This works, but feels very hack-ish. I'd still be open to any better approaches.
EDIT:
Just a note that this eventually failed. However, I was fortunate enough to know in advance the list of expected filenames and I was able to do the following (more reliable since zlib_decode() will decode as much as it can and discard the rest anyway):
foreach ($filenames as $thisFilename) {
$thisPos = strpos($rawData, $thisFilename);
$gzresult = zlib_decode(substr($rawData, $thisPos + strlen($table) + 8)); // skip 8 bytes for filename size and uncompressed data size, which are useless info.
}
I am trying to learn Imagemagick, php.net docs are terrible T_T, and I cannot seem to find any answers to my questions. I am wanting to allow people to upload images then resize them and lose EXIF data.
Heres what I have currently.
$thumbnail = new Imagick("http://4.bp.blogspot.com/-hsypkqxCH6g/UGHEHIH43sI/AAAAAAAADGE/0JBu9izewQs/s1600/luna-llena1.jpg");
$thumbnail->thumbnailImage( 100, 100, true );
$thumbnail->writeImage( "avatar/thumbnail.jpg" );
Now how do I control the image file that it is being saved as? Lets say the user submits a gif/png/jpg how would I go about taking that image then saving it as the same input format or changing them all to .png?
This IMO produces the best results for imagick thumbnails;
Load the picture
$img = new imagick( $_FILES['Picture']['tmp_name'] );
Trim an excess off the picture
$img->trimImage(0);
Create the thumbnail, in this case, I'm using 'cropThumbnailImage'
$img->cropThumbnailImage( 180, 180 );
Set the format so all pics can now be the same standard format
$img->setImageFormat( 'jpeg' );
Set the Image compression to that of a jpg
$img->setImageCompression(Imagick::COMPRESSION_JPEG);
Set the quality to be 100
$img->setImageCompressionQuality(100);
The resulting thumbnail is then a little bit blury IMO, so I add a slight sharpening effect to make it 'sharper'. . play around with these settings, but I like..
$img->unsharpMaskImage(0.5 , 1 , 1 , 0.05);
I agree, the PHP.net docs are not very helpful. I've found that it's easiest to find how to do things using commands, then match the commands up with the PHP methods. I'm a little late replying so you might have figured it out by now, but if not, or for the benefit of anyone else:
If you want to change the image format before saving, add this before your writeImage line:
$thumbnail->setImageFormat('png');
Then change the extension in your writeImage line to match, e.g. thumbnail.png
To change the quality, write:
$thumbnail->setImageCompressionQuality(40); // Adjust the number 40
In some cases you might also want to set the compression type by writing:
$thumbnail->setImageCompression(Imagick::COMPRESSION_JPEG);
You can find the COMPRESSION constants here: http://www.php.net/manual/en/imagick.constants.php
Note: These are just examples. This compression would not actually work with a png file.
I am generating PNG file with cairo extension of PHP. The image contains a background and a text. Now I want to compress these images by PHP after its generated by cairo. Is there any library to do this?
I found pngcrush tool. But its a command line tool. I dont want to invoke system call. If there is not PHP solution a C solution would do. In that case I'll make a PHP extension.
I have read this related question. But there is no answer in it.
You can use imagepng() ...
//If you don't already have a handle to the image and it's just on the file system...
$im = imagecreatefrompng("yourGenerateFile.png");
$quality = 5; //0 - 9 (0= no compression, 9 = high compression)
imagepng($im, 'file/to/save.png', $quality); //leave out filename if you want it to output to the buffer
imagedestroy($im);
I would take a look at PngOptimizer. You can get the source for it at the bottom of the page, and it has a separated CLI version too.
Only problem is that source is C++ , not ANSI C. I have never made a PHP extension, so i don't know if it makes a difference.
For C code take a look at ImageMagick. It looks like there is a PHP extension too.
I have a sever which people can upload files to. The problem is that some of the filenames are mangled (dont have any extension) and so I cannot immediately determine file type. This question is two part: for the files which do have filenames what is the best way to determine whether or not it is an image? (Just a big long if/else if list?) Secondly, for the files which dont have extensions, how can I determine if they are images?
You can use exif_imagetype()
<?php
$type =exif_imagetype($image);
where $type is a value
IMAGETYPE_GIF
IMAGETYPE_JPEG
IMAGETYPE_PNG
IMAGETYPE_SWF
IMAGETYPE_PSD
IMAGETYPE_BMP
IMAGETYPE_TIFF_II (intel byte order)
IMAGETYPE_TIFF_MM (motorola byte order)
IMAGETYPE_JPC
IMAGETYPE_JP2
IMAGETYPE_JPX
IMAGETYPE_JB2
IMAGETYPE_SWC
IMAGETYPE_IFF
IMAGETYPE_WBMP
IMAGETYPE_XBM
IMAGETYPE_ICO
From the manual:
When a correct signature is found, the appropriate constant value will be returned otherwise the return value is FALSE. The return value is the same value that getimagesize() returns in index 2 but exif_imagetype() is much faster.
You can use getimagesize
It does not require the GD image library and it returns same information about image type.
http://it2.php.net/manual/en/function.getimagesize.php
If you have the GD2 extension enabled, you could just use that to load the file as an image, then if it returns invalid you can catch the error and return FALSE, otherwise return TRUE.
You have two options here, one's simple and pre-built with some shortfalls, the other is complex and requires math.
PHP's fileinfo can be used to detect file types based on the file's actual header information. For instance, I just grabbed your gravitar:
But the actual code is this:
‰PNG
IHDR szzô
IDATX…—OL\UÆZÀhëT)¡ c•1T:1‘Š‘.Ú(]4†A“ÒEY˜à.................................
So, even without the file name I could detect it quite obviously. This is what the PHP Fileinfo extension will do. Most PNG and JPG files tend to have this header in them, but this is not so for every single file type.
That being said, fileinfo is dead simple to use, from the manual:
$fi = new finfo(FILEINFO_MIME,'/usr/share/file/magic');
$mime_type = $fi->buffer(file_get_contents($file));
Your other option is more complex and it depends on your own personal ambitions, you could generate a histogram and profile files based on their content.
Something like this looks like a GIF file:
And something like this looks like a TIFF file:
From there you'd need to generate a model over multiple types of files for what the histogram of each type should be, and then use that to guess. This is a good method to use for files that don't really have those "magic headers" that can be read easily. Keep in mind, you'll need to learn some math and how to model an average histogram function and match them against files.
You can try to load the image into PHP's GD library, and see if it works.
$file = file_get_contents('file');
$img = imagecreatefromstring($file);
if($img === FALSE){
// file is NOT an image
}
else{
// file IS an image
}
Look at image magic identify. http://www.imagemagick.org/script/identify.php
The php wrapper is here: http://www.php.net/manual/en/function.imagick-identifyimage.php
Or if you just want to validate that it's an image (and don't care about the meta data): http://www.php.net/manual/en/function.imagick-valid.php
exif_imagetype() might work
make sure you have exif enabled.
Try looking at exif_imagetype
If you need a fast solution, use imagesx() and imagesy(). There is also a fast way to check large image file dimensions, by reading just a small amount of data from the file header. Explained in more detail in the following url:
http://hungred.com/useful-information/php-fastest-image-width-height/
You can use the Fileinfo extension:
http://www.php.net/manual/en/function.finfo-file.php
finfo_file() uses magic bytes and does not have to load the whole image into memory. The result is a string with the corresponding MIME type, e.g.:
text/html
image/gif
application/vnd.ms-excel
The type of the image is typically going to be able to be inferenced from the header information of the file.
For the first question is extension is known you could use the PHP function in_array() Documentation