Imagemagick Convert creating a very pixelated image - php

I use imagemagick to create thumbnails from images on my website using convert like so: convert -size 220x220 %s -resize 220 -profile '*' %s", $image, $thumb and this has worked great for a long time. Thousands of images have been processed and all the thumbnails look great ... except for one. For some reason this image produces a very ugly thumbnail and I can't figure out why.
Original image: http://i.imgur.com/fCbAN.jpg
Generated Thumbnail: http://i.imgur.com/MdLCs.jpg
Does anyone have any insight as to why this might happen with my convert code?

The thumbnail has been saved with very low quality (approximately 10-15, 99 being close to lossless). I think the question is, "why did that happen".
I can think of some reasons, but you will have to experiment. I assume the images you posted are the real images (not copies done converting e.g. PNG to JPG, I mean), and the command line is complete and describes the complete image workflow.
your ImageMagick setup attempts to keep estimated image quality. You do not set a quality explicitly (e.g. -quality 75), so the thumbnail gets the same quantizer setting as the source image. Suppose the source has a low quantizer, but you do not see it due to the high-frequency component (the image is "noisy" due to scanning). When resampling, the background loses its noise and becomes a smooth gradient, which was absent in the source. And a smooth gradient is hell on low quantizers. Try explicitly setting a quality factor (40 to 99, 40 is better compressed but chunkier, 99 is very high quality but bigger file).
there is some kind of interference between the resampler and the Moiré pattern that the scanner creates in the acquired image. This is less likely, because I see a "wavelength" of about 8 pixels which isn't at all uncommon, nor do I think that with so many images you acquired, none had approximately the same size and aspect ratio of this one; which in this scenario ought to have triggered the same behaviour. You say it didn't happen, so if this image isn't uncommon for size, aspect ratio, or source (e.g. one of the very few images scanned with a Scan-o-matic 600 scanner in the batch), this scenario becomes pretty unlikely. But if it is correct, then add a Gaussian blur before resizing and it ought to fix things: e.g. -blur 2x2.
there is bad juju in the file name, and for some reason this gets the ImageMagick wrapper to interpret a command of "set quantizer to its crappiest value". REALLY unlikely (if the interpret interprets a part of the filename as an option, it shouldn't interpret it as a filename, and the rest of the filename is no longer the true filename; resulting in a "File not found" error which we don't observe. All the same, if the original file name is something like "--progressive-swedish-music.jpg", try renaming it before thumbnailing.
I'm putting my money on option #1, anyway.
Another test which you could attempt is to run the same command from ImageMagick (command line) and not from PHP.

Related

pdf to png or jpg conversion and back again with php - losing fonts

I need to accept hundreds of pdfs at a time via PHP. I am storing these files on S3, so, file size will become a concern - not only for storing, but general handling. I'm finding the best way to reduce file size is conversion from PDF to PNG and back to PDF. A 15M file drops to 700kb. The problem is I'm losing certain fonts. Is there a way to ensure this doesn't happen? How do I ensure the process I use maintains the fonts in the original document? Is there some massive font library I can install?
from the command line I've tried...
Imagemagick
Ghostscript
pdftk
inkscape (real nice output)
They all work with varying levels of success, but each of them lose certain fonts - and not always the same ones.
Nope!
The .PDF format is an encapsulation of "graphics commands," such as "render the following text at position (X,Y) in the workspace using font Z."
When you "convert" such a file to any(!) "image file" format, you are in fact asking the PDF-engine to "carry out those graphics commands," producing a bitmap (a rectangular grid of pixels ...) as its only output.
Well, once you have done that, "you can never go back." The PDF-engine rendered its rectangular grid of pixels as best it could, and now, both it and the PDF-file that it consumed are gone, leaving you only with a rectangular grid of (output) pixels.

Rank for JPEG quality

I have to check few JPEG files for quality level and give to every file corresponding quality mark. Then I must be able to choose better image by this mark.
How to decide about visual image quality?
I'm dealing with photographs. Image dimensions and even compression ratio cannot indicate
visual quality of of the image. For example, if you enlarge the image and save it with bigger quality the visual quality will be reduced...
The code is in PHP.
Any advises will be very thankful!
If you have access to the original image then SSIM is one of the better methods to do this. It'd be pretty slow to do in pure PHP, but if you can execute shell commands, check DSSIM tool (you'll need to adapt it to load JPEGs instead of PNGs).
ImageMagick has compare command that can return Mean Square Error/PSNR of the image (compared to original), but these measurements only check per-pixel differences, so they are a poor way measure distortion caused by blockyness and ringing of JPEG compression.

php detect dpi of image in a pdf

I've tried a few tests using Imagick::getImageResolution on a PDF, and I can't figure out how to get the resolution (and colourspace) of an image embedded in a PDF. I've tried ripping the image out of the PDF, but during that process it seems the DPI is arbitrarily set to 72 not mater what I do.
I saw in 1564529 someone said DPI doesn't matter to a PDF, but that is not true (when an image is embedded in a PDF, several attributes about the image, like resolution, are defined in the PostScript). Is there a way in PHP (possibly with PSLib?) to figure out what the DPI of an embedded image is?
The 'dpi' of an image in PDF (or PostScript) is more nebulous than you may think. This is because it is possible to render the PDF at different scales, and so the actul dpi will vary.
You are correct that there is information regarding the scale factor of the image mebedded in the document. This is the Current Transformation Matrix, but it is not as simple as a single value, or even a single matrix.
The CTM maps co-ordinates into an idealised 'user space' which is nominally defined in points (72 per inch), but is infinitely subdivisible. When it comes to rendering, the 'user space' has a further transformation applied to scale it properly to the 'device space', the transformation is required because the device probably isn't 72 dpi.
You can find a much fuller explanation of this in the PDF Reference Manual, especially section 4.2.1 in the 1.7 reference.
So it would seem that all you need to do is take the declared /Width and /Height from the image dictionary, and apply the /Matrix to determine how big the image is in user space. Given that user space is effectively 72 dpi, then you would know how many inches the image was scaled to, how many pixels the image contains, and a simple division would give you the answer you want.
Indeed, in may cases this will work. However, one of the problems from your point of view, is that is possible, indeed common, to concatenate matrices to affect the current scaling, so simply looking at the matrix applied to an image won't give you the scale factor applied to that image, because something else may have already scaled the CTM. In addition PDF contains the 'UserUnit' kludge which allows a file to alter the default scaling of user space.
So the only way to work out the 'dpi' of an image is to interpret the page description to the point where the image is rendered, work out the total scaling at that point and from there figure out how much area the image covers. Then given the width and height of the image, work out its dpi.
In passing, here's a conundrum for you; its entirely possible to draw the same image multiple times in PDF, using the same image data. You only have to include the image data once. If I draw an image which is 100 pixels by 100 pixels and I draw it to cover one square inch, the resolution is 100 dpi. Now I draw the same image, but I scale it to cover half an inch. The resolution of the rendered image is now 200 dpi.
So what is the 'dpi of the image' ?
Hope this helps you:
http://forums.digitalpoint.com/showthread.php?t=884349

php: Storing images in database

Currently i am using gd to converting the image uploaded in jpg with
imagjpeg($data,NULL,85)
and storing it in a blob mysql field. Problem is the quality. Yes the quality is just awful. A screenshot of a window with some text inside becomes pretty hugly. (While with a game screenshot the quality is passable)
Should I use other lib than GD?
Should I use other gd format? (imagepng?)
ps. please note: this is not a duplicate.. i am not asking how to save an img to db
ps2. note that if i should change my currently format/method I have to convert something like 5000-6000 images already stored as jpg in my db
ps3. i use 85 for imagejpeg, can't use a higher value because the image size would grow more than the original version
ps4. I need to store image in db, please stay in topic
Thanks all
================================
REFORMULATING THE QUESTION
I save image (mostly software screenshots, sometime games screenshots) in BLOB field after doing an imagejpeg($resourceFromImageCreateFromString,NULL,85);
Problem I am experiencing is the image uploaded looks pretty bad in confront of the original even if it's the same size. (sometime it gets bigger because of 85)
Is the imagejpeg implementations that sucks?
ps. my simple upload script does the follow calls:
upload file
open it with "rb" (binary)
pass the data to imagecreatefromstring
pass the result to imagejpeg
Thanks again
Is there a special reason you want to store your image inside a BLOB?
What quality argument did you pass to imagejpeg()?
You can set the quality of your output with the 3rd parameter to imagejpeg(). The problem is that JPEG is not the best format for images with a lot of text - you have to choose between turning down the quality and getting a lot of artifacts in your image, or turning up the quality and having a large file size. You might consider using PNG instead.
my first recommendation would be to try saving it as a png as the quality is better.
my second recommendation is to try the quality parameter in imagejpeg($image, $filename, $quality).
recommendation #3 - I worked on a site that I had to rewrite the image storage system because they implemented just what you are doing, storing images as BLOBs in the database. Their system only had about 20K images in it and it was crashing weekly because the database could not handle the load.
The conversion process for 5-6K images should not take more than a couple hours no matter how large the images. When I converted my images to disk storage from db storage, I ran 1K images at a time and each run took 5-10 minutes.
Why do you re-code anyway if it already IS a jpeg? To save space? Well, but then you already have your answer, in part - to save space from jpg to jpg you have to save in lower quality.
You cannot specify quality with imagecopyresampled, with imagejpeg you can. Use a high(er) value for the quality parameter.
Please note that JPEG is a format optimized for storing FOTOS. Images with large areas of the same color, straight lines etc. are much better stored in a lossless format like PNG. Of course, if you have a screenshot taken from a screen with fotos as desk background you have elements of both - so choose your format according to what you want. If the foto-part is more important and you don't care as much about fonts and lines, go with jpeg. Of course JPEG can be just as good quality as PNG for screenshots as well, but then you miss out on most of its compression capabilities, you have to use a 90+% quality setting. At 100% JPEG too is lossless, but by then a PNG might actually be of smaller (file)size.

How to convert large SVG file to tiled PNGs?

I have a large SVG file (approx. 60 MB, 10000x10000 pixels but with the potential to get much larger), and I'm wanting to create, say, many tiled 256x256 PNG images from it (in that example there would be 1600 images; round(10000/256)^2).
Does anyone have any idea of how to do this on a web server (running PHP amongst other things)? I thought about rsvg, but it doesn't seem to have any functionality to modify the bounding box (and I'd rather avoid doing it manually for each section). ImageMagick might be able to do it, but I've not been having much luck with getting it to work. Using rsvg to create a large PNG and then using a tool dedicated to tiling very large images might work, but I've not had any luck finding such a thing! Speed isn't really an issue, although it is desirable, so if the worst comes to the worst, I might look into modifying the SVG's bounding box per section. I could see the generation taking forever, though!
Anyone know of any methods to do this?
Edit 2016-03-02:
I recently came back to needing an answer for this question again, and Inkscape appears to be the only tool which can render SVGs for a given area at given sizes (svgexport almost meets these requirements, but it doesn't let you change the aspect ratio).
My aim was to tile an SVG into 256x256 tiles, and I've now successfully made a script which can tile an arbitrarily large SVG by doing repeated renderings in inkscape of about 16,000 x 16,000 and tiling the resulting images. I've successfully rendered SVGs where the dimensions are over 500,000 x 500,000 pixels—no problems with memory usage (it just takes a long time!)
inkscape has a command line mode to export pngs, taking an optional argument to choose which area to export
inkscape vector.svg --export-png=raster.png --export-area=0:0:100:100
I'd look at Apache Batik. In particular, their SVG Rasterizer looks like just what you need.
I've never used it for giant SVG files, though, so I don't know if it's optimized for that case or not.
Check out this question i posted earlier and got working.
If the image is only 10000x10000 the script i have in the question works best.
If however you want to use much bigger images check out the script in my anser.
ImageMagick crop huge image
PanoJS seems to do what you're asking about. You need to convert the SVG to a large PNG first though (e.g. using inkscape on the command line), and then use PanoJS's tilemaker to make the tiles. It is a very memory intensive beast, but if you can get it to run successfully, you can then use the PanoJS Javascript code to point to your webserver. XKCD used it for a large image describing money.
You might want to edit the source properties of your SVG (a copy), to render certain areas only. Use the "width" and "height" properties to match your desired tile size (256) and the "viewBox" to the desired tile area (for example 'viewBox="512 256 768 512"' for the 3rd tile in the second row).
You could do something like this in a loop:
$sed = "sed 's/width=\"10000\"/width=\"256\"' ".$sourcefile;
$sed .= " | sed 's/height=\"10000\"/height=\"256\"'";
$sed .= " | sed 's/viewBox=\"0 0 10000 10000\"/viewBox=\"0 0 256 256\"'";
exec($sed." > ".$tmpfile);
exec('rsvg '.$tmpfile.' > '.$tilefile);
I don't know how this behaves on very large files though.

Categories