Optimize images

322 views
Skip to first unread message

Kevin Ingwersen (Ingwie Phoenix)

unread,
Jan 14, 2015, 10:28:44 PM1/14/15
to nod...@googlegroups.com
Hey everyone.

I am currently working on reducing the amount of data sent from my connect based HTTP server to my client. So far I am very proud that 9/10 of my site is cache-able, plus some PHP pages (used trough a fast-cgi connection) being able to re-cache themselves if possible. This means that on average, only 3.3KB is transfered - at all. However, if I open an image which is stored in the database and read it to the client, it turns into a 200KB transmission. Ouch! Now imagine there were 20 due to a user listing…I guess you get where I am going.

For now I am using the compression Connect/Express middleware. Compression is really, really neat. But it would be great if I could teach it to compress images too! It works flawlessly with my PHP binding, which means that I can just write my Yii stuff and don’t have to worry about the compressing stuff; its done int he server for me.

But images… x.x

What good and easy-to-use tools are out there to optimize images?
Is there one that „rules them all“ - as in, one that can handle multiple image formats?

Would be great to know!

Kind regards, Ingwie

Sindre Sorhus

unread,
Jan 15, 2015, 9:20:45 AM1/15/15
to nod...@googlegroups.com

You really shouldn't use this on the fly though. Minifying images can be a very slow process.

Ryan Schmidt

unread,
Jan 15, 2015, 9:23:44 AM1/15/15
to nod...@googlegroups.com

On Jan 14, 2015, at 5:56 PM, Kevin Ingwersen wrote:

> For now I am using the compression Connect/Express middleware. Compression is really, really neat. But it would be great if I could teach it to compress images too! It works flawlessly with my PHP binding, which means that I can just write my Yii stuff and don’t have to worry about the compressing stuff; its done int he server for me.
>
> But images… x.x
>
> What good and easy-to-use tools are out there to optimize images?
> Is there one that „rules them all“ - as in, one that can handle multiple image formats?

Unless your images are being generated dynamically, you'll want to compress your images once when you save them, not every time you send them.

optipng and pngcrush are popular programs for minimizing the size of pngs.

Kevin Ingwersen (Ingwie Phoenix)

unread,
Jan 15, 2015, 10:47:55 AM1/15/15
to nod...@googlegroups.com
Thanks for both your replies!

In the end I went with imagemin. its very easy to use and is easily put into a middleware.

You may have to change this around and about, but here is how I implemented a caching, minifying middleware:

CDN.use("/cdn", function(req, res, next){
var fname = path.basename(req.url);
var ext = path.extname(fname);
if(ext.substr(1).match(/^(png|jpg|jpeg|gif|svg)$/i)) {
var infile = config.base+"/cdn/"+url.parse(req.url).pathname;
if(
typeof req.headers["if-none-match"] != "undefined"
&& req.headers["if-none-match"]==md5_file(infile)
) {
log.info("Its cached.");
res.statusCode = 304;
return res.end();
}
var dirname = path.dirname(req.url);
mkdirp(config.base+"/cache/cdn/"+dirname, function(err){
if(err) {
console.log("Error",err);
return next();
}
var cacheDir = config.base+"/cache/";
var outdir = config.base+"/cache/cdn/"+path.dirname(req.url);
var outname = md5_file(infile)+"-"+path.basename(infile);
var outfile = path.join(outdir, outname);
var extName = ext.substr(1);
fs.exists(outfile, function(exists){
// One way or another, we're sending something here, so set headers.
var age = 30*24*60*60;
var time = Date.now();
var d = new Date(Date.now() + age*1000);
res.setHeader("Etag", md5_file(infile)); // Outfile wont exist, but we can cheat. :)
res.setHeader("Cache-control", "public, max-age="+age);
res.setHeader("Expires", d.toUTCString());
if(!exists) {
log.info("BIRD3 CDN -> Generating: ",outfile);
var imagemin = new Imagemin()
.src(infile)
.use(Imagemin.jpegtran({ progressive: true }))
.use(Imagemin.gifsicle())
.use(Imagemin.optipng())
.use(Imagemin.pngquant())
.use(Imagemin.svgo());
imagemin.run(function(err, files, stream){
if(err) {
log.error("Imagemin error");
log.error(err);
return next();
}
fs.writeFile(outfile, files[0].contents, function(err){
if(err) {
log.error("Can not write optimized image: "+outfile);
console.error(err);
}
res.setHeader("Content-type", mime.types[extName]);
res.end(files[0].contents);
return;
});
});
} else {
log.info("BIRD3 CDN -> Sending generated: "+outfile);
fs.readFile(outfile, function(err, output){
if(err) {
log.error(err);
return next();
}
res.setHeader("Content-type", mime.types[extName]);
res.end(output);
return;
});
}
});
});
} else return next();
});

This is straight from my code. Feel free to replace parts and reuse, or make a module, or whatever. But I think this is quite a neat thing to have. Because if your images change, then this also will regenerate the images. Otherwise, it tells your browser that the image should be cached as well and should save you some reads.

Kind regards, Ingwie

PS. If you have advice on optimizing this thing, i’d be happy to hear about it. :)

Ryan Schmidt

unread,
Jan 15, 2015, 3:52:10 PM1/15/15
to nod...@googlegroups.com

On Jan 15, 2015, at 1:02 AM, Ryan Schmidt wrote:

> optipng and pngcrush are popular programs for minimizing the size of pngs.

Also, consider whether using a different image format would help. png and jpeg are somewhat old formats by now. Newer formats include webp and bpg:

https://developers.google.com/speed/webp/

http://bellard.org/bpg/

Browser support for these formats isn't as good as png and jpeg, but if you can serve webp or bpg images to those users whose browsers support them, and fall back to png or jpeg when needed, that can still help you reduce your bandwidth and make your site faster for some users, and it will get better over time as more users upgrade to newer browsers.


Kevin Ingwersen (Ingwie Phoenix)

unread,
Jan 15, 2015, 4:11:07 PM1/15/15
to nod...@googlegroups.com
I was thinking of implementing this hybrid. There is a webp middleware that actually figures out if the browser supports it or not and delivers a converted image accordingly. That’d actually work - but is there such a middleware for BPG?
> --
> Job board: http://jobs.nodejs.org/
> New group rules: https://gist.github.com/othiym23/9886289#file-moderation-policy-md
> Old group rules: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
> ---
> You received this message because you are subscribed to the Google Groups "nodejs" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to nodejs+un...@googlegroups.com.
> To post to this group, send email to nod...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/nodejs/3DA85868-C3E8-4D31-AB32-A06F4F4F56C6%40ryandesign.com.
> For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages