Background color when scaling / cropping. And a fix for transparent backgrounds.
FiReaNG3L - December 28, 2007 - 21:53
| Project: | ImageAPI |
| Version: | 6.x-1.x-dev |
| Component: | ImageAPI GD |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | needs review |
Description
ImageAPI.module sounds very interesting; I recently had problems with imagecache / image.inc putting a black background on images when scaling / cropping to a definite size (say 150x150 pixels) when the image is too wide or tall to fit the square.
Is there a way to customize the background to another color (say, white) with image API?
I tried to modify image.inc myself but the best I could achieve is a background change that worked, but bleeded in the image if black was present.
Thanks for all the awesome work on imagecache / imageAPI!

#1
Small followup: a search on d.o. reveals that many users have the same problem; maybe ImageAPI.module would be a nice place to fix this since they are mostly related to imagecache.module and the new version isnt using image.inc anymore!
Non-extensive list:
Imagecache Scale Problem (Black background) : http://drupal.org/node/201163
Background in cropped images : http://drupal.org/node/123270
Changing Background Color of Thumbnails Re: CCK/VIews Image Gallery : http://drupal.org/node/190235
All the workarounds thus far involve doing some other action to avoid the crop, but if thats the result you want and nothing else, you're stuck with a black background, which is ugly if your theme is white based.
Also image_exact.module (http://drupal.org/project/image_exact) states in its description : The only limitation of this implementation is that imagecache doesn't check the image size before cropping, so if someone uploads a very small image, it will "crop" to the size specified, adding a black background to fill in the dimensions. I will submit a patch to imagecache that will make this configurable.
And here's a possible fix:
Here is a Patch to avoid black backgrounds on cropped images : http://drupal.org/node/199957
#2
I'd really prefer you test the module rather than post feature requests right now. I would also be nice if you contributed this image.inc fix you attempted as a possible patch instead of just mentioning it. Code is gold and all..
#3
As I said, there's a potential fix in the last issue I linked to - image.inc should be patched, but imageAPI too because its the future of imagecache, which is the main resource using image manipulation. I will test the patch as soon as I get back home (christmas vacation and all). This issue is just to document the problem as a feature request against the dev version, so its not like the house is on fire or something :)
#4
I have successfully change background color when cropping with easy hack of Drupal core file
includes/image.inc:In function
<?phpfunction image_gd_crop($source, $destination, $x, $y, $width, $height) {
...
imageCopy($res, $im, 0, 0, $x, $y, $width, $height);
$result = image_gd_close($res, $destination, $info['extension']);
...
}
?>
add string:
<?phpfunction image_gd_crop($source, $destination, $x, $y, $width, $height) {
...
imageCopy($res, $im, 0, 0, $x, $y, $width, $height);
imageFill($res, 0, 0, imageColorAllocate($res,255,255,255) );
$result = image_gd_close($res, $destination, $info['extension']);
...
}
?>
When I try to add imageFill function before imageCopy, i see black backgrond. But when I add it after imageCopy, all works good.
Numbers
255,255,255you can change to any RGB color values as you want.#5
This issue doesn't solve problem with black backgrounds, it's avoid clipping if size of clip area large than image.
#6
Another (better) method to fill background with some color:
In function
<?phpfunction image_gd_crop($source, $destination, $x, $y, $width, $height) {
...
$res = imageCreateTrueColor($width, $height);
imageCopy($res, $im, 0, 0, $x, $y, $width, $height);
$result = image_gd_close($res, $destination, $info['extension']);
...
}
?>
add string:
<?phpfunction image_gd_crop($source, $destination, $x, $y, $width, $height) {
...
$res = imageCreateTrueColor($width, $height);
imagefilledrectangle($res, 0, 0, $width, $height, imagecolorallocate($res,255,255,255) );
imageCopy($res, $im, 0, 0, $x, $y, $width, $height);
$result = image_gd_close($res, $destination, $info['extension']);
...
}
?>
#7
I've tried this, and not been able to make it work... Nothing at all happens... Any idea as to what I could be doing wrong? I'm using Imagecache 1.3 on Drupal 5.6.
I tried the other hack you posted, and that worked like a charm - that is, until I uploaded an image consisting mainly of black... Apparently, imageFill doesn't handle alpha-colors too well...
Nevertheless; if you (or anyone else for that matter) have any more ideas on how to make this work, it would be greatly appreciated! It's such a bummer going back to the black background images after having it "working" sweetly for a while ;)
Thanks
joeboris
#8
#4 works partially (see attachment)
#6 no change.
Now I'll try both.
--------------------------
Velvet Cushion
#9
adresaklumea, I create another method for filling background when cropping, it should be work good with half -transparent png's too. Try my new patch and feedback please about it works.
You must set background color as HTML color in string
<?php$bg_color = variable_get('image_crop_background', '#FF0000');
?>
or set a Drupal variable 'image_crop_background' to HTML color you need.
This patch is for Drupal 5.7 core, not for ImageAPI module.
#10
Beautiful, works like a charm
10*e99 thanks
#11
How to patch the ImageAPI ?
#12
I tried the patch in #9 but my whole site goes down and I get the following error messages:
Warning: require_once(./includes/image.inc) [function.require-once]: failed to open stream: Permission denied in drupal\includes\common.inc on line 1850
Fatal error: require_once() [function.require]: Failed opening required './includes/image.inc' (include_path='.;C:\php5\pear') in drupal\includes\common.inc on line 1850
Which is really strange I don't know where this comes from? I am using the 5.7 Drupal.
#13
This is a patch for imageapi to set the background color for cropping.
At now you can set the color manually in source code by modifying this string:
<?php$color=array('red'=>255,'green'=>255,'blue'=>255,'alpha'=>0);
?>
And this patch have a workaround with wrong image size for function
imagecopyresampled()when cropping.#14
Thank you again.
you rock!
#15
This still isn't quite the right solution... I'm tempted to split canvas resize and crop into seperate functions and not allow oversized crops.... and have an explicit set background for canvas resizing that inherits from the image->res if unset.
regardless this breaks background transparency preservation in it current state.
.darrel.
#16
Subscribing,
The patch in #9 works for me, using Imagecache 5.x-1.6 and Drupal 5.9. FWIW I use scaling to outside dimensions followed by cropping slightly smaller. The background now blends nicely.
I assume the plan is to make the string value assignable in the image toolkit admin page?
Something along the lines of
<?php
function image_gd_settings() {
…
$form['image_crop_background'] = array(
'#type' => 'textfield',
'#title' => t('Background color'),
'#description' => t('Define the image background color for manipulations. Values need to be hexdecimal, eg #FFFFFF is white.'),
'#size' => 7,
'#maxlength' => 7,
'#default_value' => variable_get('image_crop_background', "#FFFFFF"),
);
…
}
?>
A couple of random thoughts…
The default should be probably white, since it would sit well with default theme(s).
The # should be removed from the field and only the 6 characters are saved for the color variable, eg ff00ff I think we can use a field prefix to display the # at the start of the field.
@ dopry, I didn't realize there was transparency, my images seem to end up with a black background when cropping oversize. Is there anything I can do, this strikes me as a nice feature to get into core, I'd easily use it on all my sites.
Drew
#17
I have edited the patch for support imageapi-5.x-1.2 and add an option in imageapi_gd settings to set background color manually. It's worked for me and, I hope, help others.
#18
this would really need to go into HEAD (6.x-1.x) and be backported.
#19
Looking at #7, It's wrong to use variable_set/get for this which should be a per-preset setting.
Anyway...
I've tweaked imageapi to :
- Properly support transparent inputs - it just wasn't doing it before. Now if you crop a PNG or GIF the background will remain transparent - even if cropped to a larger size. There was code there to support this but it seems to have rotted away at some point and stopped doing it properly.
- Allow crop to larger dimensions : behave like "set canvas size" - without creating huge black chunks. Jpegs still create white chunks, but that's less ugly usually.
It involved moving jpeg handling over next to png handling (truecolor), as the previous index transparency only works on GIFs AFAIK.
In the future, setting the preferred bg color via the UI is still a TODO
Patch is against todays HEAD/6-dev
Index: imageapi_gd.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imageapi/imageapi_gd.module,v
retrieving revision 1.12
diff -u -p -r1.12 imageapi_gd.module
--- imageapi_gd.module 9 Jul 2008 02:49:47 -0000 1.12
+++ imageapi_gd.module 9 Oct 2008 07:28:38 -0000
@@ -32,6 +32,10 @@ function imageapi_gd_settings_form() {
function imageapi_gd_image_open($image) {
if ($image->res = _gd_open($image->source, $image->info['extension'])) {
+ // Retain transparency for PNGs
+ if ($image->info['extension'] == 'png') {
+ imagesavealpha($image->res, TRUE);
+ }
return $image;
}
return false;
@@ -44,7 +48,11 @@ function imageapi_gd_image_close($image,
function imageapi_gd_image_crop(&$image, $x, $y, $width, $height) {
$res = _gd_create_tmp($image, $width, $height);
- if (!imagecopyresampled($res, $image->res, 0, 0, $x, $y, $width, $height, $width, $height)) {
+ // Support 'cropping' to a size larger than the source - but do not copy null values into new canvas - so PNGs and GIFs can remain transparent.
+ $targetwidth = min($image->info['width'], $width);
+ $targetheight = min($image->info['height'], $height);
+
+ if (!imagecopyresampled($res, $image->res, 0, 0, $x, $y, $targetwidth, $targetheight, $targetwidth, $targetheight)) {
return false;
}
// destroy the original image and return the modified image.
@@ -134,7 +142,7 @@ if (!function_exists('imagefilter')) {
function _gd_create_tmp($image, $width, $height) {
$res = imagecreatetruecolor($width, $height);
- if ($image->info['extension'] == 'gif' || $image->info['extension'] == 'jpg') {
+ if ($image->info['extension'] == 'gif') {
// grab transparent color index from src.
$transparent = imagecolortransparent($image->res);
@@ -142,22 +150,23 @@ function _gd_create_tmp($image, $width,
if ($transparent >= 0) {
// get color(r,g,b) for index;
$transparent = imagecolorsforindex($image->res, $transparent);
- // allocate to new image and get new index.
- $transparent = (isset($color['alpha']))
- ? imagecolorallocatealpha($res, $color['red'], $color['green'], $color['blue'], $color['alpha'])
- : imagecolorallocate($res, $color['red'], $color['green'], $color['blue']);
+ // Allocate the values to the new image and get new color.
+ $transparent = (isset($transparent['alpha']))
+ ? imagecolorallocatealpha($res, $transparent['red'], $transparent['green'], $transparent['blue'], $transparent['alpha'])
+ : imagecolorallocate($res, $transparent['red'], $transparent['green'], $transparent['blue']);
- $transparent = imagecolorallocate($res, $transparent['red'], $transparent['green'], $transparent['blue']);
// flood with our new transparent color.
imagefill($res, 0, 0, $transparent);
// tell the new image which color is transparent.
imagecolortransparent($res, $transparent);
}
}
- elseif ($image->info['extension'] == 'png') {
+ elseif ($image->info['extension'] == 'png' || $image->info['extension'] == 'jpg') {
+ imagesavealpha($res, true);
imagealphablending($res, false);
- $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
- imagefill($res, 0, 0, $transparency);
+ $transparency = imagecolorallocatealpha($res, 255, 255, 255, 127);
+ #imagefill($res, 0, 0, $transparency); // imagefill doesn't always work with transparent apparently
+ imagefilledrectangle($res, 0, 0, $width, $height, $transparency);
imagealphablending($res, true);
imagesavealpha($res, true);
}
#20
Input on patch #19...
If you set the X offset to right than a black background is added to the left and the image is cropped.
Steps to reproduce:
The image should be surround at left & bottom by a white background. At bottom is OK but on X axis it adds white background to right and black background to left. Also it reduces the X dimension by cropping the image.
#21
But... it works fine with X offset set to left
#22
Input for #19 and #20, I had the same problem but found I could make everything work (left, right, and center) by changing:
<?phpif (!imagecopyresampled($res, $image->res, 0, 0, $x, $y, $targetwidth, $targetheight, $targetwidth, $targetheight))
?>
to
<?phpif (!imagecopyresampled($res, $image->res, 0, 0, $x*(-1), $y*(-1), $targetwidth, $targetheight, $targetwidth, $targetheight))
?>
Attached is a new patch with this change.
#23
For CENTRING I have applied patch from #22 and change one row in function imageapi_gd_image_crop from
<?phpif (!imagecopyresampled($res, $image->res, 0, 0, $x*(-1), $y*(-1), $targetwidth, $targetheight, $targetwidth, $targetheight))
?>
to
<?phpif (!imagecopyresampled($res, $image->res, ($width-$image->info['width'])/2-$x, ($height-$image->info['height'])/2-$y, ($x)*(-1), $y*(-1), $targetwidth, $targetheight, $targetwidth, $targetheight)) {
?>
and all work fine for me)
I use drupal 6
#24
How's this? Moving this to critical since it's been an issue for so long. Here's a patch as well as a screenshot.
The patch was created from HEAD.
#25
I'd like some extra comments so it's clear what's happening there. why are/were we passing the $width, $height parameters if we're using $image->info['height'], $image->info['width']?
#26
Here we go. This patch says why we're using the source width and height instead of the destination width and height. Think we should remind people that we're cropping here and not scaling? Or is that good? I thought it made sense.....
#27
the comments look better... but looking at the docs for imagecopyresampled() it references them as the src and dest sizes so wouldn't the first set be $height and $width and the second be $image['height'] and $image['width']?
this has me really wishing we had some unit tests to validate some of these type of changes.
and if we're adding a feature we need to add it to the imagemagick api or at least determine that it's unsupported by IM...
#28
I've been wishing for unit tests for my image processes also ... but I just cannot imagine how to validate that the produced image is what I expected :-)
#29
dman: maybe check the output / md5 with http://ca.php.net/function.file-get-contents compared to an 'expected' image from a source image
#30
Byte/hash matching won't really help for JPEG algorithms against different builds, libraries, image toolkits, compression preferences, OS etc.
:-(
#31
Andrew: We're using the same width and height for both the source and destination because we are cropping, not scaling. If we were scaling, we'd use different source/destination widths and heights.
#32
that makes sense. okay this looks pretty good to me. committed to HEAD. thanks!
#33
Yeah, should've included that as part of the patch with the added documentation. Thanks a lot, Drewish.
#34
Automatically closed -- issue fixed for two weeks with no activity.
#35
This patch is not in the latest 1.x-dev? Updated patch for this.
#36
Above patch works for png and jpg, but not for gif images. Im scaling images to fit e.g. 100x100, and then cropping to 100x100. See attached gif images problem: only the top part gets the #FFF background I set in the ImageAPI config page. The bottom part is still black. Why doesnt it apply the set background color for the entire image, why only the top part?
#37
Updated to latest in DRUPAL-6--1.
#38
Subsc
#39
The #37 patch works for me. Thanks a lot.
#40
Subscribing
PS. Is this related to #422836: ImageAPI GD2 6.x-1.5 ignores crop background color setting ?
#41
Subscribing