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

FiReaNG3L - December 28, 2007 - 22:00

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

dopry - December 29, 2007 - 16:16

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

FiReaNG3L - December 30, 2007 - 00:53

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

Murz - February 28, 2008 - 10:05

I have successfully change background color when cropping with easy hack of Drupal core file includes/image.inc:
In function

<?php
function 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:
<?php
function 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,255 you can change to any RGB color values as you want.

#5

Murz - February 28, 2008 - 10:07

Here is a Patch to avoid black backgrounds on cropped images : http://drupal.org/node/199957

This issue doesn't solve problem with black backgrounds, it's avoid clipping if size of clip area large than image.

#6

Murz - March 14, 2008 - 10:12

Another (better) method to fill background with some color:
In function

<?php
function 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:

<?php
function 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

joeboris - March 24, 2008 - 11:05

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

adresaklumea - April 4, 2008 - 22:31

#4 works partially (see attachment)
#6 no change.
Now I'll try both.
--------------------------
Velvet Cushion

AttachmentSize
Sweetheart-Leather.jpg 10.9 KB

#9

Murz - April 7, 2008 - 07:58

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.

AttachmentSize
image_crop_transparent_1.patch 1.27 KB

#10

adresaklumea - April 10, 2008 - 13:28

Beautiful, works like a charm
10*e99 thanks

#11

adresaklumea - May 23, 2008 - 19:50

How to patch the ImageAPI ?

#12

reed.richards - May 25, 2008 - 11:04

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

Murz - May 27, 2008 - 06:40

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.

AttachmentSize
imageapi-5.x-1.1_crop_background.patch 2.58 KB

#14

adresaklumea - May 28, 2008 - 18:34

Thank you again.
you rock!

#15

dopry - May 29, 2008 - 20:03
Status:active» needs work

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

drew reece - August 11, 2008 - 00:30

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

Murz - September 2, 2008 - 09:36

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.

AttachmentSize
imageapi-5.x-1.2_crop_background_1.patch 4.35 KB

#18

drewish - September 2, 2008 - 16:59
Version:5.x-1.x-dev» 6.x-1.x-dev

this would really need to go into HEAD (6.x-1.x) and be backported.

#19

dman - October 9, 2008 - 07:34
Title:Background color when scaling / cropping - customizable?» Background color when scaling / cropping. And a fix for transparent backgrounds.
Status:needs work» needs review

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);
   }

AttachmentSize
imageapi-transparent_backgrounds-20081009.patch 3.57 KB

#20

claudiu.cristea - November 6, 2008 - 10:50

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:

  • Source image: 100px x 100px
  • Add a preset with a CROP action
  • Set the Crop action to...
    • With: 120px
    • Height: 120px
    • X offset: right
    • Y offset: top

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

claudiu.cristea - November 6, 2008 - 11:16

But... it works fine with X offset set to left

#22

tylor - November 15, 2008 - 04:39

Input for #19 and #20, I had the same problem but found I could make everything work (left, right, and center) by changing:

<?php
if (!imagecopyresampled($res, $image->res, 0, 0, $x, $y, $targetwidth, $targetheight, $targetwidth, $targetheight))
?>

to

<?php
if (!imagecopyresampled($res, $image->res, 0, 0, $x*(-1), $y*(-1), $targetwidth, $targetheight, $targetwidth, $targetheight))
?>

Attached is a new patch with this change.

AttachmentSize
imageapi-transparent_backgrounds_02.patch 3.58 KB

#23

VVVi - December 3, 2008 - 08:49

For CENTRING I have applied patch from #22 and change one row in function imageapi_gd_image_crop from

<?php
if (!imagecopyresampled($res, $image->res, 0, 0, $x*(-1), $y*(-1), $targetwidth, $targetheight, $targetwidth, $targetheight))
?>

to

<?php
  
if (!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

Rob Loach - December 5, 2008 - 22:03
Priority:normal» critical

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.

AttachmentSize
204497.patch 2.19 KB
cropbackground.png 37.73 KB

#25

drewish - December 6, 2008 - 02:46

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

Rob Loach - December 8, 2008 - 19:28

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.....

AttachmentSize
204497.patch 2.42 KB

#27

drewish - December 8, 2008 - 21:02
Status:needs review» needs work

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

dman - December 8, 2008 - 21:47

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

FiReaNG3L - December 9, 2008 - 05:18

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

dman - December 9, 2008 - 06:15

Byte/hash matching won't really help for JPEG algorithms against different builds, libraries, image toolkits, compression preferences, OS etc.
:-(

#31

Rob Loach - December 15, 2008 - 16:59

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

drewish - December 15, 2008 - 21:39
Status:needs work» fixed

that makes sense. okay this looks pretty good to me. committed to HEAD. thanks!

#33

Rob Loach - December 15, 2008 - 22:14

Yeah, should've included that as part of the patch with the added documentation. Thanks a lot, Drewish.

#34

System Message - December 29, 2008 - 22:20
Status:fixed» closed

Automatically closed -- issue fixed for two weeks with no activity.

#35

edmund.kwok - August 17, 2009 - 09:30
Priority:critical» normal
Status:closed» needs review

This patch is not in the latest 1.x-dev? Updated patch for this.

AttachmentSize
imageapi_background_color.patch 1.9 KB

#36

morningtime - October 6, 2009 - 08:32

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?

AttachmentSize
pgmatch.gif 6.91 KB
pgmatch_7.gif 1.84 KB

#37

Rob Loach - October 8, 2009 - 21:05

Updated to latest in DRUPAL-6--1.

AttachmentSize
imageapibackground.patch 2.03 KB

#38

R.Muilwijk - October 13, 2009 - 13:06

Subsc

#39

omo - November 6, 2009 - 15:18

The #37 patch works for me. Thanks a lot.

#40

p.brouwers - November 17, 2009 - 09:39

#41

Bobuido - November 21, 2009 - 12:58

Subscribing

 
 

Drupal is a registered trademark of Dries Buytaert.