Convert HEIC to JPG in Go (original) (raw)

The “High Efficiency Image File Format” or HEIF is an image format often used by Apple devices. Although called HEIF, the file types are often heic (presumably the ‘c’ stands for container?) They use a similar encoding method of video formats and are deemed better quality and lower file size than standard jpeg files.

In our example, we’re trying to convert these heic files back into jpg files though - so we can use them elsewhere, display them or what ever we choose.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 package main import ( "image/jpeg" "io" "log" "os" "github.com/adrium/goheif" ) // Skip Writer for exif writing type writerSkipper struct { w io.Writer bytesToSkip int } func main() { err := convertHeicToJpg("image1.heic", "sample.jpg") if err != nil { log.Fatal(err) } log.Println("Conversion Passed") } // convertHeicToJpg takes in an input file (of heic format) and converts // it to a jpeg format, named as the output parameters. func convertHeicToJpg(input, output string) error { fileInput, err := os.Open(input) if err != nil { return err } defer fileInput.Close() // Extract exif to add back in after conversion exif, err := goheif.ExtractExif(fileInput) if err != nil { return err } img, err := goheif.Decode(fileInput) if err != nil { return err } fileOutput, err := os.OpenFile(output, os.O_RDWR|os.O_CREATE, 0644) if err != nil { return err } defer fileOutput.Close() // Write both convert file + exif data back w, _ := newWriterExif(fileOutput, exif) err = jpeg.Encode(w, img, nil) if err != nil { return err } return nil } func (w *writerSkipper) Write(data []byte) (int, error) { if w.bytesToSkip <= 0 { return w.w.Write(data) } if dataLen := len(data); dataLen < w.bytesToSkip { w.bytesToSkip -= dataLen return dataLen, nil } if n, err := w.w.Write(data[w.bytesToSkip:]); err == nil { n += w.bytesToSkip w.bytesToSkip = 0 return n, nil } else { return n, err } } func newWriterExif(w io.Writer, exif []byte) (io.Writer, error) { writer := &writerSkipper{w, 2} soi := []byte{0xff, 0xd8} if _, err := w.Write(soi); err != nil { return nil, err } if exif != nil { app1Marker := 0xe1 markerlen := 2 + len(exif) marker := []byte{0xff, uint8(app1Marker), uint8(markerlen >> 8), uint8(markerlen & 0xff)} if _, err := w.Write(marker); err != nil { return nil, err } if _, err := w.Write(exif); err != nil { return nil, err } } return writer, nil }