Rectangle 27 0

php Image from database into PDF using FPDF?


<?php
// load the 'fpdf' extension
require('fpdf.php');

// just for demonstration purpose, the OP gets the content from a database instead
$h_img = fopen('img.jpg', "rb");
$img = fread($h_img, filesize('img.jpg'));
fclose($h_img);

// prepare a base64 encoded "data url"
$pic = 'data://text/plain;base64,' . base64_encode($img);
// extract dimensions from image
$info = getimagesize($pic);

// create a simple pdf document to prove this is very well possible: 
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello Image!');
$pdf->Image($pic, 10, 30, $info[0], $info[1], 'jpg');
$pdf->Output();

@MonkeyZeus Of course the fopen() fread() fclose() sequence is not required at all for the OP. That is why I added that remark to it clearly stating that fact. The code is meant as a primitive example to demonstrate the point here. Code examples should be complete in themselves if possible, so that they can be tried with as little implicit requirements as possible. Glad I could be of help and shed some light here. Have fun!

@RichardGriffiths That is a completely separate question about fpdf I'd say. In my eyes what you ask does make that much sense: pdf is a format to place elements in a very precise and distinct manner, quite unlike html. There is a workaroud however I remember using in tcpdf: it is easy in php to ask the dimensions of an image, you can use those values in the ->Image() call. Again you don't really need a physical file for that, you can use the same url scheme as shown in this answer here. Oh, and for flexible and convenient layouting: github.com/arkascha/php-urithmetic ;-)

An interesting debate and another good answer. One issue however is the sizing of the image. In your example you have 40 x 40. I realise this could be altered but could it be dynamic ie to handle portrait vs landscape?

As mentioned in the comments above this is possible by using a stream ("data url") to hand over the image data to the fpdf library without writing physical files to disk:

If this is a good advice is another question, this is merely meant to prove that this is possible...

Interesting proposal but I'm not quite sure I understand your example; why use fopen() at all? Could OP simply use $pdf->Image('data://text/plain;base64,'.base64_encode($row['photoData']), 10, 30, 40, 40, 'jpg'); and avoid the calls to fopen(), fread(), and fclose()? If so then this answer is better than mine because the only disk access would be the DB read operation for photoData. I am personally not familiar with this part 'data://text/plain;base64,' so maybe that is the source of my confusion.

Note
Rectangle 27 0

php Image from database into PDF using FPDF?


$pdf->Image($mysqlrow["blob"],0,0,40,0,'data');
require('fpdf.php');
class DATAIMAGE extends FPDF
{
protected function _parsedata($file)
{
    // Extract info from a JPEG file
    $a = getimagesizefromstring($file);
    if(!$a)
        $this->Error('Missing or incorrect image file: '.$file);
    if($a[2]!=2)
        $this->Error('Not a JPEG file: '.$file);
    if(!isset($a['channels']) || $a['channels']==3)
        $colspace = 'DeviceRGB';
    elseif($a['channels']==4)
        $colspace = 'DeviceCMYK';
    else
        $colspace = 'DeviceGray';
    $bpc = isset($a['bits']) ? $a['bits'] : 8;
    return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$file);
}
}

Make a new php by copying and pasting this (piece of fpdf's code edited):

Then call this php instead of fpdf.php in your main php.

You'll now be able to display an image simply by adding 'data' to the end of the function:

Note
Rectangle 27 0

php Image from database into PDF using FPDF?


<?php
// load the 'fpdf' extension
require('fpdf.php');

// just for demonstration purpose, the OP gets the content from a database instead
$h_img = fopen('img.jpg', "rb");
$img = fread($h_img, filesize('img.jpg'));
fclose($h_img);

// prepare a base64 encoded "data url"
$pic = 'data://text/plain;base64,' . base64_encode($img);
// extract dimensions from image
$info = getimagesize($pic);

// create a simple pdf document to prove this is very well possible: 
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial','B',16);
$pdf->Cell(40,10,'Hello Image!');
$pdf->Image($pic, 10, 30, $info[0], $info[1], 'jpg');
$pdf->Output();

@MonkeyZeus Of course the fopen() fread() fclose() sequence is not required at all for the OP. That is why I added that remark to it clearly stating that fact. The code is meant as a primitive example to demonstrate the point here. Code examples should be complete in themselves if possible, so that they can be tried with as little implicit requirements as possible. Glad I could be of help and shed some light here. Have fun!

@RichardGriffiths That is a completely separate question about fpdf I'd say. In my eyes what you ask does make that much sense: pdf is a format to place elements in a very precise and distinct manner, quite unlike html. There is a workaroud however I remember using in tcpdf: it is easy in php to ask the dimensions of an image, you can use those values in the ->Image() call. Again you don't really need a physical file for that, you can use the same url scheme as shown in this answer here. Oh, and for flexible and convenient layouting: github.com/arkascha/php-urithmetic ;-)

An interesting debate and another good answer. One issue however is the sizing of the image. In your example you have 40 x 40. I realise this could be altered but could it be dynamic ie to handle portrait vs landscape?

As mentioned in the comments above this is possible by using a stream ("data url") to hand over the image data to the fpdf library without writing physical files to disk:

If this is a good advice is another question, this is merely meant to prove that this is possible...

Interesting proposal but I'm not quite sure I understand your example; why use fopen() at all? Could OP simply use $pdf->Image('data://text/plain;base64,'.base64_encode($row['photoData']), 10, 30, 40, 40, 'jpg'); and avoid the calls to fopen(), fread(), and fclose()? If so then this answer is better than mine because the only disk access would be the DB read operation for photoData. I am personally not familiar with this part 'data://text/plain;base64,' so maybe that is the source of my confusion.

Note
Rectangle 27 0

php Image from database into PDF using FPDF?


<?php

$path = '/path/to/fpdf/images/';

$filename = $row['photo_id'].'.'.$row['photo_extension'];

$filepath = $path.$filename;

// If a physical file is not available then create it
// If the DB data is fresher than the file then make a new file
if(!is_file($filepath) || strtotime($row['last_update']) > filemtime($filepath))
{
    $result = file_put_contents($filepath, $row['photoData']);

    if($result === FALSE)
    {
        die(__FILE__.'<br>Error - Line #'.__LINE__.': Could not create '.$filepath);
    }
}

$pdf->Image($filepath);

Assuming your table has unique photo_id or photo_name to accompany photoData then you can use something like this to create your images and use them in FPDF.

Brilliant - all sorted. Your help is much appreciated.

I will also assume you have a last_update and photo_extension column.

If you plan on updating the photoData which is stored in your DB then you will have to make sure to also have a timestamp column and compare that timestamp against the filemtime($filepath) of the image on your disk.

Since FPDF cannot use base64 data to produce images on the PDF, I would recommend saving the file to the disk permanently as opposed to writing a temp file for every PDF operation.

This will save you a lot of I/O overhead.

Note
Rectangle 27 0

php Image from database into PDF using FPDF?


$pdf->Image($mysqlrow["blob"],0,0,40,0,'data');
require('fpdf.php');
class DATAIMAGE extends FPDF
{
protected function _parsedata($file)
{
    // Extract info from a JPEG file
    $a = getimagesizefromstring($file);
    if(!$a)
        $this->Error('Missing or incorrect image file: '.$file);
    if($a[2]!=2)
        $this->Error('Not a JPEG file: '.$file);
    if(!isset($a['channels']) || $a['channels']==3)
        $colspace = 'DeviceRGB';
    elseif($a['channels']==4)
        $colspace = 'DeviceCMYK';
    else
        $colspace = 'DeviceGray';
    $bpc = isset($a['bits']) ? $a['bits'] : 8;
    return array('w'=>$a[0], 'h'=>$a[1], 'cs'=>$colspace, 'bpc'=>$bpc, 'f'=>'DCTDecode', 'data'=>$file);
}
}

Make a new php by copying and pasting this (piece of fpdf's code edited):

Then call this php instead of fpdf.php in your main php.

You'll now be able to display an image simply by adding 'data' to the end of the function:

Note
Rectangle 27 0

php Image from database into PDF using FPDF?


$im = new \Imagick();
$im->readImageBlob($row['photoData']);
$im->setImageFormat('pdf');
header('Content-Type: application/pdf');
echo $im;
$tmpFile = tempnam(sys_get_temp_dir(), 'fpdfimg');
if (file_put_contents($tmpFile, $row['photoData'])) {
    $fpdf->Image($tmpFile);
    // save/display image
    unlink($tmpFile);
}

According to the Docs FPDF::Image accepts a filename as the first argument, not a binary blob.

Alternatively, if you want to just serve the image as a PDF (with no other content) you could use Imagick:

I've added an example of saving using a temporary file

If you want to use FPDF specifically, save the image to a temporary file first, and then pass that to FPDF::Image.

Thanks. There are quite a few images and other text too so the temporary save to the server seems to be the best option at the moment. But I am struggling to see how you get from echo "<img src=\"data:image/jpg;charset=utf8;base64, $img\"/>"; to be saving to the server instead of displaying on the screen.

To do that, something like this should work:

Note
Rectangle 27 0

php Image from database into PDF using FPDF?


$im = new \Imagick();
$im->readImageBlob($row['photoData']);
$im->setImageFormat('pdf');
header('Content-Type: application/pdf');
echo $im;
$tmpFile = tempnam(sys_get_temp_dir(), 'fpdfimg');
if (file_put_contents($tmpFile, $row['photoData'])) {
    $fpdf->Image($tmpFile);
    // save/display image
    unlink($tmpFile);
}

According to the Docs FPDF::Image accepts a filename as the first argument, not a binary blob.

Alternatively, if you want to just serve the image as a PDF (with no other content) you could use Imagick:

I've added an example of saving using a temporary file

If you want to use FPDF specifically, save the image to a temporary file first, and then pass that to FPDF::Image.

Thanks. There are quite a few images and other text too so the temporary save to the server seems to be the best option at the moment. But I am struggling to see how you get from echo "<img src=\"data:image/jpg;charset=utf8;base64, $img\"/>"; to be saving to the server instead of displaying on the screen.

To do that, something like this should work:

Note