Note:
I want to create custom graphic by putting together a background image with a polygon and some texts.
Input background images are of varied dimensions and aspect-ratios, but the final graphic has to be of a fixed (2:1) aspect ratio (it also has to be of pre-defined dimensions, but resizing of image is trivial, so correct aspect ratio is my only target).
Presently I'm cropping-to-fit my input image to target aspect ratio (2:1) by performing max-center area cropping using imagecrop
function. Thereafter I draw red polygon on it as shown below (ignore the texts drawn on red band) using imagefilledpolygon
method [cropping screenshot below is for demonstration purpose only, it is actually being done programmatically via imagecrop
function]
Here's my function that draws the overlay (this function is called after cropping of image to 2:1 aspect ratio is done)
/**
* adds overlay (colored band) on the image
* for better output, overlay must be added before resizing
*/
public function withOverlay(): NotifAdsCreativeGenerator {
// Prepare custom red-color Hex to RGB https://stackoverflow.com/a/15202130/3679900
list($r, $g, $b) = sscanf(self::OVERLAY_COLOR, "#%02x%02x%02x");
$custom_red_color = imagecolorallocate($this->getCrrImage(), $r, $g, $b);
// prepare coordinates for polygon
$coords = [
[0, 0],
[(int) ($this->getCrrWidth() * self::OVERLAY_BEGIN_X_RATIO), 0],
[(int) ($this->getCrrWidth() * self::OVERLAY_END_X_RATIO), $this->getCrrHeight()],
[0, $this->getCrrHeight()]
];
$flattened_coords = array_merge(...$coords);
// draw polygon on image
imagefilledpolygon($this->getCrrImage(), $flattened_coords, count($flattened_coords) / 2, $custom_red_color);
return $this;
}
But what I want is to crop the image to ~ 1.28:1 aspect ratio (the approx ratio of right part of graphic without the red band) and then draw the polygon (extending) outside the image so as to obtain the final graphic in the same same 2:1 aspect ratio as shown below
I'm able to crop image to my desired aspect ratio (1.28:1) but I can't figure out a way to draw the polygon outside the image bounds (effectively expanding the image in the process). Is there a way to do this using PHP-GD library?
It was just a lack of understanding (about working of PHP-GD, available methods) on my part, but the solution is pretty simple
imagecreatetruecolor
functionimagecopy
method (some basic maths has to be done to determine the offset where the image has to be placed on canvas)/**
* adds overlay (colored band) on the image
* for better output, overlay must be added before resizing
*
* This method tries to preserve maximum center region of input image by performing minCenterCrop(.) on it
* before drawing an overlay that extends beyond left border of the cropped image
*
* (since this method incorporates call to 'withMinCenterCrop', calling that method before this is not required
* (and is redundant). For benefits of this method over 'withOverlay', read docstring comment of
* 'withMinCenterCrop' method
* @return NotifAdsCreativeGenerator
*/
public function withExtendedOverlay(): NotifAdsCreativeGenerator {
// perform min center crop to the 1.28:1 aspect ratio (preserve max central portion of image)
$this->withMinCenterCrop();
// this $required_canvas_aspect_ratio calculates to 2.0 (2:1 aspect ratio)
// calculate aspect ratio & dimensions of empty 'canvas' image
// since canvas is wider than min center-cropped image (as space on the left will be occupied by red overlay)
// therefore it's height is matched with cropped image and width is calculated
$required_canvas_aspect_ratio = self::IMAGE_WIDTH / self::IMAGE_HEIGHT;
// height of cropped image
$canvas_height = $this->getCrrHeight();
$canvas_width = $required_canvas_aspect_ratio * $canvas_height;
// create a new 'canvas' (empty image) on which we will
// 1. draw the existing input 'min-cropped' image on the right
// 2. draw the red overlay on the left
$canvas_image = imagecreatetruecolor($canvas_width, $canvas_height);
// copy contents of image on right side of canvas
imagecopy(
$canvas_image,
// cropped image
$this->getCrrImage(),
self::OVERLAY_BEGIN_X_RATIO * $canvas_width,
0,
0,
0,
// dimensions of cropped image
$this->getCrrWidth(),
$this->getCrrHeight()
);
// draw red band overlay on left side of canvas
$this->crr_image = $canvas_image;
return $this->withOverlay();
}