I have a bmp file whose mime type is image/x-ms-bmp. I need to convert this into png or jpeg file. I have done below code :
$imagecreatefrombmp = $this->imagecreatefrombmp($imageContent);
ob_start();
imagejpeg($imagecreatefrombmp);
$imagedata = ob_get_contents();
ob_end_clean();
Copied imagecreatefrombmp as below :
public function imagecreatefrombmp($readContent)
{
/* // Load the image into a string
$file = fopen($p_sFile,"rb");
$read = fread($file,10);
while(!feof($file)&&($read<>""))
$read .= fread($file,1024); */
$temp = unpack("H*",$readContent);
$hex = $temp[1];
$header = substr($hex,0,108);
// Process the header
// Structure: http://www.fastgraph.com/help/bmp_header_format.html
if (substr($header,0,4)=="424d")
{
// Cut it in parts of 2 bytes
$header_parts = str_split($header,2);
// Get the width 4 bytes
$width = hexdec($header_parts[19].$header_parts[18]);
// Get the height 4 bytes
$height = hexdec($header_parts[23].$header_parts[22]);
// Unset the header params
unset($header_parts);
}
// Define starting X and Y
$x = 0;
$y = 1;
// Create newimage
$image = imagecreatetruecolor($width,$height);
// Grab the body from the image
$body = substr($hex,108);
// Calculate if padding at the end-line is needed
// Divided by two to keep overview.
// 1 byte = 2 HEX-chars
$body_size = (strlen($body)/2);
$header_size = ($width*$height);
// Use end-line padding? Only when needed
$usePadding = ($body_size>($header_size*3)+4);
// Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
// Calculate the next DWORD-position in the body
for ($i=0;$i<$body_size;$i+=3)
{
// Calculate line-ending and padding
if ($x>=$width)
{
// If padding needed, ignore image-padding
// Shift i to the ending of the current 32-bit-block
if ($usePadding)
$i += $width%4;
// Reset horizontal position
$x = 0;
// Raise the height-position (bottom-up)
$y++;
// Reached the image-height? Break the for-loop
if ($y>$height)
break;
}
// Calculation of the RGB-pixel (defined as BGR in image-data)
// Define $i_pos as absolute position in the body
$i_pos = $i*2;
$r = hexdec($body[$i_pos+4].$body[$i_pos+5]);
$g = hexdec($body[$i_pos+2].$body[$i_pos+3]);
$b = hexdec($body[$i_pos].$body[$i_pos+1]);
// Calculate and draw the pixel
$color = imagecolorallocate($image,$r,$g,$b);
imagesetpixel($image,$x,$height-$y,$color);
// Raise the horizontal position
$x++;
}
// Unset the body / free the memory
unset($body);
// Return image-object
return $image;
}
Its not creating the image correctly.
I need to render this image in a RTF file.
Related
I dispatch php gd in my controller, here's the code
class getSmallImageController extends Controller
{
public function getImg(request $request)
{
// Get the image from local file. The image must be 300*200 size.
//change $img to your own path
$img_path = '/home/jonnyy/PhpstormProjects/zcapt/app/repository/Image/1.jpg';
$img = imagecreatefromjpeg($img_path);
$img_size = getimagesize($img_path);
if ($img_size[0] != 300 || $img_size[1] != 200)
die("image size must be 300*200");
//get value of authID from init.php
$response = app('App\Http\Controllers\initController')->index($request);
$authID = $response->getOriginalContent()['authID'];
// Calculate the diagonal coordinate for that square
$position_x_1 = DB::table('inits')
->select('x')
->where('authID', '=', $authID)
->inRandomOrder()
->first();
$position_y_1 = DB::table('inits')
->select('y')
->where('authID', '=', $authID)
->inRandomOrder()
->first();
// Create a small image with height 50 and width 50
$img_small = imagecreatetruecolor(50, 50);
// Copy one part of the large image (the image with size 300*200) to small part of image
imagecopy($img_small, $img, 0, 0, current($position_x_1), current($position_y_1), 50, 50);
// Change brightness of the picture
imagefilter($img_small, IMG_FILTER_BRIGHTNESS, 50);
$position_1 = 0;
$position_2 = 50;
// Adding some blur in to small picture
for ($i = 50; $i < 120; $i = $i + 6) {
imagerectangle($img_small, $position_1, $position_1, $position_2, $position_2, imagecolorallocatealpha($img_small, 255, 255, 255, $i));
$position_1 = $position_1 + 1;
$position_2 = $position_2 - 1;
}
// Set header in type jpg
;
// Generate image
header("Content-type: image/jpg");
// Generate image
imagejpeg($img_small);
// Release memory
imagedestroy($img_small);
;
imagedestroy($img);
}
}
Got this garbled
But When I dd() the last line of my code,
dd(imagedestroy($img))
return the picture I want.
By the way, the GD library works in another controller which I dispatched for.
That isn't the way the Laravel with MVC should work. As a dirty solution I believe that put exit; after imagedestroy() could work. Another option would be to save the image to disk and display to the user.
The following option is to save in memory and then send to the user. If your page/application isn't accessed too frequently, it can work well for you.
ob_start();
imagejpeg($img_small);
imagedestroy($img_small);
$image_data = ob_get_contents();
ob_end_clean();
$response = \Response::make($image_data, 200);
$response->header("Content-Type", "image/jpeg");
return $response;
I'm working on a class that takes an array of images by src and merges them into a single tiled image, similar to the following image;
The only issue is the images provided to the class aren't of set dimensions like in the image above.
The following state of the class creates a vertically stacked list of the images without gaps (an example shown below), and calculates the required height of the export image automatically (calculated in $total_height).
I imagine gaps are inevitable in the final output one way or another due to the infinite variation in image dimensions, but I'm not sure where to start in incorporating tiling horizontally as well as vertically.
class BoardCreator {
private $_img_type;
private $_img_urls = array();
public function __construct($img_export_type, array $img_urls) {
$this->_img_type = $img_export_type; // File format for exported image
$this->_img_urls = $img_urls; // Array of image URLs
}
public function GenerateBoard() {
/*
* Arrays to hydrate with loaded image properties & resources
*/
$images = array(); // Image resources
$width = array(); // Image widths
$height = array(); // Image heights
$total_height = 0; // Total height required for the board
/*
* Load in each image, and store its width & height
*/
for ($i=0; $i < count($this->_img_urls); $i++) {
switch (exif_imagetype($this->_img_urls[$i])) {
case IMAGETYPE_JPEG :
$images[$i] = imagecreatefromjpeg($this->_img_urls[$i]);
break;
case IMAGETYPE_PNG :
$images[$i] = imagecreatefrompng($this->_img_urls[$i]);
break;
case IMAGETYPE_GIF :
$images[$i] = imagecreatefromgif($this->_img_urls[$i]);
break;
// default w/ error required
}
// Store the image's dimensions
list($width[$i], $height[$i]) = getimagesize($this->_img_urls[$i]);
// Add this image's height to the required canvas height
$total_height = $total_height + $height[$i];
}
/*
* Create a new "canvas" image with specified dimensions
*/
$canvas_image = imagecreatetruecolor($width[0], $total_height);
/*
* Copy each image into the "canvas" image generated above
*/
$current_x = 0;
$current_y = 0;
for ($i=0; $i < count($images); $i++) {
imagecopy(
$canvas_image, // destination image
$images[$i], // source image
0, // x co-ordinate of destination
$current_y, // y co-ordinate of destination
0, // x co-ordinate of source
0, // y co-ordinate of source
$width[$i], // source img width
$height[$i] // source img height
);
$current_y = $current_y + $height[$i];
}
/*
* Save the resulting image in the format specified at initiation
*/
switch ($this->_img_type) {
case "jpg" :
$images[$i] = imagejpeg($canvas_image, "../board_exports/test.jpg");
break;
case "png" :
$images[$i] = imagepng($canvas_image, "../board_exports/test.png");
break;
case "gif" :
$images[$i] = imagegif($canvas_image, "../board_exports/test.gif");
break;
default :
// Create an error to handle here
die("Error in BoardCreator.php (Method GenerateBoard() )");
break;
}
/*
* Release the created image from memory
*/
imagedestroy($canvas_image);
/*
* Loop through and release each loaded image
*/
for ($i=0; $i < count($this->_img_urls); $i++) {
imagedestroy($images[$i]);
}
}
i made this code to help you.
1.- to fix "the infinite variation in image dimensions" i make thumbnails of images with this function:
function generate_image_thumbnail($source_image_path, $thumbnail_image_path,$THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_HEIGHT)
{
$condicion = GetImageSize($source_image_path); // image format?
if($condicion[2] == 1) //gif
$original = imagecreatefromgif("$source_image_path");
if($condicion[2] == 2) //jpg
$original = imagecreatefromjpeg("$source_image_path");
if($condicion[2] == 3) // png
$original = imagecreatefrompng("$source_image_path");
$thumb = imagecreatetruecolor($THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_HEIGHT);
$ancho = imagesx($original);
$alto = imagesy($original);
imagecopyresampled($thumb,$original,0,0,0,0,$THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_HEIGHT,$ancho,$alto);
imagejpeg($thumb,$thumbnail_image_path,90);
return true;
}
2.- create an image to paste the thumbnails
$size_image=460;
$img_disp = imagecreatetruecolor($size_image,$size_image);
$backcolor = imagecolorallocate($img_disp,0,0,0);
imagefill($img_disp,0,0,$backcolor);
3.- start to paste the thumbnails
//$THUMBNAIL_IMAGE=150;
$images_by_side = round($size_image/$THUMBNAIL_IMAGE); // round(460/150)=3 3 images by side
$separator = $size_image%$THUMBNAIL_IMAGE; //150*3=450... so 10px in total of space
$space_btwen_images=$separator/($images_by_side+1); //10px / 3 of total images + 1 =2,5
$total_image = pow($images_by_side , 2 ); //total images to paste (images by side)^2.. 3^2=9
//some math calculations to make more nice the output image
$dst_x=$space_btwen_images;
$cont_imgs=0;
for($x=0;$x<$total_image;$x++) {
if($cont_imgs == $images_by_side){
$dst_x=$dst_x+$THUMBNAIL_IMAGE+$space_btwen_images;
$cont_imgs=0;
}
$dst_y=$cont_imgs*$THUMBNAIL_IMAGE+($space_btwen_images * ($cont_imgs+1));
$cont_imgs++;
$thumb_image=$img_tmb_dir.$arr_img[$x]; //image to paste
$condicion = GetImageSize($thumb_image); // image format?
if($condicion[2] == 1) // gif
$image_to_copy = imagecreatefromgif("$thumb_image");
if($condicion[2] == 2) // jpg
$image_to_copy = imagecreatefromjpeg("$thumb_image");
if($condicion[2] == 3) // png
$image_to_copy = imagecreatefrompng("$thumb_image");
echo "dst_x=".$dst_x."; dst_y=".$dst_y.";<br>";
//output to check the destinations of the images to paste
/*
dst_x=2.5; dst_y=2.5;
dst_x=2.5; dst_y=155;
dst_x=2.5; dst_y=307.5;
dst_x=155; dst_y=2.5;
dst_x=155; dst_y=155;
dst_x=155; dst_y=307.5;
dst_x=307.5; dst_y=2.5;
dst_x=307.5; dst_y=155;
dst_x=307.5; dst_y=307.5;
*/
imagecopy($img_disp, $image_to_copy, $dst_x, $dst_y, 0, 0, $THUMBNAIL_IMAGE, $THUMBNAIL_IMAGE);
}
imagejpeg($img_disp, "test3.jpg",90);
imageDestroy($img_disp);
echo '<img src="test3.jpg"/>';
4.-
with my images (150 x 150) and $size_image=460; will return
and $size_image=610 will return
Is there any working example how to read an animated gif, change color of any pixel in any frame of it using GD library or ImageMagick and save it as an animated gif again?
I have been googling for it for 2 days and I did not found answer anywhere.
Edit:
I have almost perfect solution. But some transparent (animated) gifs do not retain its transparency correctly (only part of the transparency is corrupted).
Source:
One of the wrong images: http://commons.wikimedia.org/wiki/File:Animation30.gif
GifFrameExtractor class: https://github.com/Sybio/GifFrameExtractor
GIFEncoder class: http://www.phpclasses.org/package/3163-PHP-Generate-GIF-animations-from-a-set-of-GIF-images.html
require_once('GIFEncoder.class.php');
require_once('GifFrameExtractor-master/src/GifFrameExtractor/GifFrameExtractor.php');
$gifFilePath = "input.gif";
// check this is an animated GIF
if (!\GifFrameExtractor\GifFrameExtractor::isAnimatedGif($gifFilePath)) {
\die('not an namiated image');
}
$gfe = new \GifFrameExtractor\GifFrameExtractor();
$gfe->extract($gifFilePath);
// frames as a GD source
$frameImages = $gfe->getFrameImages();
$frameDurations = $gfe->getFrameDurations();
// color used as a transparent color, if any
$tColor = array('red' => -1,'green'=>-1,'blue'=>-1);
foreach($frameImages as $i => $gdSource) {
// do something with gdSource
colorize($gdSource);
if($i == 0) {
//get the color used as transparent
// should be for any frame the same
$tColor = getTransparentColor($gdSource);
}
//GIFEncoder works only with binary data or files
//It cant work with gd source
//Therfore i output the gd source to stdout, catch it
//and use it as binary data.
//It could be memory consuming, so you might write the
//frames as a file and then use them instead of binary data.
\ob_start(); // catch output
\imagegif($gdSource); // write binary data to output
$frameImages[$i] = \ob_get_contents(); //replace GD source by the binary data
\ob_end_clean();
}
// create animated gif
$gif = new \GIFEncoder(
$frameImages, //binary data (or path to images on file system)
$frameDurations,
0, // infinite loop
2, // dont know what is this for (number 0-3 or -1 to ignore)
$tColor['red'], $tColor['green'], $tColor['blue'],
'bin' // or 'url' if $frameImages is array of paths to images on file system
);
// write image to file system
\FWrite ( \FOpen ( "output.gif", "wb" ), $gif->GetAnimation ( ) );
// send image to browser
//Header ( 'Content-type:image/gif' );
//echo $gif->GetAnimation ( );
//helpful function
/**
* Make grayscale color
* #param $color array('red'=>,'green'=>,'blue'=>);
* #return array('red'=>,'green'=>,'blue'=>);
*/
function transformColor($color) {
$gst = $color['red']*0.15+$color['green']*0.5+$color['blue']*0.35;
$color['red'] = $color['green'] = $color['blue'] = $gst;
return $color;
}
//helpful function
/**
* Get the transparent color from GD resource.
* If no tranpsarent color, all returned RGB values are -1
* #param $rs GD resource
* #return array('red'=>,'green'=>,'blue'=>)
*/
function getTransparentColor($rs) {
$transparentIndex = \ImageColorTransparent($rs);
$transparentColor = NULL;
if ($transparentIndex >= 0 && $transparentIndex < \ImageColorsTotal($rs)) {
$transparentColor = #\ImageColorsForIndex($rs, $transparentIndex);
}
return $transparentColor ? $transparentColor : array('red' => -1,'green'=>-1,'blue'=>-1);
}
// transform the GD resource with transparency
// there is probably problem,because if I save frames alone, they have the problem with transparency described above
function colorize($rs) {
assert('gd' === \get_resource_type($rs));
// you might want to create copy of the source here
// (instead of resource alias)
$bild = $rs;
//width
$x = \imagesx($bild);
// height
$y = \imagesy($bild);
$transparentIndex = \ImageColorTransparent($rs);
$transparentColor = NULL;
if ($transparentIndex >= 0 && $transparentIndex < \ImageColorsTotal($bild)) {
$transparentColor = #\ImageColorsForIndex($rs, $transparentIndex);
}
\ImageSaveAlpha($bild, TRUE);
\ImageAlphaBlending($bild, FALSE);
$transparentNewIndex = NULL;
$transparentNewColor = NULL;
if (!empty($transparentColor)) {
$transparentIndexNew = \ImageColorAllocate($bild, 255, 0, 255);
\ImageColorTransparent($bild, $transparentIndexNew);
$transparentColorNew = #ImageColorsForIndex($bild, transparentIndexNew);
}
// transform pixels
for ($i = 0; $i < $y; $i++) {
for ($j = 0; $j < $x; $j++) {
$index = \imagecolorat($rs, $j, $i);
$color = \imagecolorsforindex($rs, $index);
if ($index === $transparentIndex) {
$col = $transparentIndexNew;
} else {
$rgb = transformColor($color);
//TODO: we have a problem here, if $rgb ~= $transparentColorNew,
// then this pixel will be transparent and not the desired color
$col = \imagecolorresolvealpha($bild, $rgb['red'], $rgb['green'], $rgb['blue'], intval($color['alpha']));
if($col == $transparentIndexNew) {
//TODO: fix the color not to be transparent
// it do not die with the example gif
//die('This might be a problem, but not the problem describlet above this example');
}
}
\imagesetpixel($bild, $j, $i, $col);
}
}
return $bild;
}
I believe that an animated GIF has multiple frames, so the algorithm for this would be to read the gif as multiple frames, change the pixel colours in each frame, and then save it again. Are you able to load an animated gif in GD?
Perhaps this library can help you to write the GIF image back: http://www.phpclasses.org/package/3163-PHP-Generate-GIF-animations-from-a-set-of-GIF-images.html
$file = "yourImage.gif";
$im = imagecreatefromgif ($file);
$index = imagecolorclosest ( $im, 255,255,255 ); // get your color (rgb)
imagecolorset($im,$index,92,92,92); // set new color (rgb)
$file= "yourResult.gif";
imagegif($im, $file); // save image as gif
imagedestroy($im);
I'm not sure if this works with a animated gif.
Ok, so am working on a simple generator using jquery. A user enters a text of his/her choice, selects a font, font-color and font-size. All this properties are displayed on a separate div in real-time (live preview).
I now need to save the generated preview as a picture. For that, I use php GD library. All works fine but with some fonts, everything is just messed up.
In the first image, everything looks alright but the second image, the line height is just messed up.
This is my php script that am using to processes the properties
<?php
//Width and height of desired image
$width = 320;
$height= 320;
//Create an image with specified height and width
$main_img = ImageCreate($width, $height);
$mx = imagesx($main_img);
$my = imagesy($main_img);
//Capture values from form
$main_text = $_POST['rtext'];
$main_text_size = $_POST['rfsize'];
$color = $_POST['rcolor'];
$mt_f = $_POST['rfont'];
$main_text_x = ($mx/2);
// more code here
//wrap text if text too long
$words = explode(' ', $main_text);
$lines = array($words[0]);
$currentLine = 0;
for($i = 1; $i < count($words); $i++)
{
$lineSize = imagettfbbox($main_text_size, 0, $mt_f, $lines[$currentLine] . ' ' . $words[$i]);
if($lineSize[2] - $lineSize[0] < $mx)
{
$lines[$currentLine] .= ' ' . $words[$i];
}
else
{
$currentLine++;
$lines[$currentLine] = $words[$i];
}
}
$line_count = 1;
// Loop through the lines and place them on the image
foreach ($lines as $line)
{
$line_box = imagettfbbox($main_text_size, 0, $mt_f, "$line");
$line_width = $line_box[0]+$line_box[2];
$line_height = $line_box[1]-$line_box[7];
$line_margin = ($mx-$line_width)/2;
$line_y = (($line_height+12) * $line_count);
imagettftext($main_img, $main_text_size, 0, $line_margin, $line_y, $main_text_color, $mt_f, $line);
// Increment Y so the next line is below the previous line
$line_count ++;
}
header("Content-type: image/png");
//code to download the image
?>
Is there a way I can modify the part of the code where I wrap the text to accomodate all fonts? Like automatically calculate the line height based on the font?
Thanks, any help will be appreciated
I found a very useful class at phpclasses imagefittext.class.php http://www.phpclasses.org/browse/file/41869.html. I also found an example script that is implemented using the class http://www.phpclasses.org/browse/file/41870.html. This is exactly what I wanted.
Worked Perfectly!!!1
This one might be a little confusing. I'm using AMCharts with rails. Amcharts comes with a PHP script to export images called "export.php"
I'm trying to figure out how to take the code in export.php and put it into a controller.
Here is the code:
<?php
// amcharts.com export to image utility
// set image type (gif/png/jpeg)
$imgtype = 'jpeg';
// set image quality (from 0 to 100, not applicable to gif)
$imgquality = 100;
// get data from $_POST or $_GET ?
$data = &$_POST;
// get image dimensions
$width = (int) $data['width'];
$height = (int) $data['height'];
// create image object
$img = imagecreatetruecolor($width, $height);
// populate image with pixels
for ($y = 0; $y < $height; $y++) {
// innitialize
$x = 0;
// get row data
$row = explode(',', $data['r'.$y]);
// place row pixels
$cnt = sizeof($row);
for ($r = 0; $r < $cnt; $r++) {
// get pixel(s) data
$pixel = explode(':', $row[$r]);
// get color
$pixel[0] = str_pad($pixel[0], 6, '0', STR_PAD_LEFT);
$cr = hexdec(substr($pixel[0], 0, 2));
$cg = hexdec(substr($pixel[0], 2, 2));
$cb = hexdec(substr($pixel[0], 4, 2));
// allocate color
$color = imagecolorallocate($img, $cr, $cg, $cb);
// place repeating pixels
$repeat = isset($pixel[1]) ? (int) $pixel[1] : 1;
for ($c = 0; $c < $repeat; $c++) {
// place pixel
imagesetpixel($img, $x, $y, $color);
// iterate column
$x++;
}
}
}
// set proper content type
header('Content-type: image/'.$imgtype);
header('Content-Disposition: attachment; filename="chart.'.$imgtype.'"');
// stream image
$function = 'image'.$imgtype;
if ($imgtype == 'gif') {
$function($img);
}
else {
$function($img, null, $imgquality);
}
// destroy
imagedestroy($img);
?>
There are some versions in existence in a thread I found here: http://www.amcharts.com/forum/viewtopic.php?id=341
But I have a feeling the PHP code above has changed since then - because neither implementation worked for me.
What this code more or less dose is grabs the informations, that were sent to the script (POST).
The informations include the height and width of the picture and the RGB values of every pixel. The script draws every pixel and sends the images at the end to the client.
You can use Rmagick's method to draw a pixel. This will give you the same result.
The incomming post data looks like this:
height = number -> cast to int
width = number -> cast to int
// first row with a repeating part of R:G:B,R:G:B,... (n = width)
r0 = 255:0:0,150:120:0,77:88:99,...
r1 = ...
.
.
r100 = ... -> the row count is the height - 1
Actually, I found a discussion about speeding up pixel by pixel drawing.
So apparently I was running into other errors which made me think the already existing code didnt work. However, the code on the thread I linked to in the original question does in fact work!