Build and push a Docker image to Dockerhub

Start up your docker machine, then login with

docker login

Build the image using

docker build . -t vendor/package:x.x.x

Push to dockerhub

docker push vendor/package:x.x.x

Transparent image uploads in PHP

This is an age old problem lol! Your transparent images have a nasty black background! Anyway, if you upload a GIF or PNG you need to set the transparent background color etc. In my image class, if I do a straight save there isn’t a problem, only when I resized. So I put the following in my resize function:

public function resize($width,$height) 
    {
        $new_image = imagecreatetruecolor($width, $height);
        if ( ($this->getImageType() == IMAGETYPE_GIF) || ($this->getImageType()  == IMAGETYPE_PNG) ) 
        {
            $transparency = imagecolortransparent($this->_image);
            if ($transparency >= 0) 
            {
                $transparent_color = imagecolorsforindex($this->_image, $transparency);
                $transparency = imagecolorallocate($new_image, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
                imagefill($new_image, 0, 0, $transparency);
                imagecolortransparent($new_image, $transparency);
            }
            elseif ($this->getImageType() == IMAGETYPE_PNG) 
            {
                imagealphablending($new_image, false);
                imagesavealpha($new_image, true);
                $color = imagecolorallocatealpha($new_image, 0, 0, 0, 127);
                imagefill($new_image, 0, 0, $color);
            }
        }
        imagecopyresampled($new_image, $this->_image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
        $this->_image = $new_image;
    }

That will save your PNG’s or GIF’s and retain their transparency. However, PNG’s will NOT outpuut correctly unless you explicitly tell php to retain alpha channel info:

imagealphablending($this->_image,true);
imagesavealpha($this->_image,true);
imagepng($this->_image);

Here is the full Image class, with the transparency feature:

<?php
/**
* Utility class for processing images
* @author alasdair.shields
* 6 Feb 2012
*/
class ESOS_Entity_Image {

    protected $_image;
    protected $_image_type;


    /** 
     *  @param string $filename
     */
    public function load($filename) 
    {

        $image_info = getimagesize($filename);
        $this->_image_type = $image_info[2];
        if( $this->_image_type == IMAGETYPE_JPEG ) 
        {
            $this->_image = imagecreatefromjpeg($filename);
        } 
        elseif( $this->_image_type == IMAGETYPE_GIF ) 
        {
            $this->_image = imagecreatefromgif($filename);
        } 
        elseif( $this->_image_type == IMAGETYPE_PNG ) 
        {
            $this->_image = imagecreatefrompng($filename);
        }
    }


    /** 
     *  @param string $filename
     *  @param string $image_type
     *  @param int $compression
     *  @param string $permissions
     */
    public function save($filename, $compression=75, $permissions=null) 
    {
        switch($this->getImageType())
        {
            case IMAGETYPE_JPEG:
                imagejpeg($this->_image,$filename,$compression);
                break;
            case IMAGETYPE_GIF:
                imagegif($this->_image,$filename);
                break;
            case IMAGETYPE_PNG:
                imagepng($this->_image,$filename);
                break;
        }
        if( $permissions != null) 
        {
            chmod($filename,$permissions);
        }
    }


    /** 
     *  @param string 
     */
    public function output() 
    {
        switch($this->getImageType())
        {
            case IMAGETYPE_JPEG:
                imagejpeg($this->_image);
                break;
            case IMAGETYPE_GIF:
                imagegif($this->_image);
                break;
            case IMAGETYPE_PNG:
                imagealphablending($this->_image,true);
                imagesavealpha($this->_image,true);
                imagepng($this->_image);
                break;
        }
    }

    public function getWidth() 
    {

        return imagesx($this->_image);
    }

    public function getHeight() 
    {

        return imagesy($this->_image);
    }

    public function resizeToHeight($height) 
    {

        $ratio = $height / $this->getHeight();
        $width = $this->getWidth() * $ratio;
        $this->resize($width,$height);
    }

    public function resizeToWidth($width) 
    {
        $ratio = $width / $this->getWidth();
        $height = $this->getheight() * $ratio;
        $this->resize($width,$height);
    }

    public function scale($scale) 
    {
        $width = $this->getWidth() * $scale/100;
        $height = $this->getheight() * $scale/100;
        $this->resize($width,$height);
    }


    /** 
     *  Now with added Transparency resizing feature
     *  @param int $width
     *  @param int $height
     */
    public function resize($width,$height) 
    {
        
        $new_image = imagecreatetruecolor($width, $height);
        if ( ($this->getImageType() == IMAGETYPE_GIF) || ($this->getImageType()  == IMAGETYPE_PNG) ) 
        {
            // Get transparency color's index number
            $transparency = imagecolortransparent($this->_image);
            
            // Transparent Gifs have index > 0
            // Transparent Png's have index -1
            if ($transparency >= 0) 
            {
                // Get the array of RGB vals for the transparency index
                $transparent_color = imagecolorsforindex($this->_image, $transparency);
                
                // Now allocate the color
                $transparency = imagecolorallocate($new_image, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
                
                // Fill the background with the color
                imagefill($new_image, 0, 0, $transparency);
                
                // And set that color as the transparent one
                imagecolortransparent($new_image, $transparency);
            }
            // Or, if its a PNG
            elseif ($this->getImageType() == IMAGETYPE_PNG) 
            {
                // Set blending mode as false
                imagealphablending($new_image, false);
                
                // Tell it we want to save alpha channel info
                imagesavealpha($new_image, true);
                
                // Set the transparent color
                $color = imagecolorallocatealpha($new_image, 0, 0, 0, 127);
                
                // Fill the image with nothingness
                imagefill($new_image, 0, 0, $color);
            }
        }
        // Now resample the image
        imagecopyresampled($new_image, $this->_image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
        
        // And allocate to $this
        $this->_image = $new_image;
    }

    
    public function getImageType()
    {
        return $this->_image_type;
    }


    

    public function getHeader() 
    {
        if( $this->_image_type == IMAGETYPE_JPEG ) 
        {
            return 'image/jpeg';
        } 
        elseif( $this->_image_type == IMAGETYPE_GIF ) 
        {
            return 'image/gif';
        } 
        elseif( $this->_image_type == IMAGETYPE_PNG ) 
        {
            return 'image/png';
        }
    }


    /** 
     *  Free's up memory
     */
    public function destroy()
    {
        imagedestroy($this->_image);
    }
}

Outputting Images as base64 encoded strings

As you know, user uploads shouldn’t be in the public folder of your site, as that poses a security risk. However it also means that you need to make some sort of download controller, and the problem with that is that it’s sending more unnecessary requests than it needs to, and depending how you set your download controller up, it could go through a ton of framework php just to process your image!

So instead of having

<img src="/some/url/" />

I decided to actually output the src directly in the page, rather than have another request sent.

<img src="data:image/jpeg;base64,/9j/4AAQSkZJRABAgMRBAUhMQYEtcEtcEtcEtcEtc">

First up, here’s my image class. I added getHeader() and destroy() methods to it.

<?php
/**
* Utility class for processing images
* 6 Feb 2012
*/
class ESOS_Entity_Image {

    protected $_image;
    protected $_image_type;

    public function load($filename) {

        $image_info = getimagesize($filename);
        $this->_image_type = $image_info[2];
        if( $this->_image_type == IMAGETYPE_JPEG ) {

            $this->_image = imagecreatefromjpeg($filename);
        } elseif( $this->_image_type == IMAGETYPE_GIF ) {

            $this->_image = imagecreatefromgif($filename);
        } elseif( $this->_image_type == IMAGETYPE_PNG ) {

            $this->_image = imagecreatefrompng($filename);
        }
    }

    public function save($filename, $image_type=IMAGETYPE_JPEG, $compression=75, $permissions=null) {

        if( $image_type == IMAGETYPE_JPEG ) {
            imagejpeg($this->_image,$filename,$compression);
        } elseif( $image_type == IMAGETYPE_GIF ) {

            imagegif($this->_image,$filename);
        } elseif( $image_type == IMAGETYPE_PNG ) {

            imagepng($this->_image,$filename);
        }
        if( $permissions != null) {

            chmod($filename,$permissions);
        }
    }

    public function output($image_type=IMAGETYPE_JPEG) {

        if( $image_type == IMAGETYPE_JPEG ) {
            imagejpeg($this->_image);
        } elseif( $image_type == IMAGETYPE_GIF ) {

            imagegif($this->_image);
        } elseif( $image_type == IMAGETYPE_PNG ) {

            imagepng($this->_image);
        }
    }

    public function getWidth() {

        return imagesx($this->_image);
    }

    public function getHeight() {

        return imagesy($this->_image);
    }

    public function resizeToHeight($height) {

        $ratio = $height / $this->getHeight();
        $width = $this->getWidth() * $ratio;
        $this->resize($width,$height);
    }

    public function resizeToWidth($width) {
        $ratio = $width / $this->getWidth();
        $height = $this->getheight() * $ratio;
        $this->resize($width,$height);
    }

    public function scale($scale) {
        $width = $this->getWidth() * $scale/100;
        $height = $this->getheight() * $scale/100;
        $this->resize($width,$height);
    }

    public function resize($width,$height) {
        $new_image = imagecreatetruecolor($width, $height);
        imagecopyresampled($new_image, $this->_image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
        $this->_image = $new_image;
    }

    public function getImageType()
    {
        return $this->_image_type;
    }


    

    public function getHeader() {

        if( $this->_image_type == IMAGETYPE_JPEG ) {
            return 'image/jpeg';
        } elseif( $this->_image_type == IMAGETYPE_GIF ) {
            return 'image/gif';
        } elseif( $this->_image_type == IMAGETYPE_PNG ) {
            return 'image/png';
        }
    }


    /** 
     *  Free's up memory
     */
    public function destroy()
    {
        imagedestroy($this->_image);
    }

}

Now for the fun part. In your image helper class:

<?php

class ESOS_View_Helper_OrgImage
{
    public function orgImage(ESOS_Entity_Organisation $org)
    {
        $id = $org->getLogoFileId();
        if($id != null)
        {
            $file_svc = ESOS_Service_Locator::getInstance()->getFileSvc();
            $file = $file_svc->getFile($id);
            $path = $file->getPath().DIRECTORY_SEPARATOR.$file->getFilenameOnDisk();
            $img = new ESOS_Entity_Image();
            $img->load(UPLOAD_PATH.$path);
            $header = $img->getHeader();

            ob_start();
             $img->output();
             $img->destroy();
            $i = ob_get_clean();
            
            return( '<img src="data:'.$header.';base64,' . base64_encode( $i ).'" />');
        }
    }
}

The important part to note is the section after ob_start(). We start output buffering the image, free up the memory, and clear the output buffer, allocating the output to a variable. Finally, we base64 encode the output, and return the image with src set to data:image/jpeg;base64,blahblah_encoded_string.

You now have your image, and have it in the same request! Have fun! I’m going to tweak this class now to set id, classes and styles!

Using Tiny MCE javascript WYSIWYG

Just some quick notes.
Firstly, don’t give your customers all those buttons! They will end up breaking something!
Secondly, although they bang on about a jQuery version, I just could not get it to work!
Probably the most important factor here is adding images etc. Without buying some $50 plugin, its actually one line of code!
Anyway, here’s a typical setup from one of my sites:

<script type="text/javascript" src="/js/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">

$(document).ready(function() {
tinyMCE.init({
plugins : '-example', // - tells TinyMCE to skip the loading of the plugin
    mode : "textareas",
    theme : "advanced",
    theme_advanced_blockformats : "p,div,h1,h2,h3,h4,h5,h6,blockquote,dt,dd,code,samp",
    theme_advanced_buttons1 : "image, bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,bullist,numlist,undo,redo,link,unlink,formatselect,code",
    theme_advanced_buttons2 : "",
    theme_advanced_buttons3 : "",
    theme_advanced_toolbar_location : "top",
    theme_advanced_toolbar_align : "left",
    theme_advanced_statusbar_location : "bottom",
 editor_encoding: "raw",
    remove_linebreaks : false,
    convert_newlines_to_brs : true

// Example content CSS (should be your site CSS)
content_css : "css/style.css",

});

//adding your images ionto the tinmce window
$('#click').click(function(){
img = '<img src="http://your/url/to/image.jpg" />';
tinyMCE.execCommand('mceInsertContent',false,img);
});
});
</script>

Google QR Codes and Zend_PDF

Now that we can generate QR codes using the Google Chart API, and we have a controller action that serves it up for us with the correct .PNG header (see my previous post), we need to get it where it’s of any use – on paper!

So following on from my last post about Zend_Pdf, we can now do the following to get it in our PDF:

//draw qr code
 $target = 'http://example.co.uk/download/qr?target=http://www.example.co.uk/properties/view/id/'.$prop->getID();
 $img = file_get_contents($target); 
 file_put_contents(APPLICATION_PATH.'/uploads/tmp/'.$prop->getID().'-qr.png',$img);
 $image = Zend_Pdf_Image::imageWithPath(APPLICATION_PATH.'/uploads/tmp/'.$prop->getID().'-qr.png');
 $page->drawImage($image, 13, 13, 94,94);
 unlink(APPLICATION_PATH.'/uploads/tmp/'.$prop->getPid().'-qr.png');

The first line of code is the url of our download controllers QR action.  file_get_contents stores the image in memory, which we then save into a temp folder using file_put_contents. These commands are the equivalent of a lot of fopen etc, so use them if you don’t already!  This example uses my property object to make a dynamic filename, but this isn’t necessary, but I don’t need to tell you that!

We then use Zend_Pdf to load our png, and when drawing an image, the numbers in the argument are x1, y1, x2, y2 being bottom left and top right corners respectively. Finally, ditch the temp file with the unlink command. Have Fun!