I am trying to create an image with a pattern of a repeated circle. I am doing this in PHP with GD. So far I have been able to tile the circle in horizontal manner (x-axis) but am unable to tile it in the vertical(y-axis). Here is an example image.
Below is the code that created the above image :
$width = 1000;
$height = 500;
$image_p = imagecreatetruecolor($width, $height);
$color = imagecolorallocate($image_p, 0, 255, 0);
for ($i = 0; $i <= 10; $i++){
if ($i % 2 !== 0){ //only if odd numbers
imagefilledellipse ($image_p, 50 * $i, 50, 100, 100, $color);
}
}
imagejpeg($image_p, uniqid() .'.jpg');
My guess is that in order to tile each circle in a vertical manner it just needs another nested for loop and it would be similar to one already there except the change in y-axis like so :
imagefilledellipse ($image_p, 50, 50 * $i, 100, 100, $color);
I have tried a lot of nesting variation but could not get it to work. Please help.
The function imagefilledellipse has the following signature (I suppose):
imagefilledellipse(image, x, y, width, height, color)
Which means that you are drawing for every i in 0 < i < 10 a circle with a different x position.
Swap it with the y parameter to draw vertical circles:
$width = 1000;
$height = 500;
$image_p = imagecreatetruecolor($width, $height);
$color = imagecolorallocate($image_p, 0, 255, 0);
for ($i = 0; $i <= 10; $i++){
if ($i % 2 !== 0){ //only if odd numbers
imagefilledellipse ($image_p, 50, 50 * $i, 100, 100, $color);
}
}
imagejpeg($image_p, uniqid() .'.jpg');
In order to draw both horizontal and vertical circles you will need indeed, as you said, a nested for-loop:
$width = 1000;
$height = 500;
$image_p = imagecreatetruecolor($width, $height);
$color = imagecolorallocate($image_p, 0, 255, 0);
for ($i = 0; $i <= 10; $i++){
for ($j = 0; $j <= 10; $j++) {
if ($i % 2 !== 0 && $j % 2 !== 0) { //only if odd numbers
imagefilledellipse ($image_p, 50 * $i, 50 * $j, 100, 100, $color);
}
}
}
imagejpeg($image_p, uniqid() .'.jpg');
Also, you do not need to check for odd numbers if you would change the scale from i * 50 to 50 + i * 100, like this:
imagefilledellipse ($image_p, 50 + 100 * $i, 50 + 100 * $j, 100, 100, $color);
If you know how many columns you want it should be quite easy.
$colCounter=0;
$yAxis = 50;
for ($i = 0; $i <= 10; $i++){
if ($i % 2 !== 0){ //only if odd numbers
if ($colCounter % 5 === 0){ // Do something every 5 cols
$yAxis = $yAxis + 50 // add 50 onto each row
}
$colCounter++;//increment counter
imagefilledellipse ($image_p, 50 * $i, $yAxis, 100, 100, $color);
}
}
Note this is un-tested code
Related
I'm trying to make a function that takes a JPG file, add a grid overlay, and in each cell write in text A1, A2, A3 and so on.
The current code (below) only draws the grid, with a static column/row size.
Question 1) How can I add the coordinates as text in each cell? E.g rows are letters, and columns are numbers. So first row is A1, A2, A3 ... and next row is B1, B2, B3.
Question 2) How can I modify it, so that I specify just how many rows and columns I want, and it will automatically adjust the size of the col/rows accordingly to fit the dimensions of the input image?
function draw_grid(&$img, $x0, $y0, $width, $height, $cols, $rows, $color) {
imagesetthickness($img, 5);
//draw outer border
imagerectangle($img, $x0, $y0, $x0+$width*$cols, $y0+$height*$rows, $color);
//first draw horizontal
$x1 = $x0;
$x2 = $x0 + $cols*$width;
for ($n=0; $n<ceil($rows/2); $n++) {
$y1 = $y0 + 2*$n*$height;
$y2 = $y0 + (2*$n+1)*$height;
imagerectangle($img, $x1,$y1,$x2,$y2, $color);
}
//then draw vertical
$y1 = $y0;
$y2 = $y0 + $rows*$height;
for ($n=0; $n<ceil($cols/2); $n++) {
$x1 = $x0 + 2*$n*$width;
$x2 = $x0 + (2*$n+1)*$width;
imagerectangle($img, $x1,$y1,$x2,$y2, $color);
}
}
$imgpath = "foto/306/306.jpg";
$img = imagecreatefromjpeg($imgpath);
$size = getimagesize($imgpath);
$width = $size[0];
$height = $size[1];
$red = imagecolorallocate($img, 255, 0, 0);
draw_grid($img, 0,0, $width /10 , $height /10 ,20,10,$red);
header("Content-type: image/jpg");
imagejpeg($img);
imagedestroy($img);
As described in my comment, your current code is only drawing the outlines. This is fine for drawing a Grid, but if you wish to add some text to the cell, you have to draw each rectangle manual, and use those coordinates to place the text.
Using imagettfbbox, you can calculate the width/height of the text, you'll need that information to 'center' the text in to the cell.
Regarding your second question, dividing the total picture width with the number of cells you want so you'll know the size of each individual cell.
I've updated your code to show the general idea of calculation the x/y coordinates
<?php
$imgpath = "duck.jpg";
$img = imagecreatefromjpeg($imgpath);
$size = getimagesize($imgpath);
$width = $size[0];
$height = $size[1];
$red = imagecolorallocate($img, 255, 0, 0);
// Number of cells
$xgrid = 5;
$ygrid = 5;
// Calulate each cell width/height
$xgridsize = $width / $xgrid;
$hgridsize = $height / $ygrid;
// Remember col
$c = 'A';
// Y
for ($j=0; $j < $ygrid; $j++) {
// X
for ($i=0; $i < $xgrid; $i++) {
// Dynamic x/y coords
$sy = $hgridsize * $j;
$sx = $xgridsize * $i;
// Draw rectangle
imagerectangle($img, $sx, $sy, $sx + $xgridsize, $sy + $hgridsize, $red);
// Draw text
addTextToCell($img, $sx, $xgridsize, $sy + $hgridsize, $hgridsize, $c . ($i + 1));
}
// Bumb cols
$c++;
}
function addTextToCell($img, $cellX, $cellWidth, $cellY, $cellHeight, $text) {
// Calculate text size
$text_box = imagettfbbox(20, 0, 'OpenSans', $text);
$text_width = $text_box[2]-$text_box[0];
$text_height = $text_box[7]-$text_box[1];
// Calculate x/y position
$textx = $cellX + ($cellWidth / 2) - $text_width;
$texty = $cellY - ($cellHeight / 2) - $text_height;
// Set color and draw
$color = imagecolorallocate($img, 0, 0, 255);
imagettftext($img, 20, 0, $textx, $texty, $color, 'OpenSans', $text);
}
// Save output as file
imagejpeg($img, 'output.jpg');
imagedestroy($img);
shell_exec('open -a Preview output.jpg');
1) Check out the imagettftext() and imagefttext() functions. One of those should do what you want.
2) Divide the width and height of the input image by the number of columns and rows respectively that you want to divide it into to get the width and height of each cell.
There is an excellent code in this question which produces images similar to the following example, using PHP GD library. The image is basically a repeated square pattern.
I need to create similar images BUT with circles pattern but am unable to do so as I am still learning. I tried to modify the code using imagefilledellipse.
$width = 1000;
$height = 600;
$image_p = imagecreatetruecolor($width, $height);
$baseR = 255 - rand(0, 100);
$baseG = 255 - rand(0, 100);
$baseB = 255 - rand(0, 100);
for ($i = 0; $i <= floor($width / 40); $i++){
for ($j = 0; $j <= floor($height / 40); $j++){
$val = floor(100 * (rand(0, 100) / 100)); //value will always be within the range of 1-100
$r = $baseR - $val;
$g = $baseG - $val;
$b = $baseB - $val;
$color = imagecolorallocate($image_p, $r, $g, $b);
imagefilledellipse($image_p, $i * 40, $j * 40, ($i * 40), ($j * 40), $color);
}
}
imagejpeg($image_p, uniqid() .'.jpg');
The result is horrible. Although I understand rest of the code, this line imagefilledellipse($image_p, $i * 40, $j * 40, ($i * 40), ($j * 40), $color); is beyond me. Please help.
just change
imagefilledellipse($image_p, $i * 40, $j * 40, ($i * 40), ($j * 40), $color);
by
imagefilledellipse($image_p, $i * 40, $j * 40, 40, 40, $color);
I have created a code to generate a random pattern image. it creates an image with given width and height and fills it with small 40x40 pixel rectangles.
this is my code:
<?php
$width = 1000;
$height = 600;
$image_p = imagecreate($width, $height);
$baseR = 255 - rand(0, 100);
$baseG = 255 - rand(0, 100);
$baseB = 255 - rand(0, 100);
for ($i = 0; $i <= floor($width / 40); $i++){
for ($j = 0; $j <= floor($height / 40); $j++){
$val = floor(100 * (rand(0, 100) / 100));
$r = $baseR - $val;
$g = $baseG - $val;
$b = $baseB - $val;
$color = imagecolorallocate($image_p, $r, $g, $b);
imagefilledrectangle($image_p, $i * 40, $j * 40, (($i + 1) * 40), (($j + 1) * 40), $color);
}
}
imagejpeg($image_p, 'my_dir/test.jpg');
?>
there's no problem when i set the width to a value like 640 and the height to 400. but if i set the width to 1000 and the height to 800, there will be a blank area on the right side of the image which is not covered by rectangles.
I implemented the same code in delphi and it worked perfectly, but in PHP...!
Change imagecreate to imagecreatetruecolor
You're creating a palette based image with 255 colors max. You're running out of colors to allocate at the end and it's recycling the last color on the palette for the remainder of the blocks.
Just for the sake of my question, lets say this function:
int imagecolorexact ( resource $image , int $red , int $green , int $blue )
We can call it up pretty easy like this:
$index = imagecolorexact($image, 0, 0, 0);
Obviously because we are talking the example in hand is about RGB colors, therefore the $red, $green and $blue values are between 0 and 255. This function returns an index of the pixel with that rgb compound.
What I need is to get the index of all pixels that their compound is NOT (0, 0, 0), so I'd thought to do it like this:
for($i = 0; $i <= 255; $i++) {
for($j = 0; $i <= 255; $i++) {
for($k = 0; $i <= 255; $i++) {
$index[] = imagecolorexact($image, $i, $j, $k);
}
}
}
But this will run 255*255*255 times which is alot I quess.
My question is:
Is there any way to simplify this?
Why am I asking this?
I am trying to change all the black pixels from an image to yellow, thus that would be:
$image = imagecreatefrompng("./test.png");
imagecolorset($image, imagecolorexact($image, 0, 0, 0), 255, 255, 0);
And I need to change all the NON black pixels from the same image into black, thus that will be (I quess?):
for($i = 1; $i <= 255; $i++) {
for($j = 1; $i <= 255; $i++) {
for($k = 1; $i <= 255; $i++) {
$index = imagecolorexact($image, $i, $j, $k);
imagecolorset($new, $value, 0, 0, 0);
}
}
}
Thus I am asking if there is a better, optimized way?
I have the following PHP method that generates new users a profile image when they first sign up, before they upload their own. All it does is just create them a brightly colored square - something to make the interface look a little more interesting when showing a list of users without profile photos.
How could I adapt this method so it created a checkerboard of random colors? Something like this: http://krazydad.com/bestiary/thumbs/random_pixels.jpg
public function generate_random_image($filename, $w = 200, $h = 200, $chosen_color = NULL) {
if(!$chosen_color) {
$color_options = Array("#6f0247", "#FF0569", "#FFF478", "#BAFFC0", "#27DB2D", "#380470", "#9D69D6");
$random = rand(0,sizeof($color_options));
$chosen_color = $color_options[$random];
}
$rgb = self::hex2rgb($chosen_color);
$image = imagecreatetruecolor($w, $h);
for($row = 1; $row <= $h; $row++) {
for($column = 1; $column <= $w; $column++) {
$color = imagecolorallocate ($image, $rgb[0] , $rgb[1], $rgb[2]);
imagesetpixel($image,$column - 1 , $row - 1, $color);
}
$row_count++;
}
$filename = APP_PATH.$filename;
imagepng($image, $filename);
return $chosen_color;
}
How about you just change
$color = imagecolorallocate ($image, $rgb[0] , $rgb[1], $rgb[2]);
to
$color = imagecolorallocate ($image, rand(0,255), rand(0,255), rand(0,255));
Then, each pixel will have it's own colour. Just draw to a small image, then scale by 200% or 300% (or some other arbitrary number) and you'll get nice, big chunky pixels like the image you linked.
While iterating through $rows and $columns you should increase step to desired pixel size and choose another color with each iteration.
example for pixel width = 20x20 :
$pixel = 20;
for($row = 0; $row <= $h / $pixel; $row++) {
for($column = 0; $column <= $w/ $pixel; $column++) {
$rgb = self::hex2rgb($color_options[rand(0,sizeof($color_options))]);
$color = imagecolorallocate ($image, $rgb[0] , $rgb[1], $rgb[2]);
imagefilledrectangle(
$image,
$column*$pixel,
$row*pixel,
$column*$pixel+$pixel,
$row*pixel+$pixel,
$color
);
}
}