Coder Social home page Coder Social logo

andrewstephens75 / as-dithered-image Goto Github PK

View Code? Open in Web Editor NEW
171.0 3.0 2.0 5.03 MB

HTML custom element to correctly dither an image giving pixel-perfect crisp results on all displays

License: MIT License

JavaScript 86.51% HTML 13.49%
atkinson customelement dithering dithering-algorithms javascript

as-dithered-image's Introduction

Custom HTML Element for Client-side Atkinson Dithering

There are many dithering algorithms to crush multi-colored images down to black and white but the one I like best was introduced with the original Apple Macintosh for its crisp 512x342 monochrome display. One of Apple's engineers, Bill Atkinson, developed what came to be known as Atkinson Dithering, a good trade-off between fast and accurate with results possessing a certain charm that on-paper "better" dithers cannot match.

I wanted to bring this to the web. For some examples of how to use this project and an interactive demo see my blog post on the subject.

Why Do This Client Side?

You can pre-dither your images but this gives bad results because dithering relies on the precise correspondence between the source and out pixels. Unless you can guarantee that your image will be displayed at exactly the same size (in pixels) as it was output, the pixels of the image will not align with the pixels of your screen and the results will be either blurry or fulled with weird patterns. The technical term for this is aliasing but whatever you call it, it ruins your image.

The only way to get really crisp results in a web browser is to dither the source image to the exact pixel size of the element when it is displayed.

Why as-dithered-image?

There is other javascript floating around out there that does much the same thing. as-dithered-image has a few advantages:

  • I put some effort into getting really crisp results even on high-DPI displays. Most of the other code out there looks slightly blurry due to not taking this into account.
  • Resizing is completely supported, allowing for dithered images in responsive designs. The element automatically adjusts its aspect ratio based on the image.
  • Dithering is performed in a web worker so as to not block rendering of the rest of the page.
  • as-dithered-image elements that are completely offscreen are not dithered until they are just about to scroll into view
  • Accessibility is supported with the alt tag.
  • Some control over the look of the dither is supported with the crunch and cutoff attributes.

Usage

You will need to copy the following two files into your web project, they should be placed together in the same directory.

  • as-dithered-image.js
  • ditherworker.js

Example usage:

<script src="as-dithered-image.js"></script>

<as-dithered-image src="mypicture.jpg" alt="Description of the image for screen readers"></as-dithered-image>

as-dithered-image takes 6 attributes:

  • src (required) the url of the image. Can be a data url.
  • alt (strictly speaking optional, but it is rude not to) the alt text, important for screen readers.
  • crunch (optional) controls the size of the logical pixels the image is dithered into. May be one of:
    • an integer, where 1 means dither to logical css pixels no matter what the DPI. 2 makes the logical pixels twice the size, for a coarser look. 3 is really blocky.
    • auto (the default) attempts to give good results on very high-DPI screens (like iPhones) which have such small pixels that standard dithering just looks grey. It is equivalent of 1 on most displays and 2 on devices where the ratio of screen to css pixels is 3 or more.
    • pixel dither to screen pixels. This can either look amazing or be completely wasted depending on the size of the screen but you paid for all the pixels so you might as well use them.
  • cutoff (optional) a float between 0 and 1, defaulting to 0.5. Controls the cutoff the dithering algorithm uses to determine whether a pixel is black or white. Modifying this will produce either a lighter or darker image.
  • darkrgba (optional) a string of the form "rgba(0, 0, 0, 255)" (and only this form because I am lazy). Sets the RGBA value for dark pixels, defaulting to fully opaque black, useful for matching the image to the colors of the surrounding page or making transparent areas. Note that this just controls the output color, the dithering is still performed based on the closeness of a pixel to black or white.
  • lightrgba (optional) a string of the form "rgba(255, 255, 255, 255)". Similar to the above but for the light pixels.

Legal

See LICENSE file for usage.

as-dithered-image's People

Contributors

andrewstephens75 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

as-dithered-image's Issues

Support ordered dithering?

Hey! Having a lot of fun implementing things with this little script and I'm enjoying the results. Thanks for writing this!

Would it be possible to add ordered/Bayer dithering as an option?

Ordered dithering produces "worse" results than Atkinson dithering because of the visible cross-hatch effect, but some of us (me) think that effect is cool :)

And on the plus side, ordered dithering is very fast to execute.

image image image

Improve rendering speed w/ caching

Really cool component.

Here are some quick thoughts (could be a pull-request but I just wanted to put this out there):

  • How about using gray-scale images as placeholders during resizing operations? Use the browser's native (fast) rescaling for "smooth" resizing. Then, dither only when the resizing stops or is paused.
  • Also, you could use the Cache API to cache the dithered versions so if the user resizes again to the same size (likely), you incur no dithering lag/cost? https://medium.com/javascript-dots/cache-api-in-javascript-644380391681

Object-fit: cover?

Hi @andrewstephens75 . Thanks for this component. I'm hoping to possibly use it in a small festival site that is using diffused dithered images in its marketing campaign.

Can the component be used for a full width and height image background layer that fills the viewport in an object-fit: cover manner?

I've tried a few things but not sure if it's worth pursuing further if the underlying component doesn't really support it.

Thanks!

Ideas for future improvements

Random ideas for the future (in no particular order)

Make sure none of these changes break printing

  • add image-rendering: crisp-edges or pixilated to the canvas css
  • have another attempt at handling fractional device pixel ratios
  • cache the src image once, don't load it every time
  • automatically apply the aspect ratio when the new image loads
  • do something if the image fails to load (show placeholder icon?)
  • Move dithering to worker. Cancel outstanding operations on subsequent resizing.
  • Try to reduce redraws during resizing - possibly defer resizing until no resize events have been seen for 10ms or something
  • defer resizing if the component is off-screen, performing the operation just as it scrolls into view with the Intersection API : https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
  • display something during resizing, a placeholder image or icon.
  • support a dither attribute to swap in alternate dithers (Sierra dithering looks interesting https://github.com/nwj/dither)
  • support a threshold attribute to control the threshold between light and dark (0.0 - 1.0, 0.5 is the default)
  • support dark and light attributes to control the color of the resulting image. Do we dither assuming these will be black and white and then just force the color or actually dither to those colors (much harder)?
  • maybe have a setting to set one of the colors to transparent (for slightly off-white backgrounds, etc)
  • have another attempt at extending the img tag. We cannot get access to the image data but perhaps you can fetch the src and render a replacement canvas over the top.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.