Re: Image handling advice needed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



William Stokes wrote:
Hello,

I need to build an image 'library'. The library will consist mostly of images taken with digital cameras. Since unedited digicam pics will most likely be too big for web usage they need to be edited automatically so that they can be put to a web page.

I'am trying to deside between two options. To resize (=scale down) the images once they are uploaded to server and store the smaller file or upload and store the original BIG file and scale it to thumbnail once it's viewed. Any opinnions about this.

I think that if the disk space is not an issue I could upload the original file. But are there performance issues if the thumbnails are created "on the fly" if there are hundreds of pics?

Will - do a bit of both.

upload and store the original in fullsize (and _without_ any compression or whatever).
then have a script (or set of them, depending or your needs) that doesn't just blindly
resample a requested image according some given criteria (set in either the script or
the from the request) but first check it's 'own' cache for previously resampled files ...
if it finds a valid file in 'its cache' then just spit it out; otherwise generate the
requested image file (manipulating/resampling however you like) and save it to the cache
(most likely to disk) and also output the image data.

this effectively gives you one time resampling with some added bonuses:

1. when the underlying extension (e.g. GDlib) is upgraded you can clear your image
cache and have all your images regenerated automatically using the improved routines
(e.g. crisper resamping)

2. when the client wants all the images on the site to be a different
tint/size/ratio/format/etc you can change you image generation scripts, clear the image
cache and bingo - 'fixed' images.


below is a class I use to store images I cache in the manner I described above.
using it is quite simple [if you don't want it to use values of named REQUEST args
as the basis of the unique cache identifier (i.e. the filename) then you'll have
to do some hacking]:

// create the object
$ic = ImageCache('/dev/shm/site-image-cache'); // read up on /dev/shm !!!

// set out an array of REQUEST arguments. e.g. imagine the following url
// "./showimg.php?id=12345&size=big"  - how you use the actual REQUEST argument values
// to generate an non-existant image is up to you.
$cacheArgs = array('size', 'id')

// use the image cacher to determine the generated name of the cached image file.
$ic->genCacheFileName( $cacheArgs, 'jpeg', 'some-prefix' );

// determine a set of files with which to check the file modification
// time against (at least 1 is required)
$files = array('/path/to/your/original/image/file.jpg');

// check the cache
if (!$ic->checkCache($files)) {
	// do some stuff to create an image
	// use the value from $ic->getCacheFilePath()
	// as the path+filename under which to store the
	// new image
}


// show cache image.
$ic->showImage();

<?php

class ImageCache
{
    var $validTypes = array('png','gif','jpeg');

    var $cacheFileName;
    var $cacheFileType;
    var $cacheDir;
    var $dirSep;

    var $im;

    /* you must give a valid 'cache' dir AND you must have already generated
     * a cache file name for the file we want to cache (may have already been cached)
     *
     * in effect you must always call ImageCache::genCacheFileName() before calling this function.
     */
    function ImageCache($cDir)
    {
        $this->cacheDir         = $cDir;
        $this->dirSep           = defined('DIR_SEP') ? DIR_SEP: '/';

        // just to be safe we define this if it does not exist.
        if (!defined('WEBROOT')) {
            define('WEBROOT', realpath($_SERVER['DOCUMENT_ROOT']));
        }
    }

    function genCacheFileName( $args = array(), $type = '', $prefix = '' )
    {
        /* name/val pair delimiter in the string that results in the hash for the cache id */
        $qHashMark = '%~^*';

        $args = (array)$args; natsort($args);
        $qry  = array();
        foreach ($args as $arg) {
            if (($val = $this->getR( $arg, false )) !== false) {
                $qry[] = "{$arg}=".str_replace($qHashMark,'',$val);
            }
        }

        //var_dump(WEBROOT . $_SERVER['PHP_SELF'] .'-:-'. join($qHashMark, $qry));
        $hash = md5(WEBROOT . $_SERVER['PHP_SELF'] .'-:-'. join($qHashMark, $qry));

        if (!in_array($type, $this->validTypes)) {
            if ($type == 'jpg') {
                $type = 'jpeg';
            } else {
                $type = 'png';
            }
        }

        $this->cacheFileType = $type;

        if (!$prefix) {
            $prefix = 'cacheimg';
        }

        return ($this->cacheFileName = "{$prefix}_{$hash}.{$type}");
    }

    function getCacheFilePath()
    {
        return $this->cacheDir . $this->dirSep . $this->cacheFileName;
    }

    /* Return true if the cache file is younger than the source file(s),
     * false otherwise.
     *
     * the (array of) files passed to this function should be complete paths,
     * not just filesnames.
     */
    function checkCache( $files = array() )
    {
        $cacheState = true;

        $cf           = $this->getCacheFilePath();
        $mTime        = is_readable($cf) ? filemtime($cf): 0;
        $lastModified = gmdate("D, d M Y H:i:s ", $mTime)."GMT";
        $files        = (array) $files;

        if (!count($files) || !$mTime) {
            $cacheState = false;
        } else {
            foreach($files as $file) {
                if ($mTime < filemtime( $file )) {
                    $cacheState = false;
                    break;
                }
            }
        }


        if ($cacheState) {
            $headers = getallheaders();
            if (isset($headers['If-Modified-Since']) && ($headers['If-Modified-Since'] == $lastModified)) {
                /* The UA has the exact same image we have. */
                header("HTTP/1.1 304 Not Modified");
                exit;
            } else {
                unset($headers);
                header("Last-Modified: ".$lastModified);
                return true;
            }
        } else {
            // not cached - or cache invalidated
            // must cache the (new) data.
            header("Last-Modified: ".$lastModified);
            return false;
        }
    }

    function showImage($type = '', $quality = 100)
    {
        header( "Content-type: image/{$this->cacheFileType}" );
        readfile( $this->getCacheFilePath() );
        exit;
    }

    /* helper function - saves typing - added to the class to make it selfcontained for this example */
    function getR($v = '', $r = null, $t = null)
    {
        if (!empty($v)) { if (isset($_REQUEST[$v])) {$r=!is_null($t)?$t:$_REQUEST[$v];} }
        return $r;
    }
}


Thanks for your advice
-Will


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux