13

I've some as base64 stored images in a database. Is it possible to print those data directly in a PDF document, using FPDF?

Data sctructure of the image

data:image/png;base64,iVBORw0KGgoAAAANSUhEUg7AAAfQAAACWCAYAAAAonXpvAAAfgUlEQVR4Ae2dC9BuVVnHuSN3QaBENA9h5A2IcJxMj8hUkymoQDfClIkmrQZr1EydMqapnKRMc8JmHLBBHadJJaV0lKQDZCmCQiqQ2KERUFARDhcFDpx /33W tznPe/ 3ttaa9/ a2Z9/32Xvt5nvVbl2evtdfee9dtS27bt4mACJmACJm8ACJtBvArv123xbbwImYAImYAImIAJ26K4HJmACJmACJjAAAnboAyhEZ8EETMAETMAE7NBdB0zABEzABExgAATs0AdQiM6CCZiACZiACdihuw6YgAmYgAmYwAAI2KEPoBCdBRMwARMwAROwQ3cdMAETMAETMIEBELBDH0AhOgsmYAImYAImYIfuOmACJm

I think $pdf->imagepng() should be the right function in FPDF.

Thomas1703
  • 1,152
  • 5
  • 16
  • 33

8 Answers8

28

While the comments suggested a TCPDF solution, I did want to state that there is a way to do this entirely with FPDF. The thought process is like this:

  1. Strip data:image/png;base64, from the URI using explode
  2. Decode the URI with base64_decode
  3. Save the decoded data to a PNG file with file_put_contents
  4. Generate a PDF and add the PNG file with Image
  5. Delete the PNG file with unlink

Always remember to error check. If the image fails to save to the server you obviously do not want to continue execution. Make sure to always strictly check if the functions return false!

Here is my solution. I used a tiny image for a small URI in this example.

const TEMPIMGLOC = 'tempimg.png';

$dataURI    = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAMAAADarb8dAAAABlBMVEUAAADtHCTeKUOwAAAAF0lEQVR4AWOgAWBE4zISkMbDZQRyaQkABl4ADHmgWUYAAAAASUVORK5CYII=";
$dataPieces = explode(',',$dataURI);
$encodedImg = $dataPieces[1];
$decodedImg = base64_decode($encodedImg);

//  Check if image was properly decoded
if( $decodedImg!==false )
{
    //  Save image to a temporary location
    if( file_put_contents(TEMPIMGLOC,$decodedImg)!==false )
    {
        //  Open new PDF document and print image
        $pdf = new FPDF();
        $pdf->AddPage();
        $pdf->Image(TEMPIMGLOC);
        $pdf->Output();

        //  Delete image from server
        unlink(TEMPIMGLOC);
    }
}
Muhammad Abdul-Rahim
  • 1,980
  • 19
  • 31
18

I know this is an old topic, but there is an easier way of solving this problem. Just try this simple steps:

  1. Strip data:image/png;base64 from URI using explode
  2. Concatenate data://text/plain;base64, with what is left from the stripped URI
  3. Use the result string(base64) as argument of FPDF Image()

Example:

$dataURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAMAAADarb8dAAAABlBMVEUAAADtHCTeKUOwAAAAF0lEQVR4AWOgAWBE4zISkMbDZQRyaQkABl4ADHmgWUYAAAAASUVORK5CYII=";

$img = explode(',',$dataURI,2)[1];
$pic = 'data://text/plain;base64,'. $img;

$pdf = new FPDF();
$pdf->AddPage();
$pdf->Image($pic, 10,30,0,0,'png');
$pdf->Output();

Remember to choose the correct image type for Image() method call.

zeko868
  • 163
  • 1
  • 3
  • 10
Pedro Soares
  • 303
  • 2
  • 8
  • 1
    This is great. How did you figure this out? – Gregory Bologna Jul 18 '19 at 14:03
  • Won't it be faster if we simply str_replace "image/png" with "text/plain"? – Daniel Wu Aug 23 '21 at 03:30
  • See, it's things like this that makes me not completely give up hope in fellow programmers. Others who actually investigate how things work and not just go "oh, download this library with these 16 dependencies - and you'll need to downgrade your php version to 5.4 for it work" Thank you for being awesome! – Daniel Bengtsson Dec 02 '21 at 16:32
8

To ensure the images work with FPDF and to avoid errors, here is a modified version of @pedro-soares' code:

function getImage($dataURI){
  $img = explode(',',$dataURI,2);
  $pic = 'data://text/plain;base64,'.$img[1];
  $type = explode("/", explode(':', substr($dataURI, 0, strpos($dataURI, ';')))[1])[1]; // get the image type
  if ($type=="png"||$type=="jpeg"||$type=="gif") return array($pic, $type);
  return false;
}

Because FPDF only allows these three file types, it is important to check that it is valid. To use:

$pic = getImage($Base64StringGoesHere);
if ($pic!==false) $pdf->Image($pic[0], 10,30,0,0, $pic[1]);
Xavier Ruiz
  • 143
  • 2
  • 6
2

Don't know why haven't anyone wrote this solution till now, but I have had success by directly passing the base64 string to FPDF's Image() function. Just make sure that your base64 string has data:image/png;base64, at the beginning.

$data = "base64_string.........";
$pdf -> Image($data, 0, 0, 0, 0, "PNG");

Please note that you have to explicitly specify the image type "PNG". The 4 0s are for the image X, Y width and height respectively. Set the width and height to 0 for FPDF to automatically use the image's dimensions.

Puspam
  • 2,137
  • 2
  • 12
  • 35
  • Agreed. I only use the default base64 returned by Dropbox when downloading an image, I set the extension obtained from base64 string in the Image() method and it works, there is no necessity for transforming to text/plain as suggested in top answers. – Fabrizio Valencia Jun 29 '22 at 19:18
1

To add a bit more to Mari M answer, I just added few lines to work with any types of images. (as for me FPDF complains if the image is jpeg and I try to load tempimg.png)

$this->tempImgLoc = 'tempimg';    // Here I just remove the file extension
$dataPieces = explode(',',$dataURI);
$encodedImg = $dataPieces[1];
$decodedImg = base64_decode($encodedImg);

// extract the image type from data:image/png;base64
$extension = explode('/', $dataPieces[0]);
$extension = explode(';', $extension[1]);

$this->tempImgLoc .= '.' . $extension[0];

I am sure there is a better way to do that with regular expression, but to be honest, regexp is not my cup of tea...

195436
  • 273
  • 2
  • 10
1

Ok, I wasted half day making test with this issue. I have to tell that this solution is for print images from db row, directly, without stored them on temp files.

I´m going to write some points to consider:

  • I´m using blob type on the DB to store human signature for print on pdf document
  • I´m sending the signature to store to the db by post method, from a canvas node.
  • When I print the string from the db blob, it´s come without the plus character "+" that don´t let me to print correctly the signature. To solve this issue, I make a "str_replace" to remove the blank spaces and insert the plus character.

Then the only thing that you have to do is:

$pdf->Image(str_replace(' ','+',$dbRow['blobImage']),160,150,20,10,'png');

If you need , like me, print several images from the db, you have to see if them come or not, because if the image come empty, you´ll have an error.

I just add this to the last code:

if( $dbRow['blobImage'] ){
                 $pdf->Image(str_replace(' ','+',$dbRow['blobImage']),160,150,20,10,'png');
            }

NOTE:

  • 160 -> X position of the image
  • 150 -> Y position of the image
  • 20 -> X Scale of the image
  • 10 -> Y Scale of the image
  • 'png' -> The base format of my Base64 Image Type.
Antonio
  • 58
  • 6
1

New solution with imagecreatefromstring() Summer 2019

  • delete temporary .png if exist
  • create temporary .png file
  • use $pdf->Image (fpdf)

My Api returns me a Datamatrix of 1234 as Byte Array. The folowing code shows you how to use that Byte Array as Png in Fpdf.

My $response = "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABJSURBVChTjYwBCgAgCAP9/6dNreVUgg7Gps3EUOfD5Q4Au6YdAGcH8ygyVKrFnhmbc9FL7qRxWRxEkXWW4Q691UsGpZPzt7dEFyY47RMW+x2LAAAAAElFTkSuQmCC"

$filename = '/lk_Reptool/printing/tmp/tmppng.png';

if (file_exists($filename)) {
    unlink($filename);
}
$response = file_get_contents('https://myapi.com/TwoDCode/GetDatamatrixAsPngByteArray?datamatrixText=' . $RepID . '&pixelSize=100');
$response = base64_decode($response);
$img = imagecreatefromstring($response);
imagepng($img, $filename);

code for pdf

$pdf = new PDF('P', 'mm', 'A4');
$pdf->AddPage();
$pdf->Image('/lk_Reptool/printing/tmp/tmppng.png', 180, 20, 10, 10);
0

Simply extend Fpdf (tested on 1.8.1) with this function:

protected function _parsepngdata($data) {
    $f = tmpfile();
    fwrite($f, base64_decode(substr($data, strpos($data,",")+1)));
    fseek($f, 0);
    $info = $this->_parsepngstream($f,"pngdata");
    fclose($f);
    return $info;
}

and use it this way: (provide base64 data instead of file name, and set type to "pngdata" instead of "png")

$pdf->Image("data:image/png;base64,iVBORw0KGgo...", $x, $y, $w, $h, "pngdata");

It will create a tempory file, write / read data to/from and delete it afterwards.

snoarf
  • 1