Skip to content

Instantly share code, notes, and snippets.

@unixpickle
Last active August 29, 2015 01:55
Show Gist options
  • Save unixpickle/f3f9cfed3c191f22c7eb to your computer and use it in GitHub Desktop.
Save unixpickle/f3f9cfed3c191f22c7eb to your computer and use it in GitHub Desktop.
Diff image compression
package main
import (
"compress/gzip"
"fmt"
"image/jpeg"
"log"
"os"
)
var ImageFile string = "image.jpeg"
func main() {
rgbData, diffStreams := GetBitmapData()
fmt.Println("gzip(rgb) =", MeasureGzipSize(rgbData), "gzip(diff) =",
MeasureGzipSize(diffStreams), "RGB data length", len(rgbData))
}
func GetBitmapData() (rgbData []byte, diffStreams []byte) {
file, err := os.Open("image.jpeg")
if err != nil {
log.Fatal("Failed to open " + ImageFile)
}
defer file.Close()
image, err := jpeg.Decode(file)
if err != nil {
log.Fatal("Failed to decode " + ImageFile)
}
width := image.Bounds().Dx()
height := image.Bounds().Dy()
rgbData = make([]byte, 3*width*height)
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r, g, b, _ := image.At(x+image.Bounds().Min.X, y+image.Bounds().Min.Y).RGBA()
index := (y*width + x) * 3
rgbData[index] = byte(r >> 8)
rgbData[index+1] = byte(g >> 8)
rgbData[index+2] = byte(b >> 8)
}
}
diffStreams = make([]byte, 3*width*height)
var lastR, lastG, lastB byte
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
r, g, b, _ := image.At(x+image.Bounds().Min.X, y+image.Bounds().Min.Y).RGBA()
redIndex := y*width + x
greenIndex := y*width + x + width*height
blueIndex := y*width + x + 2*width*height
diffStreams[redIndex] = byte(r>>8) - lastR
diffStreams[greenIndex] = byte(g>>8) - lastG
diffStreams[blueIndex] = byte(b>>8) - lastB
lastR = byte(r >> 8)
lastG = byte(r >> 8)
lastB = byte(r >> 8)
}
}
return
}
func MeasureGzipSize(data []byte) int {
counter := &CounterWriter{}
writer, _ := gzip.NewWriterLevel(counter, gzip.BestCompression)
count, err := writer.Write(data)
if err != nil || count < len(data) {
log.Fatal("failed to compress in one pass")
}
if err := writer.Flush(); err != nil {
log.Fatal("got error:", err)
}
return counter.Count
}
type CounterWriter struct {
Count int
}
func (c *CounterWriter) Write(b []byte) (n int, err error) {
c.Count += len(b)
return len(b), nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment