diff --git a/fixtures/test.jpg b/fixtures/test.jpg index 3e0e61d..9309106 100644 Binary files a/fixtures/test.jpg and b/fixtures/test.jpg differ diff --git a/options.go b/options.go index bd2002f..8b5ea6b 100644 --- a/options.go +++ b/options.go @@ -1,5 +1,11 @@ package bimg +/* +#cgo pkg-config: vips +#include "vips/vips.h" +*/ +import "C" + const QUALITY = 80 type Gravity int @@ -16,6 +22,26 @@ func (i Interpolator) String() string { return interpolations[i] } +type Rotation struct { + angle int +} + +func (a Rotation) calculate() int { + angle := a.angle + divisor := angle % 90 + if divisor != 0 { + angle = a.angle - divisor + } + return angle +} + +type Direction int + +const ( + HORIZONTAL Direction = C.VIPS_DIRECTION_HORIZONTAL + VERTICAL Direction = C.VIPS_DIRECTION_VERTICAL +) + type Options struct { Height int Width int @@ -23,7 +49,9 @@ type Options struct { Enlarge bool Extend int Embed bool - Interpolator Interpolator - Gravity Gravity Quality int + Rotate int + Flip Direction + Gravity Gravity + Interpolator Interpolator } diff --git a/resize.go b/resize.go index c4a9ef9..d5e78bf 100644 --- a/resize.go +++ b/resize.go @@ -18,7 +18,6 @@ const ( func Resize(buf []byte, o Options) ([]byte, error) { // detect (if possible) the file type - defer C.vips_thread_shutdown() image, err := vipsRead(buf) @@ -26,16 +25,6 @@ func Resize(buf []byte, o Options) ([]byte, error) { return nil, err } - //var tmpImage *C.struct__VipsImage - /* - // feed it - imageLength := C.size_t(len(buf)) - imageBuf := unsafe.Pointer(&buf[0]) - debug("buffer: %s", buf[0]) - - C.vips_jpegload_buffer_seq(imageBuf, imageLength, &image) - */ - // defaults if o.Quality == 0 { o.Quality = QUALITY @@ -46,7 +35,6 @@ func Resize(buf []byte, o Options) ([]byte, error) { inHeight := int(image.Ysize) // crop - if o.Crop { left, top := calculateCrop(inWidth, inHeight, o.Width, o.Height, o.Gravity) o.Width = int(math.Min(float64(inWidth), float64(o.Width))) @@ -55,31 +43,16 @@ func Resize(buf []byte, o Options) ([]byte, error) { if err != nil { return nil, err } - //err := C.vips_extract_area_0(image, &tmpImage, C.int(left), C.int(top), C.int(o.Width), C.int(o.Height)) - //C.g_object_unref(C.gpointer(image)) - //image = tmpImage } // rotate - r := Rotation{180} - image, err = Rotate(image, r) - if err != nil { - return nil, err + if o.Rotate > 0 { + image, err = Rotate(image, Rotation{o.Rotate}) + if err != nil { + return nil, err + } } - // Finally save - //var ptr unsafe.Pointer - //length := C.size_t(0) - - //C.vips_jpegsave_custom(image, &ptr, &length, 1, C.int(o.Quality), 0) - //C.g_object_unref(C.gpointer(image)) - //C.g_object_unref(C.gpointer(newImage)) - - // get back the buffer - //buf = C.GoBytes(ptr, C.int(length)) - // cleanup - //C.g_free(C.gpointer(ptr)) - buf, err = vipsSave(image, vipsSaveOptions{Quality: o.Quality}) if err != nil { return nil, err @@ -89,19 +62,6 @@ func Resize(buf []byte, o Options) ([]byte, error) { return buf, nil } -type Rotation struct { - angle int -} - -func (a Rotation) calculate() int { - angle := a.angle - divisor := angle % 90 - if divisor != 0 { - angle = a.angle - divisor - } - return angle -} - func Rotate(image *C.struct__VipsImage, r Rotation) (*C.struct__VipsImage, error) { //vips := &Vips{} return vipsRotate(image, r.calculate()) diff --git a/resize_test.go b/resize_test.go index b944b00..245d2fa 100644 --- a/resize_test.go +++ b/resize_test.go @@ -8,7 +8,7 @@ import ( ) func TestResize(t *testing.T) { - options := Options{Width: 800, Height: 600, Crop: false} + options := Options{Width: 800, Height: 600, Crop: false, Rotate: 270} img, err := os.Open("fixtures/space.jpg") if err != nil { t.Fatal(err) diff --git a/type.go b/type.go index cd26118..f0f6cfc 100644 --- a/type.go +++ b/type.go @@ -1,5 +1,14 @@ package bimg +const ( + UNKNOWN = "unknown" + JPEG = "jpeg" + WEBP = "webp" + PNG = "png" + TIFF = "tiff" + MAGICK = "magick" +) + type Type struct { Name string Mime string diff --git a/vips.go b/vips.go index baf24df..81aa0b9 100644 --- a/vips.go +++ b/vips.go @@ -9,6 +9,7 @@ import "C" import ( "errors" "runtime" + "strings" "unsafe" ) @@ -44,9 +45,24 @@ func vipsRotate(image *C.struct__VipsImage, degrees int) (*C.struct__VipsImage, return out, nil } +func vipsFlip(image *C.struct__VipsImage, direction Direction) (*C.struct__VipsImage, error) { + var out *C.struct__VipsImage + + err := C.vips_flip_seq(image, &out) + C.g_object_unref(C.gpointer(image)) + if err != 0 { + return nil, vipsError() + } + defer C.g_object_unref(C.gpointer(out)) + + return out, nil +} + func vipsRead(buf []byte) (*C.struct__VipsImage, error) { var image *C.struct__VipsImage + debug("Format: %s", vipsImageType(buf)) + // feed it length := C.size_t(len(buf)) imageBuf := unsafe.Pointer(&buf[0]) @@ -75,6 +91,34 @@ type vipsSaveOptions struct { Quality int } +func vipsImageType(buf []byte) string { + imageType := UNKNOWN + + length := C.size_t(len(buf)) + imageBuf := unsafe.Pointer(&buf[0]) + bufferType := C.GoString(C.vips_foreign_find_load_buffer(imageBuf, length)) + + switch { + case strings.HasSuffix(bufferType, "JpegBuffer"): + imageType = JPEG + break + case strings.HasSuffix(bufferType, "PngBuffer"): + imageType = PNG + break + case strings.HasSuffix(bufferType, "TiffBuffer"): + imageType = TIFF + break + case strings.HasSuffix(bufferType, "WebpBuffer"): + imageType = WEBP + break + case strings.HasSuffix(bufferType, "MagickBuffer"): + imageType = MAGICK + break + } + + return imageType +} + func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) { var ptr unsafe.Pointer length := C.size_t(0) diff --git a/vips.h b/vips.h index 7c28872..04eb31e 100644 --- a/vips.h +++ b/vips.h @@ -20,6 +20,13 @@ vips_jpegload_buffer_seq(void *buf, size_t len, VipsImage **out) return vips_jpegload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL); }; +VipsImage* +vips_image_buffer_seq(void *buf, size_t len) +{ + // todo: handle postclose callback + return vips_image_new_from_buffer(buf, len, "access", VIPS_ACCESS_SEQUENTIAL, NULL); +}; + int vips_jpegload_buffer_shrink(void *buf, size_t len, VipsImage **out, int shrink) { @@ -32,6 +39,12 @@ vips_webpload_buffer_seq(void *buf, size_t len, VipsImage **out) return vips_webpload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL); }; +int +vips_flip_seq(VipsImage *in, VipsImage **out) +{ + return vips_flip(in, out, VIPS_DIRECTION_HORIZONTAL, NULL); +}; + int vips_pngload_buffer_seq(void *buf, size_t len, VipsImage **out) { @@ -48,7 +61,7 @@ int vips_copy_0(VipsImage *in, VipsImage **out) { return vips_copy(in, out, NULL); -} +}; int vips_rotate(VipsImage *in, VipsImage **buf, int angle) @@ -64,13 +77,13 @@ vips_rotate(VipsImage *in, VipsImage **buf, int angle) } return vips_rot(in, buf, rotate, NULL); -} +}; int vips_embed_extend(VipsImage *in, VipsImage **out, int left, int top, int width, int height, int extend) { return vips_embed(in, out, left, top, width, height, "extend", extend, NULL); -} +}; int vips_colourspace_0(VipsImage *in, VipsImage **out, VipsInterpretation space) @@ -82,10 +95,10 @@ int vips_extract_area_0(VipsImage *in, VipsImage **out, int left, int top, int width, int height) { return vips_extract_area(in, out, left, top, width, height, NULL); -} +}; int vips_jpegsave_custom(VipsImage *in, void **buf, size_t *len, int strip, int quality, int interlace) { return vips_jpegsave_buffer(in, buf, len, "strip", strip, "Q", quality, "optimize_coding", TRUE, "interlace", interlace, NULL); -} +};