Menu

SVG and JPG support

Richard
2011-10-30
2013-04-25
  • Richard

    Richard - 2011-10-30

    Replace the following files with the ones below

    qrencode.php

    <?php
    /*
     * PHP QR Code encoder
     *
     * Main encoder classes.
     *
     * Based on libqrencode C library distributed under LGPL 2.1
     * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
     *
     * PHP QR Code is distributed under LGPL 3
     * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 3 of the License, or any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
     */
    
        class QRrsblock {
            public $dataLength;
            public $data = array();
            public $eccLength;
            public $ecc = array();
            
            public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
            {
                $rs->encode_rs_char($data, $ecc);
            
                $this->dataLength = $dl;
                $this->data = $data;
                $this->eccLength = $el;
                $this->ecc = $ecc;
            }
        };
        
        //##########################################################################
        class QRrawcode {
            public $version;
            public $datacode = array();
            public $ecccode = array();
            public $blocks;
            public $rsblocks = array(); //of RSblock
            public $count;
            public $dataLength;
            public $eccLength;
            public $b1;
            
            //----------------------------------------------------------------------
            public function __construct(QRinput $input)
            {
                $spec = array(0,0,0,0,0);
                
                $this->datacode = $input->getByteStream();
                if(is_null($this->datacode)) {
                    throw new Exception('null imput string');
                }
                QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
                $this->version = $input->getVersion();
                $this->b1 = QRspec::rsBlockNum1($spec);
                $this->dataLength = QRspec::rsDataLength($spec);
                $this->eccLength = QRspec::rsEccLength($spec);
                $this->ecccode = array_fill(0, $this->eccLength, 0);
                $this->blocks = QRspec::rsBlockNum($spec);
                
                $ret = $this->init($spec);
                if($ret < 0) {
                    throw new Exception('block alloc error');
                    return null;
                }
                $this->count = 0;
            }
            
            //----------------------------------------------------------------------
            public function init(array $spec)
            {
                $dl = QRspec::rsDataCodes1($spec);
                $el = QRspec::rsEccCodes1($spec);
                $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
                
                $blockNo = 0;
                $dataPos = 0;
                $eccPos = 0;
                for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {
                    $ecc = array_slice($this->ecccode,$eccPos);
                    $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el,  $ecc, $rs);
                    $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
                    
                    $dataPos += $dl;
                    $eccPos += $el;
                    $blockNo++;
                }
                if(QRspec::rsBlockNum2($spec) == 0)
                    return 0;
                $dl = QRspec::rsDataCodes2($spec);
                $el = QRspec::rsEccCodes2($spec);
                $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
                
                if($rs == NULL) return -1;
                
                for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {
                    $ecc = array_slice($this->ecccode,$eccPos);
                    $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
                    $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
                    
                    $dataPos += $dl;
                    $eccPos += $el;
                    $blockNo++;
                }
                return 0;
            }
            
            //----------------------------------------------------------------------
            public function getCode()
            {
                $ret;
                if($this->count < $this->dataLength) {
                    $row = $this->count % $this->blocks;
                    $col = $this->count / $this->blocks;
                    if($col >= $this->rsblocks[0]->dataLength) {
                        $row += $this->b1;
                    }
                    $ret = $this->rsblocks[$row]->data[$col];
                } else if($this->count < $this->dataLength + $this->eccLength) {
                    $row = ($this->count - $this->dataLength) % $this->blocks;
                    $col = ($this->count - $this->dataLength) / $this->blocks;
                    $ret = $this->rsblocks[$row]->ecc[$col];
                } else {
                    return 0;
                }
                $this->count++;
                
                return $ret;
            }
        }
        //##########################################################################
        
        class QRcode {
        
            public $version;
            public $width;
            public $data; 
            
            //----------------------------------------------------------------------
            public function encodeMask(QRinput $input, $mask)
            {
                if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
                    throw new Exception('wrong version');
                }
                if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
                    throw new Exception('wrong level');
                }
                $raw = new QRrawcode($input);
                
                QRtools::markTime('after_raw');
                
                $version = $raw->version;
                $width = QRspec::getWidth($version);
                $frame = QRspec::newFrame($version);
                
                $filler = new FrameFiller($width, $frame);
                if(is_null($filler)) {
                    return NULL;
                }
                // inteleaved data and ecc codes
                for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
                    $code = $raw->getCode();
                    $bit = 0x80;
                    for($j=0; $j<8; $j++) {
                        $addr = $filler->next();
                        $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
                        $bit = $bit >> 1;
                    }
                }
                
                QRtools::markTime('after_filler');
                
                unset($raw);
                
                // remainder bits
                $j = QRspec::getRemainder($version);
                for($i=0; $i<$j; $i++) {
                    $addr = $filler->next();
                    $filler->setFrameAt($addr, 0x02);
                }
                
                $frame = $filler->frame;
                unset($filler);
                
                
                // masking
                $maskObj = new QRmask();
                if($mask < 0) {
                
                    if (QR_FIND_BEST_MASK) {
                        $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
                    } else {
                        $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
                    }
                } else {
                    $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
                }
                
                if($masked == NULL) {
                    return NULL;
                }
                
                QRtools::markTime('after_mask');
                
                $this->version = $version;
                $this->width = $width;
                $this->data = $masked;
                
                return $this;
            }
        
            //----------------------------------------------------------------------
            public function encodeInput(QRinput $input)
            {
                return $this->encodeMask($input, -1);
            }
            
            //----------------------------------------------------------------------
            public function encodeString8bit($string, $version, $level)
            {
                if(string == NULL) {
                    throw new Exception('empty string!');
                    return NULL;
                }
                $input = new QRinput($version, $level);
                if($input == NULL) return NULL;
                $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));
                if($ret < 0) {
                    unset($input);
                    return NULL;
                }
                return $this->encodeInput($input);
            }
            //----------------------------------------------------------------------
            public function encodeString($string, $version, $level, $hint, $casesensitive)
            {
                if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
                    throw new Exception('bad hint');
                    return NULL;
                }
                $input = new QRinput($version, $level);
                if($input == NULL) return NULL;
                $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
                if($ret < 0) {
                    return NULL;
                }
                return $this->encodeInput($input);
            }
            
            //----------------------------------------------------------------------
            public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) 
            {
                $enc = QRencode::factory($level, $size, $margin);
                return $enc->encodePNG($text, $outfile, $saveandprint=false);
            }
    
            //----------------------------------------------------------------------
            public static function jpg($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) 
            {
                $enc = QRencode::factory($level, $size, $margin);
                return $enc->encodeJPG($text, $outfile, $saveandprint=false);
            }
    
            //----------------------------------------------------------------------
            public static function svg($text, $outfile = false, $level = QR_ECLEVEL_L, $margin = 4) 
            {
                $enc = QRencode::factory($level, 1, $margin);
                return $enc->encodeSVG($text, $outfile, $saveandprint=false);
            }
    
            //----------------------------------------------------------------------
            public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
            {
                $enc = QRencode::factory($level, $size, $margin);
                return $enc->encode($text, $outfile);
            }
            //----------------------------------------------------------------------
            public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4) 
            {
                $enc = QRencode::factory($level, $size, $margin);
                return $enc->encodeRAW($text, $outfile);
            }
        }
        
        //##########################################################################
        
        class FrameFiller {
        
            public $width;
            public $frame;
            public $x;
            public $y;
            public $dir;
            public $bit;
            
            //----------------------------------------------------------------------
            public function __construct($width, &$frame)
            {
                $this->width = $width;
                $this->frame = $frame;
                $this->x = $width - 1;
                $this->y = $width - 1;
                $this->dir = -1;
                $this->bit = -1;
            }
            
            //----------------------------------------------------------------------
            public function setFrameAt($at, $val)
            {
                $this->frame[$at['y']][$at['x']] = chr($val);
            }
            
            //----------------------------------------------------------------------
            public function getFrameAt($at)
            {
                return ord($this->frame[$at['y']][$at['x']]);
            }
            
            //----------------------------------------------------------------------
            public function next()
            {
                do {
                
                    if($this->bit == -1) {
                        $this->bit = 0;
                        return array('x'=>$this->x, 'y'=>$this->y);
                    }
                    $x = $this->x;
                    $y = $this->y;
                    $w = $this->width;
                    if($this->bit == 0) {
                        $x--;
                        $this->bit++;
                    } else {
                        $x++;
                        $y += $this->dir;
                        $this->bit--;
                    }
                    if($this->dir < 0) {
                        if($y < 0) {
                            $y = 0;
                            $x -= 2;
                            $this->dir = 1;
                            if($x == 6) {
                                $x--;
                                $y = 9;
                            }
                        }
                    } else {
                        if($y == $w) {
                            $y = $w - 1;
                            $x -= 2;
                            $this->dir = -1;
                            if($x == 6) {
                                $x--;
                                $y -= 8;
                            }
                        }
                    }
                    if($x < 0 || $y < 0) return null;
                    $this->x = $x;
                    $this->y = $y;
                } while(ord($this->frame[$y][$x]) & 0x80);
                            
                return array('x'=>$x, 'y'=>$y);
            }
            
        } ;
        
        //##########################################################################    
        
        class QRencode {
        
            public $casesensitive = true;
            public $eightbit = false;
            
            public $version = 0;
            public $size = 3;
            public $margin = 4;
            
            public $structured = 0; // not supported yet
            
            public $level = QR_ECLEVEL_L;
            public $hint = QR_MODE_8;
            
            //----------------------------------------------------------------------
            public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4)
            {
                $enc = new QRencode();
                $enc->size = $size;
                $enc->margin = $margin;
                
                switch ($level.'') {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                            $enc->level = $level;
                        break;
                    case 'l':
                    case 'L':
                            $enc->level = QR_ECLEVEL_L;
                        break;
                    case 'm':
                    case 'M':
                            $enc->level = QR_ECLEVEL_M;
                        break;
                    case 'q':
                    case 'Q':
                            $enc->level = QR_ECLEVEL_Q;
                        break;
                    case 'h':
                    case 'H':
                            $enc->level = QR_ECLEVEL_H;
                        break;
                }
                
                return $enc;
            }
            
            //----------------------------------------------------------------------
            public function encodeRAW($intext, $outfile = false) 
            {
                $code = new QRcode();
                if($this->eightbit) {
                    $code->encodeString8bit($intext, $this->version, $this->level);
                } else {
                    $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
                }
                
                return $code->data;
            }
            //----------------------------------------------------------------------
            public function encode($intext, $outfile = false) 
            {
                $code = new QRcode();
                if($this->eightbit) {
                    $code->encodeString8bit($intext, $this->version, $this->level);
                } else {
                    $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
                }
                
                QRtools::markTime('after_encode');
                
                if ($outfile!== false) {
                    file_put_contents($outfile, join("\n", QRtools::binarize($code->data)));
                } else {
                    return QRtools::binarize($code->data);
                }
            }
            
            //----------------------------------------------------------------------
            public function encodePNG($intext, $outfile = false,$saveandprint=false) 
            {
                try {
                
                    ob_start();
                    $tab = $this->encode($intext);
                    $err = ob_get_contents();
                    ob_end_clean();
                    
                    if ($err != '')
                        QRtools::log($outfile, $err);
                    
                    $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
                    
                    QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
                
                } catch (Exception $e) {
                
                    QRtools::log($outfile, $e->getMessage());
                
                }
            }
            
            //----------------------------------------------------------------------
            public function encodeSVG($intext, $outfile = false,$saveandprint=false) 
            {
                try {
                
                    ob_start();
                    $tab = $this->encode($intext);
                    $err = ob_get_contents();
                    ob_end_clean();
                    
                    if ($err != '')
                        QRtools::log($outfile, $err);
                    
                    QRimage::svg($tab, $outfile, $this->margin,$saveandprint);
                
                } catch (Exception $e) {
                
                    QRtools::log($outfile, $e->getMessage());
                
                }
            }
                    
            //----------------------------------------------------------------------
            public function encodeJPG($intext, $outfile = false,$saveandprint=false) 
            {
                try {
                
                    ob_start();
                    $tab = $this->encode($intext);
                    $err = ob_get_contents();
                    ob_end_clean();
                    
                    if ($err != '')
                        QRtools::log($outfile, $err);
                    
                    $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
                    
                    QRimage::jpg($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
                
                } catch (Exception $e) {
                
                    QRtools::log($outfile, $e->getMessage());
                
                }
            }
        }
    

    qrimage.php

    <?php
    /*
     * PHP QR Code encoder
     *
     * Image output of code using GD2
     *
     * PHP QR Code is distributed under LGPL 3
     * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 3 of the License, or any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
     */
    
        define('QR_IMAGE', true);
        class QRimage {
        
            //----------------------------------------------------------------------
            public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE) 
            {
                $image = self::image($frame, $pixelPerPoint, $outerFrame);
                
                if ($filename === false) {
                    Header("Content-type: image/png");
                    ImagePng($image);
                } else {
                    if($saveandprint===TRUE){
                        ImagePng($image, $filename);
                        header("Content-type: image/png");
                        ImagePng($image);
                    }else{
                        ImagePng($image, $filename);
                    }
                }
                
                ImageDestroy($image);
            }
            //----------------------------------------------------------------------
            public static function jpg($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4,$saveandprint=FALSE) 
            {
                $image = self::image($frame, $pixelPerPoint, $outerFrame);
                
                if ($filename === false) {
                    Header("Content-type: image/jpeg");
                    ImageJpeg($image);
                } else {
                    if($saveandprint===TRUE){
                        ImageJpeg($image, $filename, 100);
                        header("Content-type: image/jpeg");
                        ImageJpeg($image, NULL, 100);
                    }else{
                        ImageJpeg($image, $filename, 100);
                    }
                }
                
                ImageDestroy($image);
            }
    
            //----------------------------------------------------------------------
            public static function svg($frame, $filename = false, $outerFrame = 4)
            {
                $file = self::imageSVG($frame, $outerFrame);
                if ($filename !== false) {
                    $fhandle = fopen($filename,'w+');
                    fwrite($fhandle, $file);
                    fclose($fhandle);
                }
                unset($file);
            }
            //----------------------------------------------------------------------
            private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4) 
            {
                $h = count($frame);
                $w = strlen($frame[0]);
                
                $imgW = $w + 2*$outerFrame;
                $imgH = $h + 2*$outerFrame;
                
                $base_image =ImageCreateTrueColor($imgW, $imgH);
                
                $col[0] = ImageColorAllocate($base_image,255,255,255);
                $col[1] = ImageColorAllocate($base_image,0,0,0);
                imagefill($base_image, 0, 0, $col[0]);
                for($y=0; $y<$h; $y++) {
                    for($x=0; $x<$w; $x++) {
                        if ($frame[$y][$x] == '1') {
                            ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]); 
                        }
                    }
                }
                
                $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
                ImageCopyResampled($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
                ImageDestroy($base_image);
                
                return $target_image;
            }
            //----------------------------------------------------------------------
            private static function imageSVG($frame, $outerFrame = 4)
            {
                $h = count($frame);
                $w = strlen($frame[0]);
                
                $imgW = $w + 2*$outerFrame;
                $imgH = $h + 2*$outerFrame;
                $eps_string = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\r
        <rect x=\"0\" y=\"0\" width=\"".$imgW."\" height=\"".$imgH."\" style=\"fill:white\"/>\r";
                for($y=0; $y<$h; $y++) {
                    for($x=0; $x<$w; $x++) {
                        if ($frame[$y][$x] == '1') {
                            $eps_string .= "    <rect x=\"".($x+$outerFrame)."\" y=\"".($y+$outerFrame)."\" width=\"1\" height=\"1\" style=\"fill:black\"/>\r";
                        }
                    }
                }
                $eps_string .= "</svg>";
                return $eps_string;
            }
        }
    

    Now you can generate SVG and JPG formatted QR Codes with:
    QRcode::svg($_REQUEST, $filename, $errorCorrectionLevel, 2);
    QRcode::jpg($_REQUEST, $filename, $errorCorrectionLevel, $matrixPointSize, 2);

    I hope this is helpfull…

     
  • Anonymous

    Anonymous - 2011-11-26

    I tried this and it created the JPG ok, but when I used it to craete an SVG, the file was created but when I try to open it in various programs, I get errors saying it is an invalid format.

    Any ideas what could be wrong?

     
  • Anonymous

    Anonymous - 2012-03-28

    There's an error in the imageSVG method in the QRImage class in qrimage.php

    In the SVG's XML the root element is created like so:

    <svg xmlns="http://www.w3.org/2000/svg"; version="1.1">
    

    The semicolon after the xmlns attribute 'breaks' the SVG image.

    Replace the line:

    $eps_string = "<svg xmlns=\"http://www.w3.org/2000/svg\"; version=\"1.1\">\r <rect x=\"0\" y=\"0\" width=\"".$imgW."\" height=\"".$imgH."\" style=\"fill:white\"/>\r";
    

    With this:

    $eps_string = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\r <rect x=\"0\" y=\"0\" width=\"".$imgW."\" height=\"".$imgH."\" style=\"fill:white\"/>\r";
    

    Now the SVG image works (althoug small, but works).

     
  • Anonymous

    Anonymous - 2012-03-28

    Uhm, I see the problem is with the code tag on this site… :/
    Well, the problem is the semicolon in the XML root element - I hope you see the point…

     
  • Culero Connor

    Culero Connor - 2012-10-18

    @repox82 Can you just give me the ready-made version?
    I used to be good at CFML but recently I moved to PHP and I'm kinda a newbie here… I gave a try to "fixing" the code by myself based on your comments but just cannot make it work!
    Would you help a college in need?

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.