issa

package module
v0.1.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2024 License: MIT Imports: 13 Imported by: 10

README

issa

issa is an image summary string module that produces a small and very compact representation of a source image. Image summaries produced by issa are expected to be a tiny fraction of the source image size at default downsampling level (16).

This makes issa image summaries suitable for using as a rich image previews that can be embedded with JSON/HTML payload before actual images are requested. Initial analysis suggested that for a 400Kb image, issa would produce a 3Kb base64 encoded summary, that would take about 2Kb storage space dehydrated. Hydration doesn't take a lot of computational resources and can be done on the critical path.

Space savings are achieved by two factors:

  • issa uses a standard 255 palette and maps all source image colors to that palette. Combined with sampling this is (obviously) the main source of the reduction
  • Additionally, having a standard palette and using GIF image allows issa to remove a reproducible header of the resulting base64 string, that is about 20% of the typical GIF image

Using issa

Typical workflow of an app using issa has the following steps:

  • Summarize, dehydrate and store source images into an image summary
  • Dehydrate images as needed and embed into HTML/JSON payload
Summarizing, dehydrating and storing image summaries
  • Load source image
  • Convert source image into paletted GIF
  • Dehydrate paletted GIF

NOTE: example below oversimplifies error handling for brevity

package main

import (
	"github.com/boggydigital/issa"
	"fmt"
	"image"
	_ "image/jpeg"
	"os"
)

func main() {
	fi, err := os.Open("image.jpeg")
	if err != nil {panic(err)}
	defer fi.Close()

	jpegImage, _, err := image.Decode(fi)
	if err != nil {panic(err)}

	gifImage := issa.GIFImage(
		jpegImage,
		issa.StdPalette(),
		issa.DefaultDownSampling)

	dhi, err := issa.Dehydrate(gifImage)
	if err != nil {panic(err)}

	fmt.Println(dhi)
}
Hydrating images
  • Load dehydrated string
  • Hydrate it
package main

import (
	"github.com/boggydigital/issa"
	"fmt"
)

func main() {

	dhi := ""
	// load dehydrated string into dhi from the store

	hi := issa.Hydrate(dhi)

	fmt.Printf(hi)
}

Sample

Source image along with an issa (from https://en.wikipedia.org/wiki/Semaeopus):

Issa moth

Dehydrated image string at the default downsampling level:

25=19=ItACtCRxIsKDBgwgTKly4ENATQM8YQsuXLl/BJwBIqCBlbRU0gtBWWcvnhASAJxdJqESSZ5VLgS6f5UGiEkCVgoAykkBCs96qfC5JOeGpkgSggs+KEiWRp0qePCtpqoxYsJ7SlRmlSiVR7yA0QFGdlATAcykgaB8LQnuiFInYt0uroD3ItijXplDtokxb0J5OEk5kplu1FcBRvgXzch1pUbHchfmcIn725AkpxAwza97MufPmgAA7

Hydrated image string at the default downsampling level (copy and paste as an URL to check out):

data:image/gif;base64,R0lGODlhGQATAAAAACwAAAAAGQATAIcqKioqKlQqKn4qKqgqKtIqKvwqVCoqVFQqVH4qVKgqVNIqVPwqfioqflQqfn4qfqgqftIqfvwqqCoqqFQqqH4qqKgqqNIqqPwq0ioq0lQq0n4q0qgq0tIq0vwq/Coq/FQq/H4q/Kgq/NIq/PxUKipUKlRUKn5UKqhUKtJUKvxUVCpUVFRUVH5UVKhUVNJUVPxUfipUflRUfn5UfqhUftJUfvxUqCpUqFRUqH5UqKhUqNJUqPxU0ipU0lRU0n5U0qhU0tJU0vxU/CpU/FRU/H5U/KhU/NJU/Px+Kip+KlR+Kn5+Kqh+KtJ+Kvx+VCp+VFR+VH5+VKh+VNJ+VPx+fip+flR+fn5+fqh+ftJ+fvx+qCp+qFR+qH5+qKh+qNJ+qPx+0ip+0lR+0n5+0qh+0tJ+0vx+/Cp+/FR+/H5+/Kh+/NJ+/PyoKiqoKlSoKn6oKqioKtKoKvyoVCqoVFSoVH6oVKioVNKoVPyofiqoflSofn6ofqioftKofvyoqCqoqFSoqH6oqKioqNKoqPyo0iqo0lSo0n6o0qio0tKo0vyo/Cqo/FSo/H6o/Kio/NKo/PzSKirSKlTSKn7SKqjSKtLSKvzSVCrSVFTSVH7SVKjSVNLSVPzSfirSflTSfn7SfqjSftLSfvzSqCrSqFTSqH7SqKjSqNLSqPzS0irS0lTS0n7S0qjS0tLS0vzS/CrS/FTS/H7S/KjS/NLS/Pz8Kir8KlT8Kn78Kqj8KtL8Kvz8VCr8VFT8VH78VKj8VNL8VPz8fir8flT8fn78fqj8ftL8fvz8qCr8qFT8qH78qKj8qNL8qPz80ir80lT80n780qj80tL80vz8/Cr8/FT8/H78/Kj8/NL8/PwAAAAAAP8A/wAA////AAD/AP///wD///9sbGxsbJZsbMBslmxslpZslsBswGxswJZswMCWbGyWbJaWbMCWlmyWlpaWlsCWwGyWwJaWwMDAbGzAbJbAbMDAlmzAlpbAlsDAwGzAwJbAwMAAAAAAAAAAAAAAAAAAAAAItACtCRxIsKDBgwgTKly4ENATQM8YQsuXLl/BJwBIqCBlbRU0gtBWWcvnhASAJxdJqESSZ5VLgS6f5UGiEkCVgoAykkBCs96qfC5JOeGpkgSggs+KEiWRp0qePCtpqoxYsJ7SlRmlSiVR7yA0QFGdlATAcykgaB8LQnuiFInYt0uroD3ItijXplDtokxb0J5OEk5kplu1FcBRvgXzch1pUbHchfmcIn725AkpxAwza97MufPmgAA7

Documentation

Index

Constants

View Source
const (
	MIMETypeBase64Prefix = "data:image/gif;base64,"
	GIF89aBase64Header   = "R0lGODlh" // GIF89a
)
View Source
const ColorPaletteBase64Content = "qKioqKlQqKn4qKqgqKtIqKvwqVCoqVFQqVH4qVKgqVNIqVPwqfioqflQqfn4qfqg" +
	"qftIqfvwqqCoqqFQqqH4qqKgqqNIqqPwq0ioq0lQq0n4q0qgq0tIq0vwq/Coq/FQ" +
	"q/H4q/Kgq/NIq/PxUKipUKlRUKn5UKqhUKtJUKvxUVCpUVFRUVH5UVKhUVNJUVPx" +
	"UfipUflRUfn5UfqhUftJUfvxUqCpUqFRUqH5UqKhUqNJUqPxU0ipU0lRU0n5U0qh" +
	"U0tJU0vxU/CpU/FRU/H5U/KhU/NJU/Px+Kip+KlR+Kn5+Kqh+KtJ+Kvx+VCp+VFR" +
	"+VH5+VKh+VNJ+VPx+fip+flR+fn5+fqh+ftJ+fvx+qCp+qFR+qH5+qKh+qNJ+qPx" +
	"+0ip+0lR+0n5+0qh+0tJ+0vx+/Cp+/FR+/H5+/Kh+/NJ+/PyoKiqoKlSoKn6oKqi" +
	"oKtKoKvyoVCqoVFSoVH6oVKioVNKoVPyofiqoflSofn6ofqioftKofvyoqCqoqFS" +
	"oqH6oqKioqNKoqPyo0iqo0lSo0n6o0qio0tKo0vyo/Cqo/FSo/H6o/Kio/NKo/Pz" +
	"SKirSKlTSKn7SKqjSKtLSKvzSVCrSVFTSVH7SVKjSVNLSVPzSfirSflTSfn7Sfqj" +
	"SftLSfvzSqCrSqFTSqH7SqKjSqNLSqPzS0irS0lTS0n7S0qjS0tLS0vzS/CrS/FT" +
	"S/H7S/KjS/NLS/Pz8Kir8KlT8Kn78Kqj8KtL8Kvz8VCr8VFT8VH78VKj8VNL8VPz" +
	"8fir8flT8fn78fqj8ftL8fvz8qCr8qFT8qH78qKj8qNL8qPz80ir80lT80n780qj" +
	"80tL80vz8/Cr8/FT8/H78/Kj8/NL8/PwAAAAAAP8A/wAA////AAD/AP///wD///9" +
	"sbGxsbJZsbMBslmxslpZslsBswGxswJZswMCWbGyWbJaWbMCWlmyWlpaWlsCWwGy" +
	"WwJaWwMDAbGzAbJbAbMDAlmzAlpbAlsDAwGzAwJbAwMAAAAAAAAAAAAAAAAAAAAA"
View Source
const DefaultSampling = 16
View Source
const GreyscalePaletteBase64Content = "AAAABAQECAgIDAwMEBAQFBQUGBgYHBwcICAgJCQkKCgoLCwsMDAwNDQ0ODg4PDw8" +
	"QEBARERESEhITExMUFBQVFRUWFhYXFxcYGBgZGRkaGhobGxscHBwdHR0eHh4fHx8" +
	"gICAhISEiIiIjIyMkJCQlJSUmJiYnJycoKCgpKSkqKiorKyssLCwtLS0uLi4vLy8" +
	"wMDAxMTEyMjIzMzM0NDQ1NTU2NjY3Nzc4ODg5OTk6Ojo7Ozs8PDw9PT0+Pj4/Pz9" +
	"AQEBBQUFCQkJDQ0NERERFRUVGRkZHR0dISEhJSUlKSkpLS0tMTExNTU1OTk5PT09" +
	"QUFBRUVFSUlJTU1NUVFRVVVVWVlZXV1dYWFhZWVlaWlpbW1tcXFxdXV1eXl5fX19" +
	"gYGBhYWFiYmJjY2NkZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5vb29" +
	"wcHBxcXFycnJzc3N0dHR1dXV2dnZ3d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+" +
	"AgICBgYGCgoKDg4OEhISFhYWGhoaHh4eIiIiJiYmKioqLi4uMjIyNjY2Ojo6Pj4+" +
	"QkJCRkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZmampqbm5ucnJydnZ2enp6fn5+" +
	"goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6+" +
	"wsLCxsbGysrKzs7O0tLS1tbW2tra3t7e4uLi5ubm6urq7u7u8vLy9vb2+vr6/v7/" +
	"AwMDBwcHCwsLDw8PExMTFxcXGxsbHx8fIyMjJycnKysrLy8vMzMzNzc3Ozs7Pz8/" +
	"Q0NDR0dHS0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc3Nzd3d3e3t7f39/" +
	"g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u7u7v7+/" +
	"w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7///8"

Variables

View Source
var HydrateColorScript []byte

Functions

func ColorHex added in v0.1.13

func ColorHex(c color.Color) string

func ColorPalette added in v0.1.11

func ColorPalette() color.Palette

func ColorPalettePrefix added in v0.1.11

func ColorPalettePrefix(w, h int) string

func DehydrateColor added in v0.1.11

func DehydrateColor(gifImage *gif.GIF) (string, error)

func DehydrateGreyscale added in v0.1.11

func DehydrateGreyscale(gifImage *gif.GIF) (string, error)

func DehydratedSizePrefix added in v0.1.3

func DehydratedSizePrefix(x, y int) string

func GIFImage

func GIFImage(img image.Image, plt color.Palette, sample int) *gif.GIF

GIFImage converts a given image to a standard palette (see ColorPalette) image, that is down-sampled (e.g. by a factor of 16x by default)

func GreyscalePalette added in v0.1.11

func GreyscalePalette() color.Palette

func GreyscalePalettePrefix added in v0.1.11

func GreyscalePalettePrefix(w, h int) string

func HydrateColor added in v0.1.11

func HydrateColor(dehydrated string) string

func HydrateGreyscale added in v0.1.11

func HydrateGreyscale(dehydrated string) string

func OptimalSampling added in v0.1.13

func OptimalSampling(imageSources []string) (int, int, error)

func RepColor added in v0.1.13

func RepColor(image *gif.GIF) color.Color

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL