When you should use base64 for images

Base64 and image files

For those who don’t know base64 it’s an encoding format for any data. In that case with the images we can simply say, that base64 equals to text (string) representation of the image itself. In most cases you’ve image tags with src attribute pointing to the http source of the image.

Overview of the problem

Let’s say we’ve a HTML document with 100 images into. That’s a rare case I agree, but sometimes it happens. You’ve to preload the thumbnails of an image gallery where only one image is displayed in a bigger size. As I mentioned before the progressive JPEG suits better for a large image but for the thumbnails you’ve to use baseline JPEGs.

Note: In fact the technique with base64 representation of the images is not well known. I think that’s because there are not so much examples with pages with more than 100 images.

But anyway. We’ve the HTML document with 100 images (100 <img> tags). That means directly 101 requests/responses from the server. In my tests on my localhost, which is supposed to be fast enough, that case loaded 2 MB with a simple small JPEG for the image, loaded 100 times, and approximately 3 seconds. Which yet again on the localhost is extreamly slow. The image is on my machine, the server is here… what else?

How to put the images inline?

The other way to do that is to put all you images in you HTML document. Than the first and more important rule for optimization (see more here), to make fewer requests is done. You now have only one request. And with the response you’ve all 100 images. That’s good when you’ve different images, cause every repeatable element in your CSS should be made with HTTP request once and than repeated with the CSS. In other way you risk the size of the document transfered in the web.

The results

The second case with the inline images and the only one request is giving me an average response time of 900ms. The size of the document is bigger, yes. I had 5KB for the HTML with no base64 images, and then the size increased to 45KB. That’s 9 times more. But however 45KB is nothing for the web, instead of all those 2 MB in the previous test.

How to make your images to strings?

Speaking in PHP terminology there is a function called base64_encode, which with a combination of file_get_contents(imagefile), make the files a base64 string.

Is there any issue?

Yes there is. First you cannot have your image files in a remote server, cause file_get_contents must read only from the local filesystem. Than if you process all those files before returning them to the client, where’s the point? You lose all that time you’ve spent with the technique.

The reasonable solution

I think this technique is good for cases like the one described at the beggining. You’ve a page with more than 100 images. Then you’ve the base64 representation already. Let say you have it in your database as string and don’t need to convert it everytime you return the image. That may happen on upload of the image and the image enters the database with its base64 representation, and it’s done.

30 thoughts on “When you should use base64 for images

  1. Sounds strange! isn’t it, you cannot have the html response smaller than the http (multiple) responses of the images. This is really strange to me, I doubt the tests you ran.

  2. I face a similar problem. I uploaded a document with multiple images. This document is sent back to the server for processing using an Ajax call.

    I have used Base64 for compressing the uploaded document.

    Issue: The document size becomes too bulky after Base64 compression & hence fails when the document is fetched.

    Any thoughts on this pls.

    regards,
    Satish

  3. Well here I used it to “download” the document from the web. On a particular request. So maybe the document becomes too big to be sent on the server. You should check the availability to upload via HTTP such large documents. If not you’d try something like FTP or whatever?

    greetings

  4. if we save the base64 data into database, I think the database will be down, because the database is used to store other big data. What will happen after 5 or 10 years?
    I’ve tried to save it into a text file, but after read it from the text file, it’s not working….

    Regards,
    Rithy

  5. Hi,

    actually it doesn’t matter whether you store the images into a file system or in the database as base64. What will happen with your servers after 10 years storing all those images there? Probably the answer is there will be more and more servers. Well the situation with base64 is the same. The database will become larger and larger, but yet again there’s a solution with clusters and/or more db server, right?

    If it’s not working from a text file, that should be some other error, because base64 is just a string. Check for junk data into the text file.

    greetings

  6. Hi,

    I’m not sure about the server, currently I have only 1 server and I am not sure how to work with 2 or more databases or servers…

    Thanks you. I got it work now. I found that after php wrote the base64 string in a text file, the ‘+’ sign is gone.

    But I’ve decided to store as normal image, I’ll encode the normal image into base64 when php load the page.
    Because it could be 2 options which can use base64 or normal image and in ie6 doesn’t support base64 image.

    But I’m not sure server will use how much cpu to encode the image…
    I’m considering about the usage of upc and ram of the server.

    Regards,
    Rithy

  7. Hi Rithy,

    you definitely have to run some tests to be sure which operation is faster. Using base64 is good for small images and multiple requests, i.e. 100 images each 2KB big. Than you’ve so much requests that even with very small images slows down the page.

    When you’ve to store images bigger than a “thumb” size it may be not a good idea. For “wallpaper” size images it’s good to store them as progressive JPGs.

    In your case maybe the converting process from image file -> base64 -> http response may not be the best solution.

    My advice is to run test with different scenarios that will answer all your questions.

    all the best,
    stoimen

  8. Hi stoimen,

    Thank you a lot for your reply and advice!

    My image is about 3kb. So I could use it.

    Cheer,
    Rithy

  9. Interesting technique, what about cache proxy server(s) for static resources (like Varnish, Squid) for these 100+ small images? Not only images, but css, js, swf, template files…

    All this about is for webserver calls (100+) which can be optimized with better solutions.

    You already said, with cheap and affordable web technologies, a “shared hosting” is a sad story today, so “i have 1 server without ssh and php.ini and without…” is not for ma’n'pa-3-pages website anymore.

    My 2 cents.

  10. @Kodeart – it all depends on the specific case. It isn’t a bad idea to store static content on CDN, which in some cases will be better. However the only way to get all 100 images with one request is with base64, isn’t it?

  11. Oh, boy, this use case is just WRONG.

    The problem is that people are confusing “request” with “connection”. You want to avoid CONNECTIONS, multiple REQUESTS over one connection is very cheap, and commonplace. The one TCP connection per request idiom does not exist in practice thanks to HTTP 1.1.

    100 small images == 3 or less connections on my Apache/Linux server.

    HTTP 1.1 has a “Connection: Keep-Alive” header.
    This is supported by ALL modern browsers (even mobile) and ALL modern servers (IIS, Tomcat, Apache, etc.)

    With Keep-Alive: The browser and server leave the connection open at the “end” of a request. The browser can send additional HTTP 1.1 requests to the server, and the server sends the requested data back over the same single connection.

    With static content this translates to Reading all 100 images from disk, and sending them to the client all in one go.

    If one of the 100 images changes ONLY that image will be re-sent, the rest will result in a “No Change” reply.

    Don’t dynamically generate data unless you have to, and when you do generate “dynamic” data make sure to set the caching headers so that multiple requests for the same “dynamic” content don’t require a full request / database lookup / transmission.

    Base64 encoding should NOT be used to fix a “too many connections” issue, see your server configuration for that.

    The “too many requests” issue is a misnomer since all modern servers & browsers allow multiple requests over one connection, and the requests are VERY cheap.

    Base64 encoding multiple images into one CSS file is a benefit only when the image data is smaller than an HTTP Request header (mostly never). Base64 it’s a 3 to 4 increase of data size, and is only worth using when the base 64 encoded data is smaller than the HTTP Header (very small images < 8×8).

    Even this is a silly way do do things. Lets say I have 100 very small images, I can paste them all into ONE big image, and serve up "palette.png" as a single static image.
    To get at the individual images just use CSS.

    #my_icon {
    display: inline-block;
    backgroundImage: url("palette.png");
    width: 16px; height: 16px;
    backgroundPosition: -48px -160px;
    }
    #my_icon2{
    /* same as above, with different bkg Pos */
    }
    ——

    Works in ALL modern browsers & is more efficient than B64.

    Satish is pushing Base64 encoded data to the server using AJAX. Hopefully he’s using the POST method to avoid URL escaping ‘%’ (huge bloat). Even with POST, the B64 encoding is being applied TWICE before upload since browsers automatically encode POST data using base64
    ( this means a 4 to 7 data expansion (almost double) ).

    As others have said: DO NOT PRE-OPTIMIZE. Just develop your site the easiest/fastest way you can, and then run tests to see where it’s ACTUALLY slow. Chances are your server will already be optimized for your “unoptimized” use case.

  12. I prefer to tune my server too. I’ve developed a Lotus Domino portal, accessed by 20.000 persons every day. Users are still using IE6, and I’ve noticed this agent has some problem in managing backgrounds. I’ve lists of links in every page of portal, shown by means of LI tags, and an anchor nested. These anchors have a css class with background setted, to override LI defaults. With empty “temporary internet files” folder (cache), IE6 doesn’t request image file once, but a request for every LI>A in the page. I’ve modified my web server rules to override default expiration; the new expire data is setted, but it doesn’t work in the empty cache scenario. In a section of the portal there are more than 100 of these images and IE6 does more than 100 different requests. I’m using Fiddler proxy to check this out.

    Any suggestion to avoid this overhead?
    Thanks in advance
    K.

  13. How about newsletter? Should I use base64 conversion there? (yes, I know, who reads newsletters anyway).

  14. i have a real estate website where we upload images to web server and save the urls to mysql . would it increase the performance if in summary search results i only show one picture and summary of the house. should i use base64 ? would it increase page performance?

  15. @Yusuf – well it depends on what you want to achieve. If you’d like to overcome slow server responses and make fewer requests then you’ve to choose base64. However if the web server is quite fast and it isn’t loaded, it’s better to forget about base64.

    For sure you’ve to make some tests in order to get the right solution in your case. Again – base64 is great if you like to overcome server requests.

  16. i have a problem to decode the imagestring and then create the image.

    It always show problem:
    [Mon May 14 16:50:46 2012] [error] [client 192.168.1.2] PHP Notice: imagecreatefromstring(): gd-jpeg, libjpeg: recoverable error: Corrupt JPEG data: 214 extraneous bytes before marker 0×68\n in /var/www/html/config.php on line 22
    [Mon May 14 16:50:46 2012] [error] [client 192.168.1.2] PHP Warning: imagecreatefromstring(): gd-jpeg: JPEG library reports unrecoverable error: in /var/www/html/config.php on line 22
    [Mon May 14 16:50:46 2012] [error] [client 192.168.1.2] PHP Warning: imagecreatefromstring(): Passed data is not in ‘JPEG’ format in /var/www/html/config.php on line 22
    [Mon May 14 16:50:46 2012] [error] [client 192.168.1.2] PHP Warning: imagecreatefromstring(): Couldn’t create GD Image Stream out of Data in /var/www/html/config.php on line 22
    how to solve this..if any know send to my mail…plz….
    thanks for reading.

  17. This feature suits my need. I’ve built an app that let the user captures a picture with a mobile phone and upload it directly to the server. The question is, with method is faster between pulling base64 string from MySQL and link to an image file.

    Thanks

  18. Hi, if I store base64 string in DB, isn’t there an overhead in doing 100 reads from DB compared to reading them directly?
    What would you say about using memcach in that case? Meaning you cache the returned string so most calls won’t reach the DB level.

  19. Hi Dror,

    what do you mean by “reading them directly”? Reading from the DB and the filesystem is practically the same approach, but sometimes reading from the DB is faster. Memcache is only a way you can cache filesystem items in memory, so it doesn’t matter which DB/Filesystem you chose. However note that base64 is slightly more heavyier than appropriate image format.

  20. Hi Stoimen,
    I thought that when I’m having a dense calls to the db , memcache could help in not going all the way to the db level but fetching the information from memory , so if I store images as base64 at db and using memcache , I would practically wont go to db but read the binary and serve it very fast … is that so ?

  21. Hi Dror,

    yes, no matter what’s your storage (db or filesystem), representing the images as base64 strings in memcache can dramatically improve the speed of fetching them by the application. But memcache is only a caching layer and if you have lots of images you’ve to store them somewhere – you can just push them all in the memcache (if there are too much).

  22. Was going to just state file_get_contents() can do get remote images.
    Now I’ll just second what “cereal” already stated,,,,,,

    Selvol

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>