about blog projects contact

The Cogwheel Blog

## Images in Web Development ### Background Processing images for use in web-development is a "knowledge area" I have had to reform into a more coherent thought-process. As a result, I decided to produce a quasi-unified set of principles - cobbled together from notes in my past - to serve as a sort of general reference guide in the field. I am not delving into the specifics of graphic design or hyper-technical specifications of color resolution and the various technologies involved in rendering these. Rather, the idea is to just set down a set of best-practice principles as a reference guide for optimizing images in their use for web pages. To skip the background discussion and go directly to the list of principles, please proceed to the Conclusion: Putting it all together section. ### Some Preliminaries #### Optimization of what? Ostensibly, the challenge which presents itself when working with images for the purposes of web development is a question of *optimization*. Before proceeding any further, it's helpful to establish precisely what it is we're trying to accomplish with the task at hand - in other words, optimization of *what*? For all intents and purposes, I am assuming here that our goal is: #### ***To deliver the best image quality in the most efficient manner possible.*** As is implied by this goal, there is a trade-off involved here. Namely, that trade-off has to do with delivering the best image quality while doing this either as quickly as we possibly can or in a manner which minimizes the size of the transferrable file(s) involved. As load times are highly correlated with file sizes, we can assume these constraints to be one and the same and thus focus our efforts on the constraint that is most easily checked when working from the host machine - the resulting file size. *Note that tools which come bundled with some browsers like Chrome allow* *developers to test load-times under various throttling conditions to better* *approximate page loads under various circumstances. As a result, we can use* *such tools at our disposal once we've addressed the basic challenge of* *maximizing image quality while minimizing file size.* As with optimization functions in general, our goal can be expressed mathematically with use of an objective function and a corresponding constraint to properly formulate the optimization task at hand. <br/> Namely: **Objective:** max(Q) **Constraint** s.t.: s <= k </br> <br> For which 'Q' in our objective function represents image quality which is subject to the constraint that file size (s) must be no larger than a given limit (k). What Q actually is or should be varies with every situation. This is because not only is Q dependent upon the available file format(s) for the image at hand, it also varies with every use-case scenario such as whether the site is meant to be used for print media as opposed to screen/display. Indeed, stated thusly, one might be tempted to think that such variables are easily substituted with desired values from the real-world. This is misleading, however. Since it is not possible to know *a priori* what every use-case scenario will be and thus the determinants of 'Q' image quality or 'k' file size, we are left to reducing our choices to a list of *best practices* for which the 'optimal' approach is a function of available options and the intended use of said image(s). #### Determinants of best practices This leads us to establishing what the parameters are which *determine* the best practices mentioned above which; in turn, inform us of our options to arrive at optimized images for use in web pages. In short order, the determinants of these best practices are: * image file format * image resolution * target viewport size Before delving into how these three determinants interact with each other to mold the requirements backdrop against which images are processed, a *brief* treatment of the notion of compression will help to better gauge what's involved in the task at hand. #### Compression *Compression* is the tool that we have at our disposal to reduce image file sizes so that we may reduce file transfer/load times. In other words the decision to compress or not to compress an image is concerned with the delivery of the image: "*in the most efficient way possible*" part of our optimization goal discussed above. ##### Lossy vs. Lossless Different image file formats exhibit different compression properties and the notion of lossy as opposed to lossless compression is important to understanding the quality of image that is renderable with various file formats. *Lossy* compression refers to the deterioration in image quality when compression is applied to an image. This happens because the compression method supported by the file format involves rendering either approximations to the original image or by allowing some data to be discarded. *Lossless* compression, as might be expected, is a compression approach which avoids the deterioration in image quality because features of the original image are accurately preserved in the resulting compressed version. *Compression Ratio* refers to the ratio of the size of the uncompressed file to that of the compressed file: <div><pre class="code"> Compression Ratio = (Uncompressed Sz) / ( Compressed Sz) </pre></div> and is a shorthand way of comparing the efficacy of various compression techniques. A ratio of 2:1, for example, would imply that the compressed image is one-half (or 50%) of the size of the original uncompressed image, thus introducing a benefit of a 50% size reduction. Bearing in mind that the whole point of compression is to reduce file size, it should be readily apparent that lossy compression techniques can yield much smaller file sizes but only at the cost of a degradation in resulting image quality when compared with lossless compression. With that said, let's have a look at different image file formats and what compression properties each has. ### Image File Formats ##### SVG vs Bitmap/Raster A critical difference between formats which needs to be established is that of the general categories of SVG and Raster images. SVG stands for *Scalable Vector Graphics* and is a graphics format which uses mathematical formulas to draw shapes/images which comprise the overall image. A massive advantage of SVG format files is their scalability. The SVG format was specifically formulated for the Web and as a result SVG images exhibit *no* loss in quality when they are zoomed/resized. Because of its very nature, SVG images are lossless and thus maybe compressed at will. Raster images, on the other hand, are bitmaps composed of a fixed set of pixels. Some raster/bitmap formats support lossless compression while others do not. When enlarged, lossy-compressed bitmap images may well exhibit poor-quality with noticeable pixelation. Despite the drawbacks associated with lossy-compressed bitmap images, issues like the effort required in the vectorization of images, capacity constraints in handling complex color situations, and a historical predilection towards the use of raster images has meant that **bitmap images still dominate** with the SVG format being used mostly in simplified graphics use-case scenarios such as logos and the like. ##### Bitmap/Raster Image Formats As of the time of this writing, the most popular image requests by format according to the [http archive](http://httparchive.org/interesting.php#imageformats) were: * JPG ~45% * PNG ~28% * GIF ~24% * WEBP ~1% * OTHER (TIFF, BMP, etc.) ~1% <br> **JPEG/JPG** - from the acronym Joint Photographic Experts Group, which created the standard. JPGs are perhaps the most popular image file format on the web because they were developed specifically for handling photographs in mind (which, in turn, are a high proportion of all web images). They render images in excellent quality even at very high compression ratios which they do by discarding information in images the eye is least likely to notice. **PNG** - stands for Portable Network Graphics and is a format which was created as an open source alternative to GIF (see below). Unlike GIF files, however, PNG files support more than 256 colors and support transparency. Beyond that, PNG files support lossless compression and thus deliver better quality files at a smaller size than do GIFs. **GIF** - the Graphics Interchange Format is an older format which supports a maximum of 256 colors. As a result of this, recommended use-case scenarios for \*.gif files tend to be those for non-photographic images with broad-sweeping color areas and *not* recommended for images with more complex color schemas such as photographs or highly-detailed illustrations. GIF files may be losslessly compressed but the trade-off is generally a simplistic/low quality image where the advantages to compression are small to begin with. **WEBP** - one of the newer formats introduced by Google to overtake JPG/PNG and designed specifically with more efficient loading of web pages in mind. Both lossy and lossless compression is supported by the WEBP format and it sports better compression ratios than traditional file formats. It is very likely that webp image formats will come to reign in the future as they are far more efficient than their popular JPEG counterparts. That said, not all browsers natively support this type as of this writing. **TIFF** - or the Tagged Image File Format is a flexible format which can support either lossy or lossless compression as the file stores details of its own image storage data. Generally speaking, TIFF serves as the standard for sharing photographs meant for printing and is commonly the format to which photos from cameras in their native RAW format are converted. As a result, usage for most TIFF files tends to be of either not compressed or losslessly compressed, resulting in large file sizes. **BMP** - an old Microsoft format which does not support compression, thus lossless by default. While it had its day as it does render images well, \*.bmp files do not scale well and for these reasons it is rarely (if at all) used on web platforms. My preferential rank-ordering of each format (based purely on my own experience) as broken down by feature is as follows: ***Photographic Source Sets***: TIFF > PNG > JPG The TIFF format by far carries the highest density photo information, being one-step removed from the actual camera RAW files. PNG files *as a source* for photos is superior to JPG as the latter will see quality deteriorate with each save while the PNG remains unchanged. ***Lossless Compression***: TIFF > PNG > BMP > GIF Both TIFF and PNG files offer better lossless compression than either GIF or BMP. Although BMP image quality is arguably better than that of a GIF, it really isnt' supported. GIF is only lossless when it comes to images with no more than 256 colors (so very simple images). ***Lossy Compression***: TIFF > JPG TIFF only comes out first here because of the quality of lossy compression in a TIFF has the potential to approximate lossless but JPGs are superior when compared on a quality/size basis. ***Photo Transparency/Translucency***: PNG > WEBP Both formats offer a transparency effect but PNG is far more widely supported than WEBP which (as of now) still requires plug-ins in some browsers. That said, I expect the WEBP format to grow in dominance in short order. ***Simple Graphics/Icons***: SVG > GIF While both formats are well suited to simplified graphics and even animation, the flexibility of SVG over the older GIF with cruder graphics and color constraints portends that SVG will likely make up a lot of ground against GIFs. ***Photo Use for the Web***: JPG > PNG > TIFF Use-wise, JPGs offer flexible compression settings such that the quality-to- size trade-off can be customized. In just about any case, JPGs will offer the best *quality-for-size* results. PNGs are lossless and thus trivially compressible but generally of smaller size than a TIFF whose quality is bound to be the best of the bunch. (*Note that I am skipping treatment of many other file types such as* *\*.psd and \*.xcf (Adobe Photoshop and GIMP, respectively) and others* *which are specially designed for image processing tasks, in the interest* *of restricting scope to popular web-destined formats.*) ##### Use in Practice All this information is fine and dandy but what does it all boil down to in practice? Given what we've just reviewed, it should be obvious that this answer depends on one's own circumstances including the file options/source sets one has available, for what purpose the images are going to be used, and the like. ***Okay, okay - but what about that 'general' use-case scenario, you say?*** The only way to really address this is identifying use-cases which might not fall under the 'general' category implied here. Special cases of web sites requiring highly-specialized image handling includes scenarios such as the following (among others): * Catalogs for Art Museums/Galleries * Artist portfolios * Photographic forensics Setting such use-cases aside, one might consider a "typical" web application to be a collection of *supporting images* for your text (be that a blog, online store, etc.) rather than the *main focus* of the site. In such use-cases, I would conjecture 99% of the time it all comes down to: <div><pre class="code"> use: SVG for small, simple graphics files like logos use: JPG compressed at desired levels for photographs --[ unless photos: a). must be exact or b). transparent then use: PNG ] use: PNG for small non-photographic complex (256+ colors) graphics images </pre></div> I hasten to point out that this is a very generalized list and does not withstand some of the many possible use-case scenarios referenced above. *(In other words: I realize there are many exceptions to the above so hold* *that hammer where it is)!* ##### Mind the Quality Chain Due to the prevalence of photographs in web imagery, our general practice guidelines above put the JPG out as the centerpiece file format. Being a lossy file format, one thing I can point out without hesitation is that one should always be mindful that quality-wise: <div><pre class="code"> There is no better than the master. </pre> In other words, for lossy formats, any/all descendant images generated after processing can only equal (and will frequently be inferior to) the master in terms of quality. This is particularly true with JPGs where every successive save re-encodes the image which results in an iterated approximation of its former self, thus degrading the quality of the image with subsequent saves. As such, it's always best, when possible, to work from a non-degradable high-quality photo master (such as TIFF or at least a PNG) and to convert to JPEG at the end of the processing. This reminds me of another maxim I've often heard repeated: <div><pre class="code"> Don't sacrifice quality for the sake of speed. </pre></div> The idea is, it defeats the point if your site loads quickly only to render very low-quality images to the end-user. In such cases, either opt for a compromise between speed and quality (preferably by re-working the image in a better way) or choose not to use images at all. ##### File Formats: The Takeaway Given the foregoing discussion, it is tempting to reduce our optimization challenge introduced in the beginning to a matter of: *Applying the 'best' compression-quality trade-off to JPEGs in our site.* While there is some truth to this, it should be noted that this is nevertheless a reductionist viewpoint which ignores various scenarios referenced above. That said, we will adopt this is our working assumption as we move onto non-format considerations below. ### The Resolution Question The question of resolution comes into play because many of the tools which handle image compression also allow for editing of image dimensions, thus raising the question as to what dimensions are appropriate for web-based images. While this is intertwined with the topic of display sizes (discussed in the following section), it is helpful to pause to consider what is meant by resolution and how resolution settings, in turn, effect the manner in which the processed image is rendered. The term *resolution* has evolved to take on several meanings, among them: * dots per inch (DPI) * pixels per inch (PPI) Conventionally, resolution was expressed in something called 'DPI' or dots per inch. This was intended for print-based media but as the current treatment is for web-based projects, PPI is our relevant metric. Higher resolution means higher pixel density, which is measured by the pixel L x W area formula of a given display (thus the megapixel metric of cameras). Pixel size, however, also impacts resolution wherein smaller pixels packed in a given area will render a crisper image than larger pixels. Thus, holding the total number of pixels between two pictures constant on an identical display, raising the PPI in one image will necessarily result in shrinkage of the overall image size, ergo the following maxim: <div><pre class="code"> image size = total pixels / pixel density </pre></div> which is another way of saying that all else held constant, you get higher resolution in smaller images - something which we all by know instinctively now in our interactions with digital media. In other words, resolution suffers as images exhibit pixelation at larger dimensions given a constant pixel density. PPI and resolution varies greatly from one display to another. That said, for a long time most devices exhibited display resolutions which fell into one of several standardized categories, broadly mapping to typical resolutions for mobile, tablet, laptop, and desktop. That all changed in 2012, however, with the introduction of Apple's 2x Retina displays (and later 3x displays) which effectively squeezed two and three times as many pixels into a given area per legacy displays (thus capable of displaying higher resolution images). This last point is important. The interplay between the resolution of a given image and that of the display impacts the decision to render images for web use in that it doesn't help to have a very high resolution image if the display resolution is far inferior to that of the image. In such cases, *scaling down* an image from its native resolution would be in order. Conversely, images with low native resolution relative to target displays should be given careful consideration so as to avoid rendering overly-pixelated images. In such cases, a smaller image size (thus higher resolution) can help offset such undesirable effects. To summarize: <div><pre class="code"> 1). Scale down ultra high-res to target display res 2). CSS-constrain max-image size limits for low res images </pre></div> The overriding dominant solution, of course, is to use the highest resolution possible/appropriate for given the image's resolution and the display's capability. ### Viewport Sizes and Responsive Design The task of resizing an image given the foregoing discussion raises the question as to what image sizes should be produced. This depends, in turn, on the size of the display (or viewport) which is handling/displaying the image. Whereas picture resolution, as discussed above, is a function of the display's pixel density, the question of resizing an image is predicated on the pixel size of the displaying viewport which can be conveniently referenced using the shorthand measure of viewport display widths. Naturally, there are a wide variety of devices all sporting their own viewport widths on the market, but these can be generally classed into the following pixel-width categories (widths shown in upper bounds, inclusive): mobile phone: ~479 px tablets-medium: ~767 px tablets-large: ~991 px desktops: ~1199 px If an image were to take up the entire width of a device's viewport, these would be the *very rough* guidelines according which images could be sized (and for which image widths should be sized smaller than these measures). However, unless every image is being used as some sort of *hero* on a page, it's highly likely that the image will be substantially smaller than these widths. As such, viewport sizes are typically used as inputs into the *responsive design* approach to building websites, serving as breakpoints used in media queries. The assumption of using responsive design, together with the principal of *mobile first* development when it comes to building websites, is an overarching one - but one which we presume is a *good* approach, in keeping with best practices in page layouts and design. As such, we leave aside any discussion of the pros and cons of responsive website design and simply take it as our goal, here. Over time, the setting of media query breakpoints for responsive images in websites has evolved from the approach of matching them to the miscellany of device display widths to the common practice today of allowing *site content* to dictate appropriate breakpoints - mindful of broad categories of "standard" viewport widths such as those listed above. [Note: If you're using a responsive CSS framework like Bootstrap, helpful guidelines on viewport widths and media queries can be found [here](http://getbootstrap.com/css/). I also find [Viewport sizes](http://viewportsizes.com/) to be helpful reference for devices and their viewport widths, if you need that level of detail.] ### HTML to the rescue: picture element and srcset attribute In an effort to better match client-side requirements with server-side deliverables, we are lucky to have the html picture element and associated srcset tag, at least for browsers which support them (see [this](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture#Browser_compatibility) for a list of compatible browsers). For browsers which fully support these, not only are we able to ascertain information regarding client-side viewport widths in which our images are being displayed, we are also able to deliver the appropriately *processed* image to the client (which we take to mean the best possible quality subject to the client-side constraints communicated back to the server via this information). As such, these HTML features play a critical role in optimizing the delivery of images to the client. An example of a picture element with srcset tags is as follows: ``` <picture> <source media="(min-width: 1000px)" srcset="mypic_large_1x.jpg 1x, mypic_large_2x.jpg 2x"> <source media="(min-width: 500px)" srcset="mypic_medium_1x.jpg 1x, mypic_medium_2x.jpg 2x"> <img src="mypic_small.jpg" alt="The mypic"> <picture> ``` As can be gleaned from this entry, a media-query is used in the source attribute of the picture tag, delineating the viewport breakpoints. This way, we can vary the deliverable image given the viewport width information that is communicated back to the server. The corresponding image source is then set using the srcset tag, which is very convenient. As can be seen from this example, descriptive filenames delineate image sizes which, if they have undergone an optimization process involving scaling/cropping, resolution, and compression treatments as discussed above, go a long way toward satisfying our optimization goal we stated in the introduction. Further note that the srcset attribute allows for a resolution specifier. The suffixes '1x' and '2x' are pixel density multipliers. Thus, if the browser communicates back that the image is being displayed on a Retina display, for example, we can send back the higher-density 2x resolution image (which we ordinarily would *not* want to do with standard/non-Retina displays). Finally, the picture element has the img fallback tag for browsers which may not support the picture element. [More on the picture element see [here](https://www.w3schools.com/tags/tag_picture.asp). For browsers which do not support the picture element, a generic picture polyfill may serve as a workaround.] ### Conclusion: Putting it all together A lot of background information has been reviewed above. It's time to tie it all together. In so doing, let us restate our goal for reference: #### ***To deliver the best image quality in the most efficient manner possible.*** and rephrase this to a working version as follows: #### ***To deliver the highest quality conforming image at the smallest possible file size.*** By *conforming image* we take this to mean an image appropriate to client-side conditions which includes features such as resolution/pixel density and viewport size, as discussed above. <br> Let us also list our **working assumptions**: 1). Mindful of various image file format qualities and the characteristics of lossy format images, we mind the quality chain and produce deliverable images rendered from a high-quality (or highest available quality) master. <br> 2). We accept responsive design (and thus the use of responsive images) as our operating framework. <br> With the practical considerations/discussions referenced above, the following would serve as a reasonable set of steps in preparing images for web use: <br> <div><pre class = "code"> <b>1). Whenever possible, start from a high-quality master. </b> a). If the image is a RAW camera image, convert it to TIFF first. b). If the image is neither of these, use a PNG or some other lossless format of the image and derive all processed children from this master. 1). Note that this holds for masters in JPEG/JPG lossy formats, too. (*) c). Separate source masters from processed children. (**) <b>2). Produce responsive images with responsive design in mind.</b> a). Decide on your content and breakpoints and the corresponding image sizes you need to produce (e.g.: 1 for mobile, 1 tablet, 1 desktop, etc.). b). Make note of your image resolutions and desired target viewport resolutions. c). Note the visual complexity of your images (i.e., how detailed are they?) <b>3). Decide on a rendered file format.</b> a). If it's a simple logo, go with an SVG and forget the overhead that comes with raster image processing. b). If you're reasonably confident your content will be viewed via Chrome or some WEBP-compatible browser, go with WEBP (best quality for the size). c). If none of the above, go with the common fallback 'JPG'. <b>4). Apply preliminary renderings</b> a). This includes things like cropping images where appropriate - mindful to save these in lossless format before further processing. <b>5). Process (rescale, convert and compress) your images.</b> a). Use the high quality master (or pre-rendered equivalent from above) as your source for each renderable image. b). Resize images to desired dimensions given the responsive layout and associated breakpoints you have in mind. (***) c). If rendering images in JPG or some other lossy format, decide what level of compression is acceptable given the visual complexity of the image. 1). More detailed images can stand up to higher compression as the naked eye does not notice loss of detail as easily with simpler images like broad sunsets/landscapes. d). If applicable/possible, produce density-variant images (e.g., 2x or 3x renderings for high-resolution displays). <b>6). Use the picture element and associate image source sets (srcset) tags</b> a). Source your images when possible in these elements in your html to deliver the appropriately rendered image to the target viewport and display resolution. <b>7). Exercise CSS max-width contraints</b> a). Where applicable, add a max-width constraint to your CSS for low-resolution images to prevent them from becoming pixelated after a certain width. _______________________________________________________________________________ <div class="footnote"> *For safekeeping, I find it's good practice to convert lossy masters to lossless PNG to serve as a master. Obviously, this will not result in an image file that's any better than the source JPG, but this way I have a lossless master/backup I can use in case I should overwrite the lossy version (which, for JPGs, results in successive degradation with each save). **In other words, in your working environment, keep a source folder, say 'img_src' for masters and a default 'img' for sourced images where processed children are saved. ***While this was not mentioned before, it's generally assumed that image dimensions are kept at their original to avoid distortion (unless, of course, this is meant to happen). </div> </pre></div> <br/> Most/all of the actual image processing tasks (file format conversion, rescaling, compression) are made possible by modern graphics applications of which [ImageMagick](http://www.imagemagick.org/script/index.php) and its offshoot [GraphicsMagick](http://www.graphicsmagick.org/) are popular. Often, such tasks end up being integrated into either a [gruntified](https://gruntjs.com/) or [gulpified](http://gulpjs.com/) workflow (though traditionally, I have used my own sets of bash wrappers around these engines and their convenient command line interfaces). ### Summary Image file sizes often make up a sizeable chunk of a given website's *page weight*. As a result, the proper rendering or optimization of images for website use is often a key part of the eternal quest to reduce page weight and increase the speed of a given site to improve user experiences. In addition to local testing options such as the network throttling features which come with Chrome's Developer Tools, Google's [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/) is one of many resources developers have at their disposal in evaluating their website's efficiency. When it comes to the image preparation part, I hope this set of stylized rules/principles helps to serve as a guide to the use of images in websites.

-A. Ozan Akcin