Viewed   77 times

Is there anything out there in the PHP world with equivalent functionality to SORL thumbnail (a Django project).

Specifically: 1) It caches results (generating thumbnails on the fly is too cpu intensive). 2) It provides a smart cropping feature that crops to fit based on image entropy (so it doesn't just crop to center, but rather crops where the 'action' is).

The big feature I'm looking for is the smart cropping ability.

 Answers

4

I found a drupal module from which I can lift some php code:

http://github.com/dylantack/codename_cornbaby

It's actually based on the same django-sorl-thumbnail approach cited, so that's perfect.

Monday, August 8, 2022
 
5

If all you've tried is GD, you might want to give some of the ImageMagick sampling filters a shot. Here's a page that examines them along with the PhotoShop ones:

http://www.xs4all.nl/~bvdwolf/main/foto/down_sample/down_sample.htm

Monday, October 17, 2022
 
torak
 
5

Add this next to the require:

use LeagueFlysystemAdapterLocal;
use LeagueFlysystemFilesystem;
use LeagueGlideServerFactory;

Like this:

<?

require '../vendor/autoload.php';

use LeagueFlysystemAdapterLocal;
use LeagueFlysystemFilesystem;
use LeagueGlideServerFactory;

// Setup Glide server
$server = LeagueGlideServerFactory::create([
    'source' => '../assets/img/source',
    'cache' => '../assets/img/cache',
]);

// You could manually pass in the image path and manipulations options
$server->outputImage('01.jpg', ['w' => 300, 'h' => 400]);
Tuesday, August 2, 2022
 
zored
 
2

Wrote a tutorial about this a while ago. Perhaps it can help. It starts with uploading, but most of it is about resizing. Just swap out the usage of the $_FILES array by geting the image type and file name a different way. Here's the code you should need:

// Create image from file
switch(strtolower($_FILES['image']['type']))
{
     case 'image/jpeg':
         $image = imagecreatefromjpeg($_FILES['image']['tmp_name']);
         break;
     case 'image/png':
         $image = imagecreatefrompng($_FILES['image']['tmp_name']);
         break;
     case 'image/gif':
         $image = imagecreatefromgif($_FILES['image']['tmp_name']);
         break;
     default:
         exit('Unsupported type: '.$_FILES['image']['type']);
}

// Target dimensions
$max_width = 240;
$max_height = 180;

// Get current dimensions
$old_width  = imagesx($image);
$old_height = imagesy($image);

// Calculate the scaling we need to do to fit the image inside our frame
$scale      = min($max_width/$old_width, $max_height/$old_height);

// Get the new dimensions
$new_width  = ceil($scale*$old_width);
$new_height = ceil($scale*$old_height);

// Create new empty image
$new = imagecreatetruecolor($new_width, $new_height);

// Resize old image into new
imagecopyresampled($new, $image, 
     0, 0, 0, 0, 
     $new_width, $new_height, $old_width, $old_height);

// Catch the imagedata
ob_start();
imagejpeg($new, NULL, 90);
$data = ob_get_clean();

// Destroy resources
imagedestroy($image);
imagedestroy($new);

// Set new content-type and status code
header("Content-type: image/jpeg", true, 200);

// Output data
echo $data;

If you want to store the image as a file rather than dumping it to the browser, remove the head and echo part at the end and then swap out the NULL parameter in the imagejpeg call with an actual filename. Hope that helps :)

Here's the code in use: http://samples.geekality.net/image-resize/

Monday, September 26, 2022
2

If you have trouble with image resizing use this code for it. Do the modifications as you need it.

function resizeImage($file){

         define ('MAX_WIDTH', 1500);//max image width               
         define ('MAX_HEIGHT', 1500);//max image height 
         define ('MAX_FILE_SIZE', 10485760);

         //iamge save path
         $path = 'storeResize/';  

        //size of the resize image 
         $new_width = 128; 
         $new_height = 128;    

        //name of the new image           
        $nameOfFile = 'resize_'.$new_width.'x'.$new_height.'_'.basename($file['name']);       

        $image_type = $file['type'];
        $image_size = $file['size'];
        $image_error = $file['error'];
        $image_file = $file['tmp_name'];
        $image_name = $file['name'];        

        $image_info = getimagesize($image_file);

        //check image type 
        if ($image_info['mime'] == 'image/jpeg' or $image_info['mime'] == 'image/jpg'){    
        }
        else if ($image_info['mime'] == 'image/png'){    
        }
        else if ($image_info['mime'] == 'image/gif'){    
        }
        else{            
            //set error invalid file type
        }

        if ($image_error){
            //set error image upload error
        }

        if ( $image_size > MAX_FILE_SIZE ){
            //set error image size invalid
        }

        switch ($image_info['mime']) {
            case 'image/jpg': //This isn't a valid mime type so we should probably remove it
            case 'image/jpeg':
            $image = imagecreatefromjpeg ($image_file);
            break;
            case 'image/png':
            $image = imagecreatefrompng ($image_file);
            break;
            case 'image/gif':
            $image = imagecreatefromgif ($image_file);
            break;
        }    

        if ($new_width == 0 && $new_height == 0) {
            $new_width = 100;
            $new_height = 100;
        }

        // ensure size limits can not be abused
        $new_width = min ($new_width, MAX_WIDTH);
        $new_height = min ($new_height, MAX_HEIGHT);

        //get original image h/w
        $width = imagesx ($image);
        $height = imagesy ($image);

        //$align = 'b';
        $zoom_crop = 1;
        $origin_x = 0;
        $origin_y = 0;
        //TODO setting Memory

        // generate new w/h if not provided
        if ($new_width && !$new_height) {
            $new_height = floor ($height * ($new_width / $width));
        } else if ($new_height && !$new_width) {
            $new_width = floor ($width * ($new_height / $height));
        }

        // scale down and add borders
    if ($zoom_crop == 3) {

         $final_height = $height * ($new_width / $width);

         if ($final_height > $new_height) {
            $new_width = $width * ($new_height / $height);
         } else {
            $new_height = $final_height;
         }

    }

        // create a new true color image
        $canvas = imagecreatetruecolor ($new_width, $new_height);
        imagealphablending ($canvas, false);


        if (strlen ($canvas_color) < 6) {
            $canvas_color = 'ffffff';       
        }

        $canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
        $canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
        $canvas_color_B = hexdec (substr ($canvas_color, 2, 2));

        // Create a new transparent color for image
        $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);

        // Completely fill the background of the new image with allocated color.
        imagefill ($canvas, 0, 0, $color);

        // scale down and add borders
    if ($zoom_crop == 2) {

            $final_height = $height * ($new_width / $width);

        if ($final_height > $new_height) {
            $origin_x = $new_width / 2;
            $new_width = $width * ($new_height / $height);
            $origin_x = round ($origin_x - ($new_width / 2));
            } else {

            $origin_y = $new_height / 2;
            $new_height = $final_height;
            $origin_y = round ($origin_y - ($new_height / 2));

        }

    }

        // Restore transparency blending
        imagesavealpha ($canvas, true);

        if ($zoom_crop > 0) {

            $src_x = $src_y = 0;
            $src_w = $width;
            $src_h = $height;

            $cmp_x = $width / $new_width;
            $cmp_y = $height / $new_height;

            // calculate x or y coordinate and width or height of source
            if ($cmp_x > $cmp_y) {
        $src_w = round ($width / $cmp_x * $cmp_y);
        $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
            } else if ($cmp_y > $cmp_x) {
        $src_h = round ($height / $cmp_y * $cmp_x);
        $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
            }

            // positional cropping!
        if ($align) {
            if (strpos ($align, 't') !== false) {
                $src_y = 0;
            }
                        if (strpos ($align, 'b') !== false) {
                                $src_y = $height - $src_h;
                        }
                        if (strpos ($align, 'l') !== false) {
                $src_x = 0;
            }
            if (strpos ($align, 'r') !== false) {
                $src_x = $width - $src_w;
            }
        }

            // positional cropping!
            imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);

         } else {       
        imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
    }
        //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
        if ( (IMAGETYPE_PNG == $image_info[2] || IMAGETYPE_GIF == $image_info[2]) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){
            imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );
    }
        $quality = 100;            
        $nameOfFile = 'resize_'.$new_width.'x'.$new_height.'_'.basename($file['name']);       

    if (preg_match('/^image/(?:jpg|jpeg)$/i', $image_info['mime'])){                       
        imagejpeg($canvas, $path.$nameOfFile, $quality);  

    } else if (preg_match('/^image/png$/i', $image_info['mime'])){                         
        imagepng($canvas, $path.$nameOfFile, floor($quality * 0.09)); 

    } else if (preg_match('/^image/gif$/i', $image_info['mime'])){               
        imagegif($canvas, $path.$nameOfFile); 

    }
}
Tuesday, October 18, 2022
3

Answering my own question

I spent two days digging through Node.js graphics libraries.

node-canvas

  • I tried it first since I'm quite familiar with <canvas> API. It's a huge plus for a library.
  • it requires Cairo which doesn't have an easy Windows download. I found it in GTK+ distribution though.
  • moreover it needs native library binding code to be compiled on module installation. It uses Node-Waf which hasn't being ported to Windows yet.

gm

  • mature
  • runs on Windows smoothly
  • docs are ok but not thorough: I had to look up into source code to figure out what API is available
  • unfortunately there's no easy way to combine images with gm. Maybe there's some way to achieve that but I haven't found one after two hours spent with it.

node-imagemagick

  • The official repo has very few basic ImageMagick commands covered but I used this fork (good thing that NPM can pull libraries directly from git repositories). It has bindings for montage which does exactly what I need.
  • ImageMagick is quite slow, though it works on Windows.

Node-Vips

  • Huge plus: it uses an incredible VIPS library which I'm familiar with. VIPS is very fast and optimized for large images. It's very smart about utilizing hardware resources: if your machine has a lot of RAM it'll do all processing in memory but will switch to hard-drive caches if memory is scarce or required for other applications.
  • same as node-canvas it requires Node-Waf so it's not available for Windows yet.

I also looked at other libraries from the list but most of them are either very immature or do not suit my use case. I would really like to try migrating to either Node-Canvas or Node-Vips when Node-Waf gets ported to Windows but until then I'll stick to node-imagemagick.

Wednesday, December 21, 2022
 
jgreen
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :