Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encoding an Image to JPEG in Go

Tags:

go

jpeg

imaging

I have a struct called SpriteImage which is defined like this:

type SpriteImage struct {
    dimentions      image.Point
    lastImgPosition image.Point
    sprite          *image.NRGBA
}

In my flow, I first initiate a new such struct:

func NewSpriteImage(width, height int) SpriteImage {
    c := color.RGBA{0xff, 0xff, 0xff, 0xff}
    blankImage := imaging.New(width, height, c)

    return SpriteImage{
        dimentions:      image.Point{X: width, Y: height},
        lastImgPosition: image.Point{X: 0, Y: 0},
        sprite:          blankImage,
    }
}

And then I add images to this SpriteImage like so:

func (s *SpriteImage) AddImage(img image.Image) error {
    imgWidth := img.Bounds().Dx()
    imgHeight := img.Bounds().Dy()

    // Make sure new image will fit into the sprite.
    if imgWidth != s.dimentions.X {
        return fmt.Errorf("image width %d mismatch sprite width %d", imgWidth, s.dimentions.X)
    }

    spriteHeightLeft := s.dimentions.Y - s.lastImgPosition.Y
    if imgHeight > spriteHeightLeft {
        return fmt.Errorf("image height %d won't fit into sprite, sprite free space %d ", imgHeight, s.dimentions.Y)
    }

    // add image to sprite
    s.sprite = imaging.Paste(s.sprite, img, s.lastImgPosition)

    // update next image position within sprite
    s.lastImgPosition = s.lastImgPosition.Add(image.Point{X: 0, Y: imgHeight})

    return nil
}

Eventually, I want to take this SpriteImage and encode it as JPEG. But it doesn't seem to work. The native JPEG Encode function takes up an image, but I have an image.NRGBA. So I'm using github.com/disintegration/imaging lib like so:

func (s SpriteImage) GetBytes() ([]byte, error) {
    var b bytes.Buffer
    w := bufio.NewWriter(&b)

    if s.sprite == nil {
        return nil, fmt.Errorf("sprite is nil")
    }

    if err := imaging.Encode(w, s.sprite, imaging.JPEG); err != nil {
        return nil, err
    }

    return b.Bytes(), nil
}

However is seems that the bytes returned are not in fact JPEG. The native Go JPEG lib will not decode those bytes to a Go image struct. If I try to decode those bytes to image like so:

     m, _, err := image.Decode(reader)
     if err != nil {
        log.Fatal(err)
     }

I'm getting err:

image: unknown format

Any ideas?

like image 267
orcaman Avatar asked Oct 18 '22 01:10

orcaman


1 Answers

So, it looks like this may be an issue with the github.com/disintegration/imaging lib. I posted an issue about it in the repo's page.

If I change my GetBytes() function to this, I get valid JPEG:

func (s SpriteImage) GetBytes() ([]byte, error) {
    var b bytes.Buffer
    w := bufio.NewWriter(&b)

    if s.sprite == nil {
        return nil, fmt.Errorf("sprite is nil")
    }

    im := s.sprite
    err := jpeg.Encode(w, im, &jpeg.Options{jpegCompression})

    if err != nil {
        fmt.Println(err)
    }

    return b.Bytes(), nil
}
like image 72
orcaman Avatar answered Oct 21 '22 01:10

orcaman