Codeigniter image manipulation class rotates image during resize - codeigniter

I'm using Codeigniter's image manipulation library to re-size an uploaded image to three sizes, small, normal and large.
The re-sizing is working great. However, if I'm resizing a vertical image, the library is rotating the image so it's horizontal.
These are the config settings I have in place:
$this->resize_config['image_library'] = 'gd2';
$this->resize_config['source_image'] = $this->file_data['full_path'];
$this->resize_config['maintain_ratio'] = TRUE;
// These change based on the type (small, normal, large)
$this->resize_config['new_image'] = './uploads/large/'.$this->new_file_name.'.jpg';
$this->resize_config['width'] = 432;
$this->resize_config['height'] = 288;
I'm not setting the master_dim property because the default it set to auto, which is what I want.
My assumption is that the library would take a vertical image, see that the height is greater than the width and translate the height/width config appropriately so the image remains vertical.
What is happening (apparently) is that the library is rotating the image when it is vertical and sizing it per the configuration.
This is the code in place I have to do the actual re-sizing:
log_message('debug', 'attempting '.$size.' photo resize');
$this->CI->load->library('image_lib');
$this->CI->image_lib->initialize($this->resize_config);
if ($this->CI->image_lib->resize())
{
$return_value = TRUE;
log_message('debug', $size.' photo resize successful');
}
else
{
$this->errors[] = $this->CI->image_lib->display_errors();
log_message('debug', $size.' photo resize failed');
}
$this->CI->image_lib->clear();
return $return_value;
EDIT
I think the problem may be from the upload library. When I get the image_height and image_width back from the upload, the width seems to be larger even though I uploaded a vertical image.
This is a portion of the code I'm using to upload the photo:
$this->upload_config['allowed_types'] = 'jpg|jpeg';
$this->upload_config['max_size'] = '2000';
$this->upload_config['max_width'] = '0';
$this->upload_config['max_height'] = '0';
$this->upload_config['upload_path'] = './uploads/working/';
$this->CI->load->library('upload', $this->upload_config);
if ($this->CI->upload->do_upload($this->posted_file))
{
$this->file_data = $this->CI->upload->data();
$return_value = TRUE;
log_message('debug', 'upload successful');
}
I added some logging to check the values:
$this->is_vertical = $this->file_data['image_height'] > $this->file_data['image_width'];
log_message('debug', 'image height:'.$this->file_data['image_height']);
log_message('debug', 'image width:'.$this->file_data['image_width']);
if ($this->is_vertical)
{
$this->resize_config['master_dim'] = 'height';
}
else
{
$this->resize_config['master_dim'] = 'width';
}
log_message('debug', 'master_dim setting:'.$this->resize_config['master_dim']);
These are the results of the log:
DEBUG - 2010-03-16 18:35:06 --> image height:1536
DEBUG - 2010-03-16 18:35:06 --> image width:2048
DEBUG - 2010-03-16 18:35:06 --> master_dim setting:width
Looking at the image in photoshop, these are the dimensions:
height: 2048
width: 1536
Anyone know what might be causing the upload library to do this?

I've never used this library, but having read the documentation, I wonder whether the master_dim property might help. If you set this to 'height' for vertical images that might keep them the right way up. You could just parse each image through a conditional to see if the image is vertically aligned and then only set this property if need be.
My other thought is about the maintain_ratio property. The documentation says that with this set to 'TRUE' it will resize as close to the target values as possible whilst maintaining the aspect ratio. I wonder if it thinks that rotating the image allows it to preserve this ratio more accurately? As an experiment, try setting this value to 'FALSE' for vertical images.

Ok - I decided not to trust photoshop and opened the images I was testing in quicktime and safari. I discovered that they were actually still horizontal.
So Codeigniter was operating exactly as expected.
I went back into photoshop, did a save for web on the test images, re-uploaded them and it worked as expected.
I then stripped out the extra code that I had added to test whether the image was vertical and the library works as I expected it would.
Now - I need to figure out how to prevent end users from doing this exact thing.
Thanks for taking the time to answer my question musoNic80. Hopefully someone else can learn from my mistakes here.

Related

How to improve display quality in pdf.js

I'm using open source library for PDF documents from mozilla(pdf.JS).
When i'm trying to open pdf documents with bad quality, viewer displays it with VERY BAD quality.
But if I open it in reader, or in browser (drag/drop into new window), whis document displays well
Is it possible to change?
Here is this library on github mozilla pdf.js
You just have to change the scaling of your pdf i.e. when rendering a page:
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
...
It is the scale value you have to change. Then, the resulting rendered image will fit into the canvas given its dimensions e.g. in CSS. What this means is that you produce a bigger image, fit it into the container you had before and so you effectively improve the resolution.
There is renderPage function in web/viewer.js and print resolution is hard-coded in there as 150 DPI.
function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size) {
var scratchCanvas = activeService.scratchCanvas;
var PRINT_RESOLUTION = 150;
var PRINT_UNITS = PRINT_RESOLUTION / 72.0;
To change print resolution to 300 DPI, simply change the line below.
var PRINT_RESOLUTION = 300;
See How to increase print quality of PDF file with PDF.js viewer for more details.
Maybe it's an issue related with pixel ratio, it used to happen to me when device pixel ratio is bigger than 1 (for example iPhone, iPad, etc.. you can read this question for a better explanation.
Just try that file on PDF.js Viewer. If it works like expected, you must check how PDF.js works with pixel ratio > 1 here. What library basically does is:
canvas.width = viewport.width * window.devicePixelRatio;
canvas.styles.width = viewport.width + 'px'; // Note: The px unit is required here
But you must check how PDF.js works for better perfomance
I ran into the same issue and I used the intent option of renderContent to fix that.
const renderContext = {
intent: 'print',
// ....
}
var renderTask = page.render(renderContext);
As per docs renderContext accepts intent which supports three values - display, print or any. The default is display. When I used print instead the render quality was extremely good, at par with any desktop app.

Codeigniter - Re-sizing multiple images works, but wrong sizes?

I'm trying to resize a fullsize image poster into three smaller variants of the file. I first save the fullsize poster, then i use it's path to create the smaller ones. The problem is that the sizes are incorrect. I have a $conf array containing general config info for all images, and then i have a $conf array for each image with specific changes (eg. size). I clear the lib before every new init.
// Config for all images
$conf['source_image'] = $file_path;
$conf['quality'] = 80;
$conf['maintain_ratio'] = true;
$conf['master_dim'] = 'auto';
// Small
$conf['new_image'] = 'img/movie_images/posters_small/' . $file_name;
$conf['height'] = 75;
//$conf['width'] = 55;
$this->image_lib->initialize($conf);
$this->image_lib->resize();
$this->image_lib->clear();
//unset($conf['width']);
// Medium
$conf['new_image'] = 'img/movie_images/posters_medium/' . $file_name;
$conf['height'] = 200;
$this->image_lib->initialize($conf);
$this->image_lib->resize();
$this->image_lib->clear();
// Big
$conf['new_image'] = 'img/movie_images/posters_big/' . $file_name;
$conf['height'] = 300;
$this->image_lib->initialize($conf);
$this->image_lib->resize();
$this->image_lib->clear();
See any errors in the code? I tried outputting errors as someone advised in another question here, but that didn't show anything either. I don't understand how it works really. If i set "master_dim" to auto, the first (the small) image get's the right height, but the default width (which is really really wide). If i set master_dim to "width", the small image stays the same (really wide, but correct height). If i set master_dim to "height" they all get the correct height, but the small one still is super wide.
Any ideas?
As you can see in the code i tried playing around with the width of the small image to get it's correct size, but didn't get it to work.
After setting master_dim to height, and also setting the width of the small image manually, it works as i want it to.
You can download the image library from http://thephpcode.com/blog/codeigniter/gradient-image-library-for-codeigniter to convert the image to fit in to a correct width and size.

Magento resize() image quality: dirty white background

I have a client who is seriously unhappy with the way their product thumbnails are rendering on Magento.
The dodgy appearance is noticeable on two accounts:
there is a dirty white background which has very light grey horizontal lines
and secondly there is ever so slight color loss (loses contrast and saturation).
I have removed ALL compression, set ALL quality to 100%, flushed image cache, experimented, broken, and fixed it all dozens of times, and nothing seems to work.
This version of Magento is ver. 1.4.2.0
Is anyone out here experiencing the same problems, and if so have you managed to fix it?
The problem has to do with the php function imagecopyresampled in the resize function inside lib/Varien/Image/Adapter/Gd2.php, there are some rounding issues that occur to make a smoothly resized image.
My solution is to simply change any very light grey pixels in the image to pure white after the image has been resized. To do so first copy lib/Varien/Image/Adapter/Gd2.php to app/code/local/Varien/Image/Adapter/Gd2.php
Next find the following code inside the resize function (around line 312)
// resample source image and copy it into new frame
imagecopyresampled(
$newImage,
$this->_imageHandler,
$dstX, $dstY,
$srcX, $srcY,
$dstWidth, $dstHeight,
$this->_imageSrcWidth, $this->_imageSrcHeight
);
Then add the following code underneath:
// Clean noise on white background images
if ($isTrueColor) {
$colorWhite = imagecolorallocate($newImage,255,255,255);
$processHeight = $dstHeight+$dstY;
$processWidth = $dstWidth+$dstX;
//Travel y axis
for($y=$dstY; $y<($processHeight); ++$y){
// Travel x axis
for($x=$dstX; $x<($processWidth); ++$x){
// Change pixel color
$colorat=imagecolorat($newImage, $x, $y);
$r = ($colorat >> 16) & 0xFF;
$g = ($colorat >> 8) & 0xFF;
$b = $colorat & 0xFF;
if(($r==253 && $g == 253 && $b ==253) || ($r==254 && $g == 254 && $b ==254)) {
imagesetpixel($newImage, $x, $y, $colorWhite);
}
}
}
}
Flush the images cache from the Cache management in Magento, and you should have nicer images for the new displays. Few things to note when implementing this, there is a small performance hit the first time you generate the images again, and images with shadows may have sharper edges as the very light greys have been removed.
try following example
echo Mage::helper('catalog/image')->init($product, 'small_image')->resize(180, 210)->setQuality(50);
You can put your own Gd2.php file in local (app/code/local/Varien/Image/Adapter/Gd2.php) and hard-wire the quality to 100%.
Quality is working for me so I have not done that.
You can also put an image convolution in there to sharpen your images, in that way you get the blur of a resize compensated for with a sharpen, e.g. put the following just inside the end of the 'resize' function:
$sharpenMatrix = array(array(-1,-1,-1),array(-1,24,-1),array(-1,-1,-1));
$divisor = 16;
$offset = 0;
imageconvolution($newImage, $sharpenMatrix, $divisor, $offset);
I had problems with images quality on one of projects. But the problem was not on back-end, but on the front-end. Images had bad quality because images width and height given in the CSS was not the same as the image file had.
quick grep shows that you are able to set this on product_image object
app/code/core/Mage/Catalog/Helper/Image.php:105: * Set image quality, values in percentage from 0 to 100
app/code/core/Mage/Catalog/Helper/Image.php:107: * #param int $quality
app/code/core/Mage/Catalog/Helper/Image.php:110: public function setQuality($quality)
app/code/core/Mage/Catalog/Helper/Image.php:112: $this->_getModel()->setQuality($quality);
app/code/core/Mage/Catalog/Model/Product/Image.php:38: protected $_quality = 90;
app/code/core/Mage/Catalog/Model/Product/Image.php:88: * Set image quality, values in percentage from 0 to 100
app/code/core/Mage/Catalog/Model/Product/Image.php:90: * #param int $quality
app/code/core/Mage/Catalog/Model/Product/Image.php:93: public function setQuality($quality)
app/code/core/Mage/Catalog/Model/Product/Image.php:95: $this->_quality = $quality;
app/code/core/Mage/Catalog/Model/Product/Image.php:100: * Get image quality
app/code/core/Mage/Catalog/Model/Product/Image.php:106: return $this->_quality;
app/code/core/Mage/Catalog/Model/Product/Image.php:331: 'quality' . $this->_quality
app/code/core/Mage/Catalog/Model/Product/Image.php:387: $this->_processor->quality($this->_quality);
I had the same issue with some of my images, later i realized that those images with lower resolution were getting distorted, try using an image more than 1100 X 1100 and it should work just fine !
Upload the images as PNG's. They may not be as small as JPG, but it allowed us to avoid some image quality issues created by Magento's resizing functionality.

How do I improve quality when using RMagick/ImageMagick to convert from SVG to PDF?

I use Rubyvis to generate SVG plots, and then allow the user to save either to SVG directly, or to some other format using RMagick.
The SVG plots have a set size, which is specified in the SVG file. It seems to me, then, that it should be trivial to convert to a PDF of the same size.
Unfortunately, this appears not to be the case. I can produce a PDF in this manner, but it is much larger (dimension-wise) than the PDFs produced if I first open the SVG in inkscape and then print-to-file as a PDF.
Worse, the PDF image quality is terrible.
Am I missing some instruction for Magick? Here's the code:
image = Magick::Image::from_blob(svg_string_data) { self.format = 'SVG' }
image[0].format = 'PDF'
image[0].to_blob
I then write the value returned (the PDF blob) directly into a file.
The answer comes to you based on a tip from cptjazz on github.
First of all, the documentation for RMagick is often wrong. I doubt this is a version problem, because the ImageMagick-hosted docs are v2.12.0, and I'm using v2.13.1. Either way, here is what you need to know.
The docs claim you can use image[0]['pdf', 'use-cropbox'] = true, since true.to_s yields the String 'true'. In fact, it needs an explicit string, and the []= method takes only one key, not two.
I did not experiment with pdf:use-trimbox, mainly because I wanted an option that also works for postscript. For postscript, you should be able to amend it only slightly, and set ps:use-cropbox to 'true', but RMagick's docs are unclear as to how one may properly set the geometry on a PS, PS2, or PS3. (Normally in ImageMagick, one would set the density to '300x300' and the geometry to '24%', supposedly.) And for some reason, PS3-format output files do not scale as well as the PDFs produced by RMagick. But I digress.
Here is what I used for PDF:
image = Magick::Image::from_blob(svg_string) { self.format = 'SVG' }
image[0].format = 'PDF'
image[0]["use-cropbox"] = 'true'
image[0].to_blob
And here is what I used for PS:
image = Magick::Image::from_blob(svg_string) { self.format = 'SVG' }
page = image[0].page.dup
image[0]["use-cropbox"] = 'true'
image[0].format = 'PS3'
image[0].density = '100x100'
image[0].page = page
image[0].to_blob
For some reason, setting a higher density makes the image smaller. Why that should be is a mystery.

Photoshop Action to fill image to make a certain ratio

I am looking to make a photoshop action (maybe this isn't possible, any other application recommendations would be helpful as well). I want to take a collection of photos and make them a certain aspect ration, ex: 4:3.
So I have an image that is 150px wide by 200px high. What I would like to happen is the image's canvas is made to be 267px wide, with the new area filled with a certain color.
So there are two possibilities I can think of:
1) Photoshop actions could do this, but I would have to pull current height, multiply by 1.333333 and then put that value in the width box of the canvas resize. Is it possible to have calculated values in Photoshop actions?
2) Some other application has this feature built in.
Any help is greatly appreciated.
Wow, I see now (after writing the answer) that this was asked a long time ago. . . oh well. This script does the trick.
This Photoshop script will resize any image's canvas so that it has a 4:5 aspect ratio. You can change the aspect ratio applied by changing arWidth and arHeight. The fill color will be set to the current background color. You could create an action to open a file, apply this script, then close the file to do a batch process.
Shutdown Photoshop.
Copy this javascript into a new file named "Resize Canvas.jsx" in Photoshop's Presets\Scripts folder.
Start Photoshop and in the File - Scripts menu it should appear.
#target photoshop
main ();
function main ()
{
if (app.documents.length < 1)
{
alert ("No document open to resize.");
return;
}
// These can be changed to create images with different aspect ratios.
var arHeight = 4;
var arWidth = 5;
// Apply the resize to Photoshop's active (selected) document.
var doc = app.activeDocument;
// Get the image size in pixels.
var pixelWidth = new UnitValue (doc.width, doc.width.type);
var pixelHeight = new UnitValue (doc.height, doc.height.type);
pixelWidth.convert ('px');
pixelHeight.convert ('px');
// Determine the target aspect ratio and the current aspect ratio of the image.
var targetAr = arWidth / arHeight;
var sourceAr = pixelWidth / pixelHeight;
// Start by setting the current dimensions.
var resizedWidth = pixelWidth;
var resizedHeight = pixelHeight;
// The source image aspect ratio determines which dimension, if any, needs to be changed.
if (sourceAr < targetAr)
resizedWidth = (arWidth * pixelHeight) / arHeight;
else
resizedHeight = (arHeight * pixelWidth) / arWidth;
// Apply the change to the image.
doc.resizeCanvas (resizedWidth, resizedHeight, AnchorPosition.MIDDLECENTER);
}
Mind that the accepted answer from #user268911 may not work for you if the source image has different pixels/inch than 72. Because the UnitValue.convert function works correctly only with 72 px/inch. To be sure the conversion is correct for ever pixel/inch value, set baseUnit property as follows:
...
var pixelWidth = new UnitValue (doc.width, doc.width.type);
pixelWidth.baseUnit = UnitValue (doc.width.baseUnit, "in");
var pixelHeight = new UnitValue (doc.height, doc.height.type);
pixelHeight.baseUnit = UnitValue (doc.height.baseUnit, "in");
...
For more details about the conversion see "Converting pixel and percentage values" section of the Adobe JavaScript Tools Guide.
What languages do you know? ImageMagick has command line tools that can do this, but you'd need to know a scripting language to get the values and calculate the new ones.
For .NET, my company's product, DotImage Photo, is free and can do this (need to know C# or VB.NET)

Resources