I've come across something that I'd like to accomplish without using any frameworks or other graphing tools that are out there on the internet, which is graphing trigonometric functions using only PHP and if needed, SQL. I'm aware of the GD library, but none of the functions were helpful. I wrote a small script, although it doesn't really work either. My goal is to do the following:
Allow for trig function name, starting value and end value to be added as parameters.
Check whether a function is cos, tan or sin.
Loop through all values given starting and end values in degrees, and convert to radians.
"Add" all values to an array, if needed, and graph the function given the points.
After looping through all the values of the function, what needs to be done to graph the function? Do the values have to be in a seperate array? What functions need to be used for graphing?
<?php
header("Content-type: image/png");
function graphFunction($function, $startDegree, $endDegree)
{
$functionList = array('cos', 'sin', 'tan');
if (strtolower($function) == 'cos')
{
$cosValues = array();
for ($c = $startDegree; $c < $endDegree; $c++)
{
array_push($cosValues, cos(deg2rad($c)));
$graph = imagecreatetruecolor(500,250);
$col_poly = imagecolorallocate($graph, 255, 255, 255);
imagepolygon($graph, [the cosine values] , 34, $col_poly);
imagepng($graph);
imagedestroy($graph);
}
}
}
echo graphFunction('cos', 0, 360);
?>
This is supposed to be a sample function, so no need to be criticizing the useless control structure as there are ways to store many things in a database, whatsoever. I hope for some feedback, and hopefully it is possible with PHP.
You can do this with PHP. I just tried with the following inside your if statement, and it seems to work.
$height = 250;
$offset = $height/2;
$graph = imagecreatetruecolor(500, $height);
$col_poly = imagecolorallocate($graph, 255, 255, 255);
for ($c = $startDegree; $c < $endDegree; $c++)
{
$this_x = $c;
$next_x = $this_x + 1;
$this_y = cos(deg2rad($this_x)) * $offset + $offset;
$next_y = cos(deg2rad($next_x)) * $offset + $offset;
imageline($graph, $this_x, $this_y, $next_x, $next_y, $col_poly);
}
imagepng($graph);
imagedestroy($graph);
So what I did was define a graph height, because the y coordinates of the points in the graph need to be set to they fit inside. Then inside the for loop I just take the current degree value as my x coordinate, calculate the y coordinate for it, then the same for the next degree value, and then I draw a line between those two points.
It's a bit cludgy, so I'm sure you'll wan to clean it up a bit. Also, you need to think about the width of your graph as well (what I've posted here will stop at 500 px wide, so if you want to graph a wider range, or if you want to plot 300 - 600 degrees it will just start halfway into your graphing area.
You also defined your image and colours inside the for loop, which I changed so you're not recreating an image resource each step and losing all previous data.
Anyway, it was just an example function, right? But using your degree values as x coordinates (adjusted to your graphing area sise), computing y coordinates based on the chosen function, the degree values and your graphing area size and then drawing lines between the points should work.
Related
I am building a web application that will use the Amazon Product Advertising API. The problem is that the API returns images of different sizes and aspect ratios for each product. If I resize all images to a static width/height, then some of them look odd due to the change in ratio. The images will be laid out in rows of four each. I was thinking that I will only make the width of the images the same while keeping the aspect ratio the same and then having some sort of max threshold for the height just in case the API returns some oddly sized image.
But, I wanted to see if people here have ran into this before and what their thoughts on this design problem are?
What a co-incidence. I was facing a similar problem and this is how I've decided to move forward. It might not be the best solution, but it works for me.
First I get the original height and width of the image
list($width, $height) = getimagesize("path to image");
Then I find out the greatest common divisor for the two and store the width and height ratios in variables, such as $wr and $hr
Then check for image orientation is made (horizontal or vertical) by comparing $wr > $hr for horizontal orientation and $hr > $wr for vertical
If horizontal, I make sure the thumb size does not exceed a certain value, say 120px and make the height corresponding to 120px based on aspect ratio. The same is done if the orientation is vertical.
I came across the same problem trying to standardize logos. At first, I thought that I could choose a standard area and resize all the images to that area, but there are two problems with that strategy. First, you have to set limits for height and width, so sometimes you end up images with a smaller area because they are very wide or tall. Secondly, that might make your layout look ugly. In my case I have a header on top, an image and then text below. I realized that a very wide image would leave a big gap between the header and the text. Because of that, I needed a solution that would give preference to width. What I mean by that is that the image can change a lot in width without changing the height a lot. Different applications may have different requirements, but I think my solution allows for any situation such as a preference for height as well:
function width_to_height($width, $slope, $icpt){
if ($width == 0){
return FALSE;
}
return floor(($icpt + sqrt(pow($icpt, 2) + 4*$slope*pow($width, 2)))/(2*$width));
}
function ratio_to_height($ratio, $slope, $icpt){
if ($ratio == 0){
return FALSE;
}
$area = $ratio*$slope + $icpt;
return floor(sqrt($area/$ratio));
}
function calc_dims($width, $height, $max_w=168, $max_h=100){
$slope = 2500;
$icpt = 6000;
$ratio = $width/$height;
$max_ratio = $max_w/$this->width_to_height($max_w, $slope, $icpt);
if ($ratio > $max_ratio){
$ht = floor($max_w/$ratio);
return array('width' => $max_w, 'height' => $ht);
}
$ht = $this->ratio_to_height($ratio, $slope, $icpt);
if ($ht > $max_h){
$wd = floor($max_h*$ratio);
return array('width' => $wd, 'height' => $max_h);
}
$wd = floor($ht*$ratio);
return array('width' => $wd, 'height' => $ht);
}
The main function is calc_dims() which calls the other two functions. Since I almost always work with classes, these functions are called with the "this->" operator. If you don't use classes, you can simply delete the operator.
You can see that I hard-coded some variables. (In my real life application, these are called from a configuration file.) $max_w and $max_h are pretty self explanatory as the maximum height and width of the images. However $slope and $icpt may be a little more difficult to understand. As you can see in the ratio_to_height() function, $slope and $icpt (intercept) are components in a linear relationship between area and the aspect ratio of the image.
You can use the values that I provide ($slope = 2500; $icpt = 6000), or you can calculate your own. I thought of automating the process a little more, but since the parameters are highly subjective, it didn't seem very practical. In order to calculate them, it's necessary to define areas for two different instances of the aspect ratios, where the ratio is $width/$height. For example, when the ratio is 1 ($width = $height), you might want the area to be 8000 pixels^2, and when the ratio is 2 ($width = 2*$height) the area could be 12000 pixels^2. With these values we have:
$A1 = 8000;
$A2 = 12000;
$r1 = 1;
$r2 = 2;
You can calculate slope and intercept as follows:
$slope = ($A2 - $A1)/($r2 - $r1);
$icpt = $A1 - $slope*$r1;
I am trying to replicate the functionality that Dribbble.com does with detecting the predominant colors in an Image. In the image below you can see a screenshot from Dribbble.com that shows the 8 predominant colors in the image to the left. Here is the actual page in the image http://dribbble.com/shots/528033-Fresh-Easy?list=following
I need to be able to do this in PHP, once I get the colors I need I will save them to a database so the processing does not need to be run on every page load.
After some research on how to get these colors out of an Image, some people said you simply examine an image pixel by pixel and then save the colors that occur the most. Other say there is more to it and that getting the colors that exist the most frequent won't give the desired affect. They say you need to Quantize the image/colors (I am lost at this point).
In the image below the Dribble shot below is a Javascript library that does the same thing, that page can be viewed here http://lokeshdhakar.com/projects/color-thief/
Viewing the source of that page I can see there is a Javascript file named quantize.js and the results are really good. So I am hoping to be able to do what that Javascript library does but with PHP and GD/ImageMagick
I had found this function that will return the colors and count in an Image with PHP but the results are different from the Javascript version above and the Dribble results
/**
* Returns the colors of the image in an array, ordered in descending order, where the keys are the colors, and the values are the count of the color.
*
* #return array
*/
function Get_Color()
{
if (isset($this->image))
{
$PREVIEW_WIDTH = 150; //WE HAVE TO RESIZE THE IMAGE, BECAUSE WE ONLY NEED THE MOST SIGNIFICANT COLORS.
$PREVIEW_HEIGHT = 150;
$size = GetImageSize($this->image);
$scale=1;
if ($size[0]>0)
$scale = min($PREVIEW_WIDTH/$size[0], $PREVIEW_HEIGHT/$size[1]);
if ($scale < 1)
{
$width = floor($scale*$size[0]);
$height = floor($scale*$size[1]);
}
else
{
$width = $size[0];
$height = $size[1];
}
$image_resized = imagecreatetruecolor($width, $height);
if ($size[2]==1)
$image_orig=imagecreatefromgif($this->image);
if ($size[2]==2)
$image_orig=imagecreatefromjpeg($this->image);
if ($size[2]==3)
$image_orig=imagecreatefrompng($this->image);
imagecopyresampled($image_resized, $image_orig, 0, 0, 0, 0, $width, $height, $size[0], $size[1]); //WE NEED NEAREST NEIGHBOR RESIZING, BECAUSE IT DOESN'T ALTER THE COLORS
$im = $image_resized;
$imgWidth = imagesx($im);
$imgHeight = imagesy($im);
for ($y=0; $y < $imgHeight; $y++)
{
for ($x=0; $x < $imgWidth; $x++)
{
$index = imagecolorat($im,$x,$y);
$Colors = imagecolorsforindex($im,$index);
$Colors['red']=intval((($Colors['red'])+15)/32)*32; //ROUND THE COLORS, TO REDUCE THE NUMBER OF COLORS, SO THE WON'T BE ANY NEARLY DUPLICATE COLORS!
$Colors['green']=intval((($Colors['green'])+15)/32)*32;
$Colors['blue']=intval((($Colors['blue'])+15)/32)*32;
if ($Colors['red']>=256)
$Colors['red']=240;
if ($Colors['green']>=256)
$Colors['green']=240;
if ($Colors['blue']>=256)
$Colors['blue']=240;
$hexarray[]=substr("0".dechex($Colors['red']),-2).substr("0".dechex($Colors['green']),-2).substr("0".dechex($Colors['blue']),-2);
}
}
$hexarray=array_count_values($hexarray);
natsort($hexarray);
$hexarray=array_reverse($hexarray,true);
return $hexarray;
}
else die("You must enter a filename! (\$image parameter)");
}
So I am asking if anyone knows how I can do such a task with PHP? Possibly something exist already that you know of or any tips to put me a step closer to doing this would be appreciated
Here's exactly what you're looking for in PHP: https://github.com/thephpleague/color-extractor
Example :
use League\ColorExtractor\Palette;
$palette = Palette::fromFilename('some/image.png');
$topEightColors = $palette->getMostUsedColors(8);
This is my simple method to get the main color of an image
$image=imagecreatefromjpeg('image.jpg');
$thumb=imagecreatetruecolor(1,1);
imagecopyresampled($thumb,$image,0,0,0,0,1,1,imagesx($image),imagesy($image));
$mainColor=strtoupper(dechex(imagecolorat($thumb,0,0)));
echo $mainColor;
You need to scale down the picture and you will get the main colors of the picture. If you need 4 colors in the pallet, scale it down to about 8x8, 6 colors to about 12x8 and so on...
imagecopyresized for scaled down image then check every pixels and store them in array imagecolorat($image,px,py)
Try this out
<?php
// EXAMPLE PICTURE
$url='https://www.nordoff-robbins.org.uk/sites/default/files/google.jpg';
//var_dump(getColorPallet($url));
echoColors(getColorPallet($url));
function echoColors($pallet){ // OUTPUT COLORSBAR
foreach ($pallet as $key=>$val)
echo '<div style="display:inline-block;width:50px;height:20px;background:#'.$val.'"> </div>';
}
function getColorPallet($imageURL, $palletSize=[16,8]){ // GET PALLET FROM IMAGE PLAY WITH INPUT PALLET SIZE
// SIMPLE CHECK INPUT VALUES
if(!$imageURL) return false;
// IN THIS EXEMPLE WE CREATE PALLET FROM JPG IMAGE
$img = imagecreatefromjpeg($imageURL);
// SCALE DOWN IMAGE
$imgSizes=getimagesize($imageURL);
$resizedImg=imagecreatetruecolor($palletSize[0],$palletSize[1]);
imagecopyresized($resizedImg, $img , 0, 0 , 0, 0, $palletSize[0], $palletSize[1], $imgSizes[0], $imgSizes[1]);
imagedestroy($img);
//CHECK IMAGE
/*header("Content-type: image/png");
imagepng($resizedImg);
die();*/
//GET COLORS IN ARRAY
$colors=[];
for($i=0;$i<$palletSize[1];$i++)
for($j=0;$j<$palletSize[0];$j++)
$colors[]=dechex(imagecolorat($resizedImg,$j,$i));
imagedestroy($resizedImg);
//REMOVE DUPLICATES
$colors= array_unique($colors);
return $colors;
}
?>
Works perfect for me.
The page you linked to has a link to the source code on GitHub so if you want to know exactly how they are doing you could replicate their source in PHP.
The big difference between how they are doing it and how you are doing it, is that they are using clustering to find the color. Instead of rounding the color when they store it, they are storing all of the raw colors in an array. Then they loop through this array until they find a cluster that has the highest ratio of points in the cluster to number of colors in the cluster. The center point of this is the most common color. The palette is then defined by the next highest sets of clusters, with some logic to prevent near complete overlap of the clusters.
Try this: http://www.coolphptools.com/color_extract
Works with JPEG and PNG.
And best!: no hustle with composer, just require_once
require_once 'colorextract/colors.inc.php';
$ex=new GetMostCommonColors();
$num_results=20;
$reduce_brightness=1;
$reduce_gradients=1;
$delta=24;
$colors=$ex->Get_Color( 'image.png', $num_results, $reduce_brightness, $reduce_gradients, $delta);
print_r($colors);
give you something like this:
Array (
[3060a8] => 0.55827380952381
[f0a848] => 0.19791666666667
[000000] => 0.069642857142857
[483018] => 0.02047619047619
[786018] => 0.01827380952381
[183060] => 0.01797619047619
[4878a8] => 0.016011904761905
[181800] => 0.015119047619048
[a87830] => 0.014345238095238
[a8c0d8] => 0.011904761904762
[6090c0] => 0.01172619047619
[d89030] => 0.011011904761905
[90a8d8] => 0.0071428571428571
[ffffff] => 0.0070238095238095
[604830] => 0.006547619047619
[f0f0f0] => 0.0063095238095238
[d8d8f0] => 0.005297619047619
[c0d8d8] => 0.0044047619047619
[f0f0ff] => 0.00041666666666667
[181830] => 0.00011904761904762 )
I tried it with different images and it seems reliable.
The idea of getting the predominant colors of the image is a bit tricky, because for example the most frequent pixel color could be so widely scattered in the image that it is not perceived as a predominant color at all.
I think an algorithm like Color coherence vector will be good enough to overcome this issue, because it clusters the colors into coherent and incoherent (which is quite intuitive), and then you can use them to discard those false positive predominant colors.
I see it is an easy algorithm to implement, this tutorial Image Retrieval: Color Coherence Vector describes describes its steps with examples of how it works and there is even a matlab implementation mentioned at the end of it.
I have a Unix bash shell script with ImageMagick called dominantcolor that may do what you want. See my scripts web site at http://www.fmwconcepts.com/imagemagick/index.php. You an run it from PHP exec(). See my pointers for use on my home page.
Input:
dominantcolor -n 6 -p all -s save plate.png
count,hexcolor
586,#5ECADC
520,#AFA85D
469,#3C3126
462,#B9C8BB
258,#488A70
205,#B06928
The -n 6 is the desired number of colors in the color quantization. The -p all means print all counts and colors for the resulting 6 colors. The -s save indictates to save a swatch image.
Colors below are shown with the dominant color on the left and decreasing count colors towards the right according to the list above.
I'm developing a game which requires a randomly generated map. The map is going to be, effectively, a giant grid containing mostly emptiness with objects scattered about, grouped in regions. The idea is that I first generate these regions, then individual classes for each region type handle the generation of the map within the regions.
What I'm currently trying to do is generate these regions randomly on a grid. The regions will always be rectangles or squares and of any size, and the grid itself could also be of any size (again, either rectangular or square).
So to simplify all this down, I'm trying to generate randomly proportioned rectangles on a grid of arbitrary size. For the record, when I say arbitrary, I mean seriously large - we could be looking at sizes as high as 100,000 x 100,000, potentially. Regions are probably going to be a maximum of 100x100, but again, the script should be able to cope with any size.
Just to throw some more constraints out there, these regions cannot overlap. Ultimately, both the regions, and the objects generated within each region will be put into a MySQL database.
I initially thought that using a 2 dimensional array to represent the entire grid and simply marking spaces as taken within that would be fine, and it was in initial tests for small sized grids. I found for very large grids, Php complained about exceeding the memory limit and would not execute the script.
Another approach I thought about taking but haven't tried is inserting regions into the database as they are created and then running a query on the database to see if an area is empty or not every time it is required. I'm confident I could make this work, but the amount of database queries would be huge. I can reduce the number of tests required by eliminating certain squares that I can know for sure to be unusable via purely mathematical means, but for large grids we're still talking a massive amount of queries. This would make the script really, really time intensive and I can't help but feel that it's unnecessary. I'd prefer to do things another way, if possible.
The last method I thought of is purely mathematical, and would be perfect if I could make it work. I used only two variables - maximum x and maximum y to store the highest value on each axis. When testing to create a region I simply checked if the new region's top left coordinate was lower than both the maximum x and y - if it was, the space could not be used. If either one was higher, there was no issue and the region was created. Some of you might spot the problem here I imagine, but to cut a long story short there's certain situations where this system would judge an empty space to be unusable, so masses of random empty blocks appeared when I ran the script.
So, I'm stuck. I can't help but feel that there's a good mathematical solution to this that uses a fixed number of variables, but I can't see it. Failing that, does anyone know of another way to achieve what I'm looking for?
Have a read through this, maybe it will help. I haven't tested it, but I have commented my intentions so you should be able to come up with something based on it.
//create some globals we will need
$region_id = 1;
$current_x = 0;
$current_y = 0;
$squares = array();
//Create the base grid
$grid = array(GRID_WIDTH);
foreach($grid as $a)
{
$a = array(GRID_HEIGHT);
$a = array_fill(0, count($a), 0);
}
//$grid[0][0] will be the top left square
//Iterates over the grid until it is full
while($current_x != (-1) && $current_y != (-1))
{
//We just need to set these counters back to their minimums
$max_x = $current_x;
$max_y = $current_y;
//Lets see how many spaces we have between current x and end of the row
//$max_x will be the maxiumum newX2
for($x = $current_x; $x<GRID_WIDTH; $x++)
{
if($grid[$x][$current_y]==0)
{
$max_x = $x;
}
}
//Lets create a width between 1 and the max left in the row
$newX1 = $current_x;
$newX2 = rand($current_x, $max_x)
//Now lets see how tall we can make it by going down the y until we hit a square or the end.. do for each x
for($x = $newX1; $x<newX2;$x++)
{
for($y = $current_y; $y<GRID_HEIGHT; $y++)
{
if($grid[$x][$y]==0)
{
//We just need the maxiumum y we can have based on our already determined width
//Since this distance has to be smallest possible distance
//We only let max_y get larger on the first iteration of x
if($y>$max_y && $x==$newX1)
{
$max_y = $y;
}
}
}
}
//lets create a height bettwen 1 and the max
$newY1 = $current_y;
$newY2 = rand($current_y, $max_y);
//create a spacewith these values
occupySpace($newX1, $newX2, $newY1, $newY2, $grid, $region_id);
$squares[] = array($newX1, $newX2, $newY1, $newY2);
//Iterate over the grid looking for an empty space
//First lets set current_x and current_y to -1. We will use this to evalute done
$current_x = -1;
$current_y = -1;
for($x = 0; $x<GRID_WIDTH; $x++)
{
for($y = 0; $y<GRID_HEIGHT; $y++)
{
//Looking for any space that hasn't been occupied, if one is found break both for loops
if($grid[$x][$y]==0)
{
$current_x = $x;
$current_y = $y;
break 2;
}
}
}
}
//fills all spaces in the region with the current region id and increments region id
function occupySpace($x1, $x2, $y1, $y2, &$grid, &$region_id)
{
for($x=$x1; $x<$x2; $x++)
{
for($y=$y1; $y<$y2; $y++)
{
$grid[$x][$y] = $region_id;
}
}
$region_id += 1;
}
?>
Update: This solution didn't originally keep track the 'regions' that were created. Now they exist in array $squares.
PS - If this is going to be a big part of your script/business I would consider writing some classes for Grid and region,
there is no need to save every bit of information into the db. For every rectangle you only need top/left-coordinates + width/height.
then you should be able get the maximum available space for a given coordinate with with one query (e.g. getting minimum-x which is bigger than your-x and also lies within the needed y-space)
Update:
For max-width you can use:
SELECT `x` - :x AS `maxWidth`
FROM `test`
WHERE `x` > :x
AND (`y` > :y OR `y` + `h` > :y)
ORDER BY `y`, `y` + `h`
LIMIT 1
and max-height:
SELECT `y` - :y AS `maxHeight`
FROM `test`
WHERE `y` > :y
AND (`x` > :x OR `x` + `w` > :x)
ORDER BY `x`, `x` + `w`
LIMIT 1
I have a table with 150x150 cells which each have a colored background and a small image/symbol in them. Additionally each cell can have zero or more of it's borders set also. The user can change and add borders and change the cell color and cell. This all works pretty well using jquery and it is just a plain html table.
At the end of the user experience I am making a pdf of this table for them to download. This is a big job and takes a while, which is not my main concern now. jQuery gathers the table data in an array and sends it to php to recreate it as an image using the gd library.
So for each cell I was drawing a rectangle of the correct color on a large image, loading the symbol image and resampling it on to the large image, drawing the borders and imagedestroy the symbol image, it worked but took 1 minute. I changed my strategy to make a small colored rectangke impose the image on it and cache it in an array to be quickly used again. That sped my time up and brought it down to 30ish seconds, but now I am exhausting memory.
I am breaking the table down into 50 cell blocks so each fits on a page, each block is made into an image and saved to disk, the next is made and saved, etc. Each time the gd image is destroyed. Then all the blocks are inserted into the pdf.
So after all that, my question is how do I figure out where the memory is being used so I can try to free it up? I have posted the main function I think is causing the issue below. In my test there are up to 30 different symbols/colors images that are 25pxX25px, these are the images that are cached in an array.
I hope I have provided enough info and my problem is clear enough.
Thank you for your time,
Todd
//make one "block" of stitches returns image file name.
//function makeStitchChartBlock($img, $startX, $startY, $endX, $endY, $caption, $brand){
function makeStitchChartBlock($stitchChartArray, $startX, $startY, $endX, $endY, $caption, $brand,$blockNumber){
global $threadColours;
$stitchCache=array();
$saveTo = 'result'.$blockNumber.'.jpeg';
// calculate size of block
$numRows=($endY-$startY);
$numColumns=($endX-$startX);
$heightOfBlock = $numRows*SYMBOL_SIZE; //in pixels --- used to determine size of image to make for block
$widthOfBlock = $numColumns*SYMBOL_SIZE; //in pixels
//----plus any extra for captions grid lines
$heightOfBlock += (($endY-$startY)+1); //each stitch has a grid line before it and the last one also has on after it
$widthOfBlock += (($endX-$startX)+1);
// create image size of block to put stitches in
$newBlockImage = imagecreatetruecolor($widthOfBlock,$heightOfBlock);
$backStitchColor = imagecolorallocate($newBlockImage, 0, 0, 0);
// insert caption????
//draw grid lines
//$newBlockImage = addGridToImage($newBlockImage);
//keep track of where to start next cell top left
$blockX=0;
$blockY=0;
for($y = $startY; $y < $endY; $y++){ //for each pixel in height, move down 1 "row" each iteration
//echo "<tr>";
for($x = $startX; $x < $endX; $x++){ // "draws" a row (for each y pixel)
//rgb(75, 90, 60)
//x and y are column and row #'s
list($r, $g, $b) = getRGBs($stitchChartArray[$y][$x][0]); //get the rgb values for the cell
$stitchColor = imagecolorallocate($newBlockImage, $r, $g, $b);
//calculate x & y start positons
$stitchStartX=($blockX*SYMBOL_SIZE)+$blockX+1; //account for each previous stitch and the grid line, then add one for new grid line
$stitchStartY=($blockY*SYMBOL_SIZE)+$blockY+1;
$stitchEndX=$stitchStartX+(SYMBOL_SIZE);
$stitchEndY=$stitchStartY+(SYMBOL_SIZE);
/* make a symbol cell image with/without color and save it in the cache */
if(!isset($stitchCache[$r][$g][$b]))
{
//create new image
$stitchCache[$r][$g][$b] = imagecreatetruecolor(SYMBOL_SIZE,SYMBOL_SIZE);
$stitchCacheColor = imagecolorallocate($stitchCache[$r][$g][$b], $r, $g, $b);
//draw colored rectangle
imagefilledrectangle($stitchCache[$r][$g][$b], 0, 0, SYMBOL_SIZE-1, SYMBOL_SIZE-1, $stitchCacheColor);
//add the symbol
$symbolFile=$stitchChartArray[$y][$x][1];
if($symbolFile){
$symbolImage = imagecreatefrompng($symbolFile);
imagecopyresampled ($stitchCache[$r][$g][$b],$symbolImage,0,0,0,0,SYMBOL_SIZE-1,SYMBOL_SIZE-1,imagesx($symbolImage), imagesy($symbolImage) );
imagedestroy($symbolImage);
}
}
//add image from cache to the block image
imagecopyresampled ($newBlockImage,$stitchCache[$r][$g][$b],$stitchStartX, $stitchStartY,0,0,SYMBOL_SIZE,SYMBOL_SIZE,SYMBOL_SIZE,SYMBOL_SIZE);
//add the backstitch lines(borders)
if($stitchChartArray[$y][$x][2]>1) //top
{
imagefilledrectangle($newBlockImage, $stitchStartX, $stitchStartY, $stitchEndX, $stitchStartY+1, $backStitchColor);
}
if($stitchChartArray[$y][$x][3]>1) //right
{
imagefilledrectangle($newBlockImage, $stitchEndX-1, $stitchStartY, $stitchEndX, $stitchEndY, $backStitchColor);
}
if($stitchChartArray[$y][$x][4]>1) //bottom
{
imagefilledrectangle($newBlockImage, $stitchStartX, $stitchEndY-1, $stitchEndX, $stitchEndY, $backStitchColor);
}
if($stitchChartArray[$y][$x][5]>1) //left
{
imagefilledrectangle($newBlockImage, $stitchStartX, $stitchStartY, $stitchStartX+1, $stitchEndY, $backStitchColor);
}
//advance x position
$blockX++;
}
//advance y position
//reset x
$blockX=0;
$blockY++;
}
imagejpeg($newBlockImage, $saveTo);
imagedestroy($newBlockImage);
//dump stitch cache
foreach($stitchCache as $r)
{
foreach($r as $g)
{
foreach($g as $b=>$data)
{
imagedestroy($data);
}
}
}
return $saveTo;
}
I would start (if you haven't already) by getting a good IDE and a debugger as these will be invaluable tools. In this instance you may be able to use a profiler to work out where the memory is being used. Failing that some good ole' manual debugging code, say
$memory = memory_get_usage();
as the first line inside your inner loop. Then when you step through using the debugger you'll be able to see where the memory is ramping up.
btw, using global variables is generally not a good idea. You might want to pass in $threadColours as a parameter or look at other ways of getting that data into the function.
I am currently working on an application that needs to analyse a number of images and figure out what color they're closest to.
Therefore I found a code snippet that does exactly that:
function analyzeImageColors($im, $xCount =3, $yCount =3)
{
//get dimensions for image
$imWidth =imagesx($im);
$imHeight =imagesy($im);
//find out the dimensions of the blocks we're going to make
$blockWidth =round($imWidth/$xCount);
$blockHeight =round($imHeight/$yCount);
//now get the image colors...
for($x =0; $x<$xCount; $x++) { //cycle through the x-axis
for ($y =0; $y<$yCount; $y++) { //cycle through the y-axis
//this is the start x and y points to make the block from
$blockStartX =($x*$blockWidth);
$blockStartY =($y*$blockHeight);
//create the image we'll use for the block
$block =imagecreatetruecolor(1, 1);
//We'll put the section of the image we want to get a color for into the block
imagecopyresampled($block, $im, 0, 0, $blockStartX, $blockStartY, 1, 1, $blockWidth, $blockHeight );
//the palette is where I'll get my color from for this block
imagetruecolortopalette($block, true, 1);
//I create a variable called eyeDropper to get the color information
$eyeDropper =imagecolorat($block, 0, 0);
$palette =imagecolorsforindex($block, $eyeDropper);
$colorArray[$x][$y]['r'] =$palette['red'];
$colorArray[$x][$y]['g'] =$palette['green'];
$colorArray[$x][$y]['b'] =$palette['blue'];
//get the rgb value too
$hex =sprintf("%02X%02X%02X", $colorArray[$x][$y]['r'], $colorArray[$x][$y]['g'], $colorArray[$x][$y]['b']);
$colorArray[$x][$y]['rgbHex'] =$hex;
//destroy the block
imagedestroy($block);
}
}
//destroy the source image
imagedestroy($im);
return $colorArray;
}
Problem is that whenever I provide an image with transparency, GDLib consinders the transparency to be black, thus producing a wrong (much darker) output than is really the case.
For example this icon where the white area around the arrow is actually transparent:
example http://img651.imageshack.us/img651/995/screenshot20100122at113.png
Can anyone tell me how to work around this?
You need imageColorTransparent(). http://www.php.net/imagecolortransparent
Transparency is a property of the image, not of a color. So use something like $transparent = imagecolortransparent($im) to see if there is any transparency on your image, then just ignore that color in your $colorArray or have some other way to identify the transparent color in the return from your function. That all depends on how you're using the returned data.
--M