Imagemagick with greyscale images and 24 bit depth - imagemagick

I am using the Imagick library to work with ImageMagick in PHP. I am first reading an (JPEG) image from an external server with:
$img = new Imagick();
$img->readImage($source);
And then upload it to my Amazon S3 bucket with the following code:
$s3 = new AmazonS3();
$s3->create_object(BUCKET, $destination_path, array(
'body' => $img->getImageBlob(),
'length' => $img->getImageSize(),
'acl' => AmazonS3::ACL_PUBLIC,
'contentType' => 'image/jpeg'
));
Everything seems to be working fine, the files appear in my storage bucket and I can view them in my browser. However, when handling greyscale images, ImageMagick converts the image from 24 bit depth to 8 bit depth. I would like them to keep their 24 bit depth, how could I achieve this? I've tried the following, without success:
$img->setImageType(imagick::IMGTYPE_TRUECOLOR);
For colorized images, everything works fine, images keep their 24 bit depth.
Edit:
It seems that ImageMagick changes the image type from 6 (truecolor) to 2 (greyscale). Trying to overwrite this does not work, as tested with the following code:
$img = new Imagick();
$img->readImage($source);
$img->setImageType(6);
echo $img->getImageType();
which outputs 2

Use setType() before you load the image. So:
$img = new Imagick();
$img->setType(6); //or use imagick::IMGTYPE_TRUECOLOR instead of 6
$img->loadImage($source);
This will output an image with truecolor, even if the loaded picture uses graycolors only.

Related

Rails 6 Axlsx Excel Gem - Images not displaying

I don't know if it's my fault or if it just doesn't work with Rails 6, but my images in the file are not displaying:
I tried:
img = File.expand_path(Rails.root+'app/assets/images/logo.jpg')
and also like described in the examples:
img = File.expand_path('../logo.jpg', __FILE__)
sheet.add_image(:image_src => img, :noSelect => true, :noMove => true) do |image|
image.start_at 5, 20
image.end_at 7, 22
end
The image is found (at least I don't get an error for this) but the only thing I see in the generated file (the rest of the creation works fine) is:
Could it be the image size not fitting in the cells? Or is it resizing automatically?
Any suggestions or ideas? I don't know what's wrong or what else I could try
Did you try setting height and width for the image? Have a look at this old answer https://stackoverflow.com/a/47982814/1796645 (potential duplicate question)
If you found a bug, then you could report it in https://github.com/caxlsx/caxlsx/issues

Rails: Download images from S3, resize and upload back to S3

In my Rails 4 application I have large number of images stored on S3 using Paperclip. Image url looks like http://s3.amazonaws.com/bucketname/files/images/000/000/012/small/image.jpg?1366900621.
Given following attachment class:
How can I download images from S3 and store locally ?
Then how to resize that locally stored image
Upload resized image to another S3 bucket without Paperclip (at a path s3/newbucket/images/{:id}/{imagesize.jpg})
Attachment class:
class Image < ActiveRecord::Base
has_attached_file :file, styles: { thumbnail: '320x320', icon: '64x64', original: '1080x1080' }
validates_attachment :file, presence: true, content_type: { content_type: /\Aimage\/.*\Z/ }
end
The basic advice would be not to resize images on-the-fly as this may take a while and your users may experience a huge response times during this operation. In case you have some predefined set of styles it would be wise to generate them in advance and just return back when required.
Well, here is what you could do if there is no other option.
def download_from_s3 url_to_s3, filename
uri = URI(url_to_s3)
response = Net::HTTP.get_response(uri)
File.open(filename, 'wb'){|f| f.write(response.body)}
end
Here we basically downloaded an image located at a given URL and saved it as a file locally. Resizing may be done in a couple of different ways (it depends on whether you want to serve the downloaded file as a Paperclip attachment).
The most common approach here would be to use image-magick and its convert command-line script. Here is an example of resizing an image to width of 30:
convert -strip -geometry 30 -quality 100 -sharpen 1 '/photos/aws_images/000/000/015/original/index.jpg' '/photos/aws_images/000/000/015/original/S_30_WIDTH__q_100__index.jpg' 2>&1 > /dev/null
You can find documentation for convert here, it's suitable not only for image resizing, but also for converting between image formats, bluring, cropping and much more! Also you could be intrested in Attachment-on-the-Fly gem, which seems a little bit outdated, but has some insights of how to resize images using convert.
The last step is to upload resized image to some S3 bucket. I assume that you've already got aws-sdk gem and AWS::S3 instance (the docs can be found here).
def upload_to_s3 bucket_name, key, file
s3 = AWS::S3.new(:access_key_id => 'YOUR_ACCESS_KEY_ID', :secret_access_key => 'YOUR_SECRET_ACCESS_KEY')
bucket = s3.buckets[bucket_name]
obj = bucket.objects[key]
obj.write(File.open(file, 'rb'), :acl => :public_read)
end
So, here you obtain an AWS::S3 object to communicate with S3 server, provide your bucket name and desired key, and basically upload an image with an option to make it visible to everybody on the web. Note that there are lots of additional upload options (including file encryption, access permissions, metadata and much more).

RMagick, Tempfile, Paperclip: how to save a image file with large dimensions and small kbs as a thumbnail?

I have a Rails rake task that is processing a batch of images. It strips out the white background (using RMagick), replaces it with a transparent layer, writes it to a tempfile and then saves it as a PNG on Amazon S3 (using Paperclip).
It works for the bulk of the images. However, it runs into an error for at least 1 image. Can someone help me figure out why and how to fix it?
Code sample:
require 'RMagick'
require 'tempfile'
include Magick
task :task_name => :environment do
x = Item.find(128) # image 128 is the one giving me trouble
sourceImage = Image.read(x.image_link_hires)
processedImage = sourceImage[0].transparent("white")
tempImageFile = Tempfile.new(["processed_image",".png"])
processedImage.write("png:" + tempImageFile.path)
x.image_transparent = tempImageFile
x.save!
end
The error message:
rake aborted! Validation failed: Image transparent C:/Users/Roger/AppData/Local/Temp/processed_image20130107-8640-1ck71i820130107-8640-i6p91w.png is not recognized by the 'identify' command., Image transparent C:/Users/Roger/AppData/Local/Temp/processed_
image20130107-8640-1ck71i820130107-8640-i6p91w.png is not recognized by the 'identify' command.
This message appears upon running the last line (the save operation).
Tempfile problem with small files?
I think the error has something to do with Tempfile not actually writing a file to the temp path. This error may have to do with small filesize? The specific image that it's having trouble with has an usually amount of white space, so the resulting filesize after processing is about 30k for an 800x800 pixel image.
How can I verify if this is the case? And if it is, how can I work around it?
Other observations:
When I write the trouble image to a normal file (rather than Tempfile), it saves successfully locally.
The task works fine for other images, which tend to be much bigger (~1-2MB)
After processedImage.write, I've checked tempImageFile.size. It says that it's 30kb as expected.
When I observe the temp file directory when the rake task runs, I can see the temp files being created when the task is run other images successfully. The files seem to show up when processedImage.write runs. However, for the trouble image, I don't see temp files ever being created.
Thanks for any advice.
Update 7 Jan 2013
I've investigated this more. I reran #1 above, but attempted to save onto S3 with Paperclip. This generated the same error message.
So now I believe the issue is that this is a small file in terms of bytes (32kb), but with a decent height and width (800x800). Paperclip is trying to save a thumbnail version of it, which is 90x90. Typically this generates a filesize that is <1% the original, which I assume is the source of the errors.
If anyone has an elegant workaround / fix for this, I'd appreciate hearing about it.

imagemagick quality image issue using php

I have convert the PDF to image,I try using the exec,by excute the linux command like '/usr/bin/convert -density 300x300 file.pdf[0] -resample 160 -resize 512x700! images/sample-0.jpeg 2>&1'.But i have read some articles that it slow as compare to imagick php module.so try using php with code
$uploadfile = "file.pdf";
$im = new Imagick ( $uploadfile . "[0]" );
$im->setImageFormat ( "png" );
$im->writeImage ( "p-10.png" );
As you can see that i am not setting the desity and resample,the quality of image is not good at all.In php manual also there no function that set the density,i also try with setResolution,but does not work.
Please help if any body any idea about this.
have dream day

Google PageSpeed & ImageMagick JPG compression

Given a user uploaded image, I need to create various thumbnails of it for display on a website. I'm using ImageMagick and trying to make Google PageSpeed happy. Unfortunately, no matter what quality value I specify in the convert command, PageSpeed is still able to suggest compressing the image even further.
Note that http://www.imagemagick.org/script/command-line-options.php?ImageMagick=2khj9jcl1gd12mmiu4lbo9p365#quality mentions:
For the JPEG ... image formats,
quality is 1 [provides the] lowest
image quality and highest compression
....
I actually even tested compressing the image using 1 (it produced an unusable image, though) and PageSpeed still suggests that I can still optimize such image by "losslessly compressing" the image. I don't know how to compress an image any more using ImageMagick. Any suggestions?
Here's a quick way to test what I am talking about:
assert_options(ASSERT_BAIL, TRUE);
// TODO: specify valid image here
$input_filename = 'Dock.jpg';
assert(file_exists($input_filename));
$qualities = array('100', '75', '50', '25', '1');
$geometries = array('100x100', '250x250', '400x400');
foreach($qualities as $quality)
{
echo("<h1>$quality</h1>");
foreach ($geometries as $geometry)
{
$output_filename = "$geometry-$quality.jpg";
$command = "convert -units PixelsPerInch -density 72x72 -quality $quality -resize $geometry $input_filename $output_filename";
$output = array();
$return = 0;
exec($command, $output, $return);
echo('<img src="' . $output_filename . '" />');
assert(file_exists($output_filename));
assert($output === array());
assert($return === 0);
}
echo ('<br/>');
}
The JPEG may contain comments, thumbnails or metadata, which can be removed.
Sometimes it is possible to compress JPEG files more, while keeping the same quality. This is possible if the program which generated the image did not use the optimal algorithm or parameters to compress the image. By recompressing the same data, an optimizer may reduce the image size. This works by using specific Huffman tables for compression.
You may run jpegtran or jpegoptim on your created file, to reduce it further in size.
To minimize the image sizes even more, you should remove all meta data. ImageMagick can do this by adding a -strip to the commandline.
Have you also considered to put your thumbnail images as inline-d base64 encoded data into your HTML?
This can make your web page load much faster (even though the size gets a bit larger), because it saves the browser from running multiple requests for all the image files (the images) which are referenced in the HTML code.
Your HTML code for such an image would look like this:
<IMG SRC="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAM4AAABJAQMAAABPZIvnAAAABGdBTUEAALGPC/xh
BQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAA
OpgAABdwnLpRPAAAAAZQTFRFAAAA/wAAG/+NIgAAAAF0Uk5TAEDm2GYAAAABYktH
RACIBR1IAAAACXBIWXMAAABIAAAASABGyWs+AAAB6ElEQVQ4y+3UQY7bIBQG4IeQ
yqYaLhANV+iyi9FwpS69iGyiLuZYpepF6A1YskC8/uCA7SgZtVI3lcoiivkIxu/9
MdH/8U+N6el2pk0oFyibWyr1Q3+PlO2NqJV+/BnRPMjcJ9zrfJ/U+zQ9oAvo+QGF
d+npPqFQn++TXElkrEpEJhAtlTBR6dNHUuzIMhFnEhxAmJDkKxlmt7ATXDDJYcaE
r4Txqtkl42VYSH+t9KrD9b5nxZeog/LWGVHprGInGWVQUTvjDWXca5KdsowqyGSc
DrZRlGlQUl4kQwpUjiSS9gI9VdECZhHFQ2I+UE2CHJQfkNxTNKCl0RkURqlLowJK
1h1p3sjc0CJD39D4BIqD7JvvpH/GAxl2/YSq9mtHSHknga7OKNOHKyEdaFC2Dh1w
9VSJemBeGuHgMuh24EynK03YM1Lr83OjUle38aVSfTblT424rl4LhdglsUag5RB5
uBJSJBIiELSzaAeIN0pUlEeZEMeClC4cBuH6mxOlgPjC3uLproUCWfy58WPN/MZR
86ghc888yNdD0Tj8eAucasl2I5LqX19I7EmEjaYjSb9R/G1SYfQA7ZBuT5H6WwDt
UAfK1BOJmh/eZnKLeKvZ/vA8qonCpj1h6djfbqvW620Tva36++MXUkNDlFREMVkA
AAAldEVYdGRhdGU6Y3JlYXRlADIwMTItMDgtMjJUMDg6Mzc6NDUrMDI6MDBTUnmt
AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDEyLTA4LTIyVDA4OjM3OjQ1KzAyOjAwIg/B
EQAAAA50RVh0bGFiZWwAImdvb2dsZSJdcbX4AAAAAElFTkSuQmCC"
ALT="google" WIDTH=214 HEIGHT=57 VSPACE=5 HSPACE=5 BORDER=0 />
And you would create the base64 encoded image data like this:
base64 -i image.jpg -o image.b64
Google performs those calculations based on it's WebP image format (https://developers.google.com/speed/webp/).
Despite giving performance gains though, it is currently supported only by chrome and opera (http://caniuse.com/webp)

Resources