Bitmaps in Canvas

The Canvas backend provides methods to load bitmap images in the various types provided by the web platform (i.e. the browser) and convert them to a Doodle Picture.

Loading Bitmaps

Bitmap images can be loaded from URLs using the LoadBitmap algebra. Bitmaps can be represented as either a HTMLImageElement or an ImageBitmap. HTMLImageElement is the standard DOM image element, while ImageBitmap is optimized for faster rendering.

Both instances of LoadBitmap have the same input: a String specifying the URL from which to load the image. To distinguish between these instances you need to specify the output type when calling the loadBitmap method. URLs can be familiar URLs like https://creativescala.org/ and also data URLs containing Base64 encoded bitmaps. The example below shows a bitmap being loaded from a data URL into both the available type. It also demonstrates the necessary imports.

import cats.effect.unsafe.implicits.global
import doodle.canvas.{*, given}
import doodle.syntax.all.*
import org.scalajs.dom

// Image as a Base64 encoded URL
val url =
  "data:image/png:base64,iVBORw..."

// Load as HTMLImageElement
val htmlImage = url.loadBitmap[dom.HTMLImageElement]

// Load as ImageBitmap (GPU-optimized)
val imageBitmap = url.loadBitmap[dom.ImageBitmap]

Converting Bitmaps to Picture

The Canvas backend has implementations of the ToPicture algebra for HTMLImageElement and ImageBitmap, which allows them to be converted to a Picture. Take, for example, the image below.

A hot air balloon

With the following code we can find its HTMLImageElement in the DOM, turn it into a Picture, and then work with it using the normal Doodle methods.

import cats.effect.unsafe.implicits.global
import doodle.canvas.{*, given}
import doodle.syntax.all.*
import org.scalajs.dom

val img =
  dom.document.querySelector("img").asInstanceOf[dom.HTMLImageElement]
val picture = img.toPicture.scale(0.5, 0.5).horizontalReflection
picture.drawWithFrame(Frame(id))

The result is shown below.

Complete Example

This example combines loadBitmap and toPicture, loading a Creative Commons bitmap from WikiMedia.

import cats.effect.unsafe.implicits.global
import doodle.canvas.{*, given}
import doodle.core.*
import doodle.syntax.all.*
import org.scalajs.dom

// Scaled down version of https://commons.wikimedia.org/wiki/File:A_Koch_woman.jpg
//
// Used under CC license https://creativecommons.org/licenses/by-sa/4.0/deed.en
val wikimediaUrl =
  "https://upload.wikimedia.org/wikipedia/commons/thumb/a/aa/A_Koch_woman.jpg/330px-A_Koch_woman.jpg"

val program = for {
  htmlImg <- wikimediaUrl.loadBitmap[dom.HTMLImageElement].toPicture
  imgBitmap <- wikimediaUrl.loadBitmap[dom.ImageBitmap].toPicture

  composite = htmlImage.beside(imgBitmap)

  _ <- composite.drawWithFrameToIO(Frame(id))
} yield ()

program.unsafeToFuture( )

Here's the result of this program.

Copyright © Noel Welsh. Built with 💖