Skip to content

Commit

Permalink
Merge pull request #315 from vansante/heif
Browse files Browse the repository at this point in the history
Add HEIC/HEIF support when libvips version >= 8.8
  • Loading branch information
h2non authored Feb 7, 2020
2 parents 2e5ad6e + 780105d commit a875ddc
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 4 deletions.
4 changes: 2 additions & 2 deletions resizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ func resizer(buf []byte, o Options) ([]byte, error) {
return nil, err
}

// If JPEG image, retrieve the buffer
if rotated && imageType == JPEG && !o.NoAutoRotate {
// If JPEG or HEIF image, retrieve the buffer
if rotated && (imageType == JPEG || imageType == HEIF) && !o.NoAutoRotate {
buf, err = getImageBuffer(image)
if err != nil {
return nil, err
Expand Down
Binary file added testdata/test.heic
Binary file not shown.
Binary file added testdata/test2.heic
Binary file not shown.
3 changes: 3 additions & 0 deletions type.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const (
SVG
// MAGICK represents the libmagick compatible genetic image type.
MAGICK
// HEIF represents the HEIC/HEIF/HVEC image type
HEIF
)

// ImageType represents an image type value.
Expand All @@ -45,6 +47,7 @@ var ImageTypes = map[ImageType]string{
PDF: "pdf",
SVG: "svg",
MAGICK: "magick",
HEIF: "heif",
}

// imageMutex is used to provide thread-safe synchronization
Expand Down
10 changes: 9 additions & 1 deletion type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ func TestDeterminateImageType(t *testing.T) {
{"test.pdf", PDF},
{"test.svg", SVG},
{"test.jp2", MAGICK},
{"test.heic", HEIF},
{"test2.heic", HEIF},
}

for _, file := range files {
Expand Down Expand Up @@ -46,6 +48,7 @@ func TestDeterminateImageTypeName(t *testing.T) {
{"test.pdf", "pdf"},
{"test.svg", "svg"},
{"test.jp2", "magick"},
{"test.heic", "heif"},
}

for _, file := range files {
Expand All @@ -63,7 +66,7 @@ func TestIsTypeSupported(t *testing.T) {
types := []struct {
name ImageType
}{
{JPEG}, {PNG}, {WEBP}, {GIF}, {PDF},
{JPEG}, {PNG}, {WEBP}, {GIF}, {PDF}, {HEIF},
}

for _, n := range types {
Expand All @@ -83,6 +86,7 @@ func TestIsTypeNameSupported(t *testing.T) {
{"webp", true},
{"gif", true},
{"pdf", true},
{"heif", true},
}

for _, n := range types {
Expand All @@ -101,6 +105,9 @@ func TestIsTypeSupportedSave(t *testing.T) {
if VipsVersion >= "8.5.0" {
types = append(types, struct{ name ImageType }{TIFF})
}
if VipsVersion >= "8.8.0" {
types = append(types, struct{ name ImageType }{HEIF})
}

for _, n := range types {
if IsTypeSupportedSave(n.name) == false {
Expand All @@ -120,6 +127,7 @@ func TestIsTypeNameSupportedSave(t *testing.T) {
{"gif", false},
{"pdf", false},
{"tiff", VipsVersion >= "8.5.0"},
{"heif", VipsVersion >= "8.8.0"},
}

for _, n := range types {
Expand Down
20 changes: 20 additions & 0 deletions vips.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ func VipsIsTypeSupported(t ImageType) bool {
if t == MAGICK {
return int(C.vips_type_find_bridge(C.MAGICK)) != 0
}
if t == HEIF {
return int(C.vips_type_find_bridge(C.HEIF)) != 0
}
return false
}

Expand All @@ -204,6 +207,9 @@ func VipsIsTypeSupportedSave(t ImageType) bool {
if t == TIFF {
return int(C.vips_type_find_save_bridge(C.TIFF)) != 0
}
if t == HEIF {
return int(C.vips_type_find_save_bridge(C.HEIF)) != 0
}
return false
}

Expand Down Expand Up @@ -431,6 +437,8 @@ func vipsSave(image *C.VipsImage, o vipsSaveOptions) ([]byte, error) {
saveErr = C.vips_pngsave_bridge(tmpImage, &ptr, &length, strip, C.int(o.Compression), quality, interlace)
case TIFF:
saveErr = C.vips_tiffsave_bridge(tmpImage, &ptr, &length)
case HEIF:
saveErr = C.vips_heifsave_bridge(tmpImage, &ptr, &length, strip, quality, lossless)
default:
saveErr = C.vips_jpegsave_bridge(tmpImage, &ptr, &length, strip, quality, interlace)
}
Expand Down Expand Up @@ -634,6 +642,18 @@ func vipsImageType(buf []byte) ImageType {
if IsTypeSupported(MAGICK) && strings.HasSuffix(readImageType(buf), "MagickBuffer") {
return MAGICK
}
// NOTE: libheif currently only supports heic sub types; see:
// https:/strukturag/libheif/issues/83#issuecomment-421427091
if IsTypeSupported(HEIF) && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70 &&
buf[8] == 0x68 && buf[9] == 0x65 && buf[10] == 0x69 && buf[11] == 0x63 {
// This is a HEIC file
return HEIF
}
if IsTypeSupported(HEIF) && buf[4] == 0x66 && buf[5] == 0x74 && buf[6] == 0x79 && buf[7] == 0x70 &&
buf[8] == 0x6d && buf[9] == 0x69 && buf[10] == 0x66 && buf[11] == 0x31 {
// This is a HEIF file
return HEIF
}

return UNKNOWN
}
Expand Down
33 changes: 32 additions & 1 deletion vips.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ enum types {
GIF,
PDF,
SVG,
MAGICK
MAGICK,
#if (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
HEIF,
#endif
};

typedef struct {
Expand Down Expand Up @@ -156,6 +159,11 @@ vips_type_find_bridge(int t) {
if (t == MAGICK) {
return vips_type_find("VipsOperation", "magickload");
}
#if (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
if (t == HEIF) {
return vips_type_find("VipsOperation", "heifload");
}
#endif
return 0;
}

Expand All @@ -173,6 +181,11 @@ vips_type_find_save_bridge(int t) {
if (t == JPEG) {
return vips_type_find("VipsOperation", "jpegsave_buffer");
}
#if (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
if (t == HEIF) {
return vips_type_find("VipsOperation", "heifsave_buffer");
}
#endif
return 0;
}

Expand Down Expand Up @@ -324,6 +337,20 @@ vips_tiffsave_bridge(VipsImage *in, void **buf, size_t *len) {
#endif
}

int
vips_heifsave_bridge(VipsImage *in, void **buf, size_t *len, int strip, int quality, int lossless) {
#if (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
return vips_heifsave_buffer(in, buf, len,
"strip", INT_TO_GBOOLEAN(strip),
"Q", quality,
"lossless", INT_TO_GBOOLEAN(lossless),
NULL
);
#else
return 0;
#endif
}

int
vips_is_16bit (VipsInterpretation interpretation) {
return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16;
Expand Down Expand Up @@ -370,6 +397,10 @@ vips_init_image (void *buf, size_t len, int imageType, VipsImage **out) {
#endif
} else if (imageType == MAGICK) {
code = vips_magickload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
#endif
#if (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
} else if (imageType == HEIF) {
code = vips_heifload_buffer(buf, len, out, "access", VIPS_ACCESS_RANDOM, NULL);
#endif
}

Expand Down

0 comments on commit a875ddc

Please sign in to comment.