Skip to content

Commit

Permalink
vips_thumbnail from file and optimizations (#237)
Browse files Browse the repository at this point in the history
* implement VipsSize

* DetermineImageTypeFromFields

* handle bmp compatibility

* refactor bmp to png sequence

* implement ImageType based on vips-loader metadata, added DetermineImageTypeFromLoader

* implement vipsThumbnailFromFile, use native vips function for NewThumbnailFromFile

* add benchmark script

* update namespace

* update namespace

* add constant

* vipsDetermineImageTypeFromMetaLoader

* add back test coverage

* vipsImageGetMetaLoader
  • Loading branch information
cshum authored Dec 30, 2021
1 parent 0bd4301 commit 6433b63
Show file tree
Hide file tree
Showing 12 changed files with 378 additions and 43 deletions.
119 changes: 119 additions & 0 deletions examples/thumbnail/bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package thumbnail

import (
"fmt"
"github.com/davidbyttow/govips/v2/vips"
"io/ioutil"
"testing"
)

var file = "../../resources/jpg-24bit-icc-iec.jpg"

func init() {
vips.LoggingSettings(func(domain string, level vips.LogLevel, msg string) {
fmt.Println(domain, level, msg)
}, vips.LogLevelError)
vips.Startup(nil)
}

func BenchmarkNewImageFromFile(b *testing.B) {
resizeToTest := func(size int) {
image, err := vips.NewImageFromFile(file)
if err != nil {
panic(err)
}
if err := image.Thumbnail(size*100, size*100, vips.InterestingCentre); err != nil {
panic(err)
}
if err := image.Flip(vips.DirectionVertical); err != nil {
panic(err)
}
if _, _, err = image.ExportNative(); err != nil {
panic(err)
}
}
for i := 0; i < b.N; i++ {
resizeToTest(1)
resizeToTest(2)
resizeToTest(3)
resizeToTest(4)
resizeToTest(5)
}
}

func BenchmarkNewImageFromBuffer(b *testing.B) {
resizeToTest := func(size int) {
buf, err := ioutil.ReadFile(file)
if err != nil {
panic(err)
}
image, err := vips.NewImageFromBuffer(buf)
if err != nil {
panic(err)
}
if err := image.Thumbnail(size*100, size*100, vips.InterestingCentre); err != nil {
panic(err)
}
if err := image.Flip(vips.DirectionVertical); err != nil {
panic(err)
}
if _, _, err = image.ExportNative(); err != nil {
panic(err)
}
}
for i := 0; i < b.N; i++ {
resizeToTest(1)
resizeToTest(2)
resizeToTest(3)
resizeToTest(4)
resizeToTest(5)
}
}

func BenchmarkNewThumbnailFromFile(b *testing.B) {
resizeToTest := func(size int) {
image, err := vips.NewThumbnailFromFile(file, size*100, size*100, vips.InterestingCentre)
if err != nil {
panic(err)
}
if err := image.Flip(vips.DirectionVertical); err != nil {
panic(err)
}
if _, _, err = image.ExportNative(); err != nil {
panic(err)
}
}
for i := 0; i < b.N; i++ {
resizeToTest(1)
resizeToTest(2)
resizeToTest(3)
resizeToTest(4)
resizeToTest(5)
}
}

func BenchmarkNewThumbnailFromBuffer(b *testing.B) {
resizeToTest := func(size int) {
buf, err := ioutil.ReadFile(file)
if err != nil {
panic(err)
}
image, err := vips.NewThumbnailFromBuffer(buf, size*100, size*100, vips.InterestingCentre)
if err != nil {
panic(err)
}
if err := image.Flip(vips.DirectionVertical); err != nil {
panic(err)
}
if _, _, err = image.ExportNative(); err != nil {
panic(err)
}
}
for i := 0; i < b.N; i++ {
resizeToTest(1)
resizeToTest(2)
resizeToTest(3)
resizeToTest(4)
resizeToTest(5)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions vips/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ int get_image_get_n_pages(VipsImage *in) {
page = vips_image_get_n_pages(in);
return page;
}

int get_meta_loader(const VipsImage *in, const char **out) {
return vips_image_get_string(in, VIPS_META_LOADER, out);
}
51 changes: 50 additions & 1 deletion vips/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package vips

// #include "header.h"
import "C"
import "unsafe"
import (
"strings"
"unsafe"
)

func vipsHasICCProfile(in *C.VipsImage) bool {
return int(C.has_icc_profile(in)) != 0
Expand Down Expand Up @@ -52,3 +55,49 @@ func vipsSetMetaOrientation(in *C.VipsImage, orientation int) {
func vipsImageGetPages(in *C.VipsImage) int {
return int(C.get_image_get_n_pages(in))
}

func vipsImageGetMetaLoader(in *C.VipsImage) (string, bool) {
var out *C.char
defer gFreePointer(unsafe.Pointer(out))
code := int(C.get_meta_loader(in, &out))
return C.GoString(out), code == 0
}

// vipsDetermineImageTypeFromMetaLoader determine the image type from vips-loader metadata
func vipsDetermineImageTypeFromMetaLoader(in *C.VipsImage) ImageType {
vipsLoader, ok := vipsImageGetMetaLoader(in)
if vipsLoader == "" || !ok {
return ImageTypeUnknown
}
if strings.HasPrefix(vipsLoader, "jpeg") {
return ImageTypeJPEG
}
if strings.HasPrefix(vipsLoader, "png") {
return ImageTypePNG
}
if strings.HasPrefix(vipsLoader, "gif") {
return ImageTypeGIF
}
if strings.HasPrefix(vipsLoader, "svg") {
return ImageTypeSVG
}
if strings.HasPrefix(vipsLoader, "webp") {
return ImageTypeWEBP
}
if strings.HasPrefix(vipsLoader, "jp2k") {
return ImageTypeJP2K
}
if strings.HasPrefix(vipsLoader, "magick") {
return ImageTypeMagick
}
if strings.HasPrefix(vipsLoader, "tiff") {
return ImageTypeTIFF
}
if strings.HasPrefix(vipsLoader, "heif") {
return ImageTypeHEIF
}
if strings.HasPrefix(vipsLoader, "pdf") {
return ImageTypePDF
}
return ImageTypeUnknown
}
1 change: 1 addition & 0 deletions vips/header.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ int get_meta_orientation(VipsImage *in);
void remove_meta_orientation(VipsImage *in);
void set_meta_orientation(VipsImage *in, int orientation);
int get_image_get_n_pages(VipsImage *in);
int get_meta_loader(const VipsImage *in, const char **out);
63 changes: 54 additions & 9 deletions vips/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,22 +373,56 @@ func LoadImageFromBuffer(buf []byte, params *ImportParams) (*ImageRef, error) {
return ref, nil
}

// NewThumbnailFromFile loads an image from file and creates a new ImageRef with thumbnail ops
// NewThumbnailFromFile loads an image from file and creates a new ImageRef with thumbnail crop
func NewThumbnailFromFile(file string, width, height int, crop Interesting) (*ImageRef, error) {
buf, err := ioutil.ReadFile(file)
startupIfNeeded()

vipsImage, format, err := vipsThumbnailFromFile(file, width, height, crop, SizeBoth)
if err != nil {
return nil, err
}

govipsLog("govips", LogLevelDebug, fmt.Sprintf("creating imageref from file %s", file))
return NewThumbnailFromBuffer(buf, width, height, crop)
ref := newImageRef(vipsImage, format, nil)

govipsLog("govips", LogLevelDebug, fmt.Sprintf("created imageref %p", ref))
return ref, nil
}

// NewThumbnailFromBuffer loads an image buffer and creates a new Image with thumbnail ops
// NewThumbnailFromBuffer loads an image buffer and creates a new Image with thumbnail crop
func NewThumbnailFromBuffer(buf []byte, width, height int, crop Interesting) (*ImageRef, error) {
startupIfNeeded()

vipsImage, format, err := vipsThumbnailFromBuffer(buf, width, height, crop)
vipsImage, format, err := vipsThumbnailFromBuffer(buf, width, height, crop, SizeBoth)
if err != nil {
return nil, err
}

ref := newImageRef(vipsImage, format, buf)

govipsLog("govips", LogLevelDebug, fmt.Sprintf("created imageref %p", ref))
return ref, nil
}

// NewThumbnailWithSizeFromFile loads an image from file and creates a new ImageRef with thumbnail crop and size
func NewThumbnailWithSizeFromFile(file string, width, height int, crop Interesting, size Size) (*ImageRef, error) {
startupIfNeeded()

vipsImage, format, err := vipsThumbnailFromFile(file, width, height, crop, size)
if err != nil {
return nil, err
}

ref := newImageRef(vipsImage, format, nil)

govipsLog("govips", LogLevelDebug, fmt.Sprintf("created imageref %p", ref))
return ref, nil
}

// NewThumbnailWithSizeFromBuffer loads an image buffer and creates a new Image with thumbnail crop and size
func NewThumbnailWithSizeFromBuffer(buf []byte, width, height int, crop Interesting, size Size) (*ImageRef, error) {
startupIfNeeded()

vipsImage, format, err := vipsThumbnailFromBuffer(buf, width, height, crop, size)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1357,10 +1391,21 @@ func (r *ImageRef) ResizeWithVScale(hScale, vScale float64, kernel Kernel) error
}

// Thumbnail resizes the image to the given width and height.
// If crop is true the returned image size will be exactly the given height and width,
// otherwise the width and height will be within the given parameters.
// crop decides algorithm vips uses to shrink and crop to fill target,
func (r *ImageRef) Thumbnail(width, height int, crop Interesting) error {
out, err := vipsThumbnail(r.image, width, height, crop)
out, err := vipsThumbnail(r.image, width, height, crop, SizeBoth)
if err != nil {
return err
}
r.setImage(out)
return nil
}

// ThumbnailWithSize resizes the image to the given width and height.
// crop decides algorithm vips uses to shrink and crop to fill target,
// size controls upsize, downsize, both or force
func (r *ImageRef) ThumbnailWithSize(width, height int, crop Interesting, size Size) error {
out, err := vipsThumbnail(r.image, width, height, crop, size)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 6433b63

Please sign in to comment.