How to cache Imagick images?

KittHaven

New member
Hello! I'd like to cache images generated on my site with Imagick but I'm unsure how. I've never really worked with caching before lol. Currently loading times on the owned adoptables page is like 10~ seconds for 7 pets... which isn't ideal. The images are currently quite large though as I'm not bothered by the look of the page just yet so just have the images printing out.

I have tried to put the below into my .htaccess file but it won't affect my Imagick images. I'm not sure if that's because the images don't have a png extension on them or what. Or do I need to wrap the generation in something to check if it's cached...? (When you go to the URL it displays as 'http://127.0.0.1/beanpets/adoptimage/view/3' and adding .png to the end breaks it) So I'm unsure if that would affect it maybe not seeing it as a png? Even though Imagick does set the image format to PNG.

<ifModule mod_headers.c>
# Turn on Expires and set default expires to 3 days
ExpiresActive On
ExpiresDefault A259200

# Set up caching on media files for 1 month
<filesMatch ".(ico|gif|jpg|jpeg|png|flv|pdf|swf|mov|mp3|wmv|ppt)$">
ExpiresDefault A2419200
Header append Cache-Control "public"
</filesMatch>

# Set up 2 Hour caching on commonly updated files
<filesMatch ".(css)$">
ExpiresDefault A7200
Header append Cache-Control "private, must-revalidate"
</filesMatch>

# Force no caching for dynamic files
<filesMatch ".(xml|txt|php|htm|html|js)$">
ExpiresDefault A0
Header set Cache-Control "no-store, no-cache, must-revalidate, max-age=0"
Header set Pragma "no-cache"
</filesMatch>
</ifModule>


I have also tried using:

ExpiresByType image/png A2592000


Neither seem to work. I'm also unsure how to even check if the browser is caching things anyway, and just not caching my Imagick images.

My imagick code, adoptimagecontroller.php (using mysidia framework):

<?php

namespace Controller\Main;
use Resource\Core\AppController;
use Resource\Core\Registry;

class AdoptimageController extends AppController{

public function __construct(){
parent::__construct();
}

public function index(){
$mysidia = Registry::get("mysidia");
}

public function view($aid){
$mysidia = Registry::get("mysidia");
header('Content-type: image/png');

//A not-so-clean way to get the id of the parent page
$fullurl = $_SERVER['REQUEST_URI'];
$scrub = explode('/',trim($fullurl,'/'));
$cleanaid = end($scrub);

$adopt = $mysidia->db->select("owned_adoptables", array(), "aid='$cleanaid'")->fetchObject();

if($adopt->species == "cat_bean"){

if($adopt->currentlevel == 5){
$images = array(
//(Snipped because of length)
);
}
}

// This creates the Imagick class that we will use.
$composed_image = new \Imagick($images);
$clut = new \Imagick();

if($adopt->species == "cat_bean"){
if($adopt->currentlevel == 5){
//(Snipped because of length)
}
}

$image = $composed_image->mergeImageLayers(\Imagick::LAYERMETHOD_FLATTEN);
$image->resizeImage(600,600, \imagick::FILTER_LANCZOS, 1);
$image->setImageFormat('png');

echo $image->getImageBlob();
}
}
?>


Ideally I really want to cache images and not store them, partly for eventual performance, and partly because I couldn't get writing images to work and this is the ideal solution anyway lol.

Thanks for any help! If you need more files then I can provide them.

 
You could try setting the cache headers directly as part of the script where the existing Content-Type header is being set.

Code:
$mysidia = Registry::get("mysidia");
header('Content-type: image/png');

// add these
$cache_for = 2419200; // One month in seconds 
$cache_until = gmdate("D, d M Y H:i:s", time() + $cache_for) . " GMT";
header("Expires: $cache_until");
header("Cache-Control: max-age=$cache_for");
 
Last edited by a moderator:
You could try setting the cache headers directly as part of the script where the existing Content-Type header is being set.

$mysidia = Registry::get("mysidia");
header('Content-type: image/png');

// add these
$cache_for = 2419200; // One month in seconds
$cache_until = gmdate("D, d M Y H:i:s", time() + $cache_for) . " GMT";
header("Expires: $cache_until");
header("Cache-Control: max-age=$cache_for");

Thank you but I couldn't get it working and I'm pretty sure it's because the image gets generated new every time the page loads, it wasn't being stored anywhere. So I kept working at writeimage and managed to get that working, and now can call the image directly from the files. Just working on unlinking and updating the image when it's changed now :3

Though for some reason my if statement isn't working for comparing the last updated and img last updated fields and unlinking if they both don't match... not sure why. I might leave it here in case anyone has an idea, instead of making a new thread.

if($adopt->lastupdate !== $adopt->imglastupdate && file_exists('C:\\wamp64\\www\\beanpets\\images\\adopts\\pets\\' . $adopt->aid . '.png')){
unlink('C:\\wamp64\\www\\beanpets\\images\\adopts\\pets\\' . $adopt->aid . '.png');
}
else{
$mysidia->db->update("owned_adoptables", ["lastupdate" => $timestamp, "imglastupdate" => $timestamp], "aid = '{$adopt->aid}'");
$storepath = 'C:\\wamp64\\www\\beanpets\\images\\adopts\\pets\\' . $adopt->aid . '.png';
$image->writeImage($storepath);
}


image.png

 I can't see any reason why it wouldn't work, but I'm still teaching myself PHP so maybe I'm just overlooking it 😅

 
It sounds like one of the conditions in the if statement might be evaluating to false. Can you try printing the output of each condition individually to see what they evaluate to?

 
It sounds like one of the conditions in the if statement might be evaluating to false. Can you try printing the output of each condition individually to see what they evaluate to?
Thanks, I managed to fix it! You gave me the idea by suggesting to print the output but turns out the code was in the wrong file lol. I was trying to compare the two values in the file that generates the image when really it needs to be done where the image is displayed so if the 2 timestamps don't match it forces the image to regenerate. It's working now! 😄

 
Back
Top