4

I have a class with several functions that can render images.

// render.php
class Render {
   public function Render($some_arguments) {
      ...
      header("Content-Type: image/png");
        $im = @imagecreate(110, 20)
            or die("Cannot Initialize new GD image stream");
        $background_color = imagecolorallocate($im, 0, 0, 0);
        $text_color = imagecolorallocate($im, 233, 14, 91);
        imagestring($im, 1, 5, 5,  "A Simple Text String", $text_color);
        imagepng($im);
        return "data:image/png;base64,".base64_encode($im);
   }
}

Then I have my php file that contains the html code and where I would like to output the image within an < img> tag:

// index.php
include("render.php");
$render = new Render();
echo "<htlm><head></head><body>";
echo "<img src=\"".$render->Render(1)."\" />";
echo "</body></html>";

When I run index.php in my browser I just get a blank screen.

Can´t I use a function call as an image source? I know I can use a php file as source, like < img src="render_image.php" />, but then I cannot send any arguments in an object oriented manner (I know I can use $_GET to retrieve arguments), but I would like to do it with a nice object oriented written code.

So, is there any way to use a function call as a source of a html tag?

Daniele
  • 1,005
  • 9
  • 26
Rox
  • 2,647
  • 15
  • 50
  • 85
  • You should get non-functioning garbage, not a blank screen. Raise error_reporting or look into the error.log. Also the `->Render()` function would output the img data, not return it. Work on that first rather than the object interface. – mario Jan 21 '12 at 11:30

4 Answers4

5

You can BASE64 encode the image and use the data url scheme:

data:[<MIME-type>][;charset=<encoding>][;base64],<data>

eg.

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">

So, if you include that instead of the raw image you can do exactly what you want.

(Examples from Wikipediea)

hypercrypt
  • 15,389
  • 6
  • 48
  • 59
  • I got it working when loading PNG files from disk, but when I create the imaged dynamically using the php functions imagecreate and imagepng I did not got it working, it just prints the image, not the html content. Look at my example above. – Rox Jan 21 '12 at 15:25
  • Updated my answer to include an approach that should work with dynamic images. – Mario Jan 21 '12 at 17:44
  • Yes. So, the way you do is to have the src='' parameter of your img tag point to a php script like this , then that php script (render_image.php) will run your render function as it is, which outputs the headers and body of the generated image. That will work without writing any image data to the hard disk. – ralfe Jan 22 '12 at 05:32
4

You'll have to split it:

Render(...) will write a temporary file (with a randomized name), that is accessible from the web for some time.

A new method Output() will return the randomized name mentioned above.

You then call Render() before outputting the HTML and embed the URL using Output().

As an alternative, you could use some file or database to exchange the parameters, essentially some method Prepare(...)? writing the params to the file or database, and Render() reading those and placing the file again etc.

As yet another alternative (without writing to the file system): You could implement include the image data using a data: uri, but the image size will be limited depending on the browser used and you can't cache the data this way (i.e. you have to send it all the time).

Depending on what you're trying to achieve, you might have luck embedding a SVG image as well. This would offer the huge advantage of being in-place while still using less bandwith, being scalable, etc. Downside is, this is only supported in newest browsers (similar to data:) but there are no size restrictions.


Edit: Using the base64/embedded approach it get's a bit more tricky resulting in something like this (untested, but should work):

ob_start(); // buffers future output
imagepng($img); // writes to output/buffer
$b64 = base64_encode(ob_get_contents()); // returns output
ob_end_clean(); // clears buffered output
Mario
  • 35,726
  • 5
  • 62
  • 78
  • I got it working with your example with ob_start(). Does the page loading go slower when reading from the output buffers or is this a fully legal way to solve the problem I have? Will the speed of reading from the buffers depend on how many visitors there are at the same time on my homepage and make the homepage go slower? – Rox Jan 22 '12 at 11:38
  • In this case you shouldn't notice any significant delay. `ob_start()` just causes PHP to wait with sending output to `stdout` (till the script ends or one of the `ob_end_*()` functions is used). It should still be far more effectice then writing to disk first. Behind the scenes it's similar to writing to a stream and then reading the contents again. Unless the image is really huge, more visitors shouldn't cause any noticeable impact. But on the other hand: If this would cause such issues, other solutions would do so as well. As I mentioned, just don't use it for too huge images. – Mario Jan 22 '12 at 11:45
1

I had pretty much the same problem a while ago. You can find a solution and some possible problems of it here: Inline generated images exceeding length

The basic I think you are looking for is <img src="data:image/png;base64,[data in base64]"/>

Community
  • 1
  • 1
nikolas
  • 8,707
  • 9
  • 50
  • 70
1

The most probable cause for the blank screen has to do with two sets of header data being submitted. So, firstly you are running this statement:

echo "<htlm><head></head><body>";

Which will automatically set the content type of the data being sent to the browser. Next, you are running this line:

echo "<img src=\"".$render->Render(1)."\" />"; 

Which then causes this line to be run:

header("Content-type: image/png");

This then attempts to set a different header to that which has already been sent by the first echo statement.

I recommend chaning the Render() function to rather accept a filename, then write the image to that file and return the path pointing to the image file which was written. That way, you are not trying to output an image file and a html file in the same stream to the browser.

Regards, Ralfe

ralfe
  • 1,412
  • 2
  • 15
  • 25
  • Is it possible to create a file that is not saved to the disk? I don´t want the images to be saved to disk, just created and rendered direclty on the browser. – Rox Jan 21 '12 at 15:41
  • this doesn't answer the question, and is obviously untested since it includes typo's. – ashleedawg Jul 25 '19 at 18:42