This commit is contained in:
Tomas Aparicio 2015-04-05 22:01:48 +02:00
parent 885b315035
commit d471c49348
5 changed files with 168 additions and 47 deletions

View file

@ -1,12 +1,46 @@
package bimg package bimg
/*
#cgo pkg-config: vips
#include "vips/vips.h"
*/
import "C"
type Image struct { type Image struct {
buf []byte buffer []byte
image *C.struct__VipsImage }
func (i *Image) Resize(width int, height int) ([]byte, error) {
options := Options{
Width: width,
Height: height,
}
return Resize(i.buffer, options)
}
func (i *Image) Extract(top int, left int, width int, height int) ([]byte, error) {
options := Options{
Width: width,
Height: height,
Top: top,
Left: left,
}
return Resize(i.buffer, options)
}
func (i *Image) Rotate(degrees Angle) ([]byte, error) {
options := Options{Rotate: degrees}
return Resize(i.buffer, options)
}
func (i *Image) Flip() ([]byte, error) {
options := Options{Flip: VERTICAL}
return Resize(i.buffer, options)
}
func (i *Image) Flop() ([]byte, error) {
options := Options{Flip: HORIZONTAL}
return Resize(i.buffer, options)
}
func (i *Image) Type() string {
return DetermineImageTypeName(i.buffer)
}
func NewImage(buf []byte) *Image {
return &Image{buf}
} }

View file

@ -22,18 +22,14 @@ func (i Interpolator) String() string {
return interpolations[i] return interpolations[i]
} }
type Rotation struct { type Angle int
angle int
}
func (a Rotation) calculate() int { const (
angle := a.angle D0 Angle = C.VIPS_ANGLE_D0
divisor := angle % 90 D90 Angle = C.VIPS_ANGLE_D90
if divisor != 0 { D180 Angle = C.VIPS_ANGLE_D180
angle = a.angle - divisor D270 Angle = C.VIPS_ANGLE_D270
} )
return angle
}
type Direction int type Direction int
@ -45,12 +41,14 @@ const (
type Options struct { type Options struct {
Height int Height int
Width int Width int
Top int
Left int
Crop bool Crop bool
Enlarge bool Enlarge bool
Extend int Extend int
Embed bool Embed bool
Quality int Quality int
Rotate int Rotate Angle
Flip Direction Flip Direction
Gravity Gravity Gravity Gravity
Interpolator Interpolator Interpolator Interpolator

View file

@ -16,8 +16,15 @@ const (
NOHALO NOHALO
) )
const (
CENTRE Gravity = iota
NORTH
EAST
SOUTH
WEST
)
func Resize(buf []byte, o Options) ([]byte, error) { func Resize(buf []byte, o Options) ([]byte, error) {
// detect (if possible) the file type
defer C.vips_thread_shutdown() defer C.vips_thread_shutdown()
image, err := vipsRead(buf) image, err := vipsRead(buf)
@ -34,7 +41,6 @@ func Resize(buf []byte, o Options) ([]byte, error) {
inWidth := int(image.Xsize) inWidth := int(image.Xsize)
inHeight := int(image.Ysize) inHeight := int(image.Ysize)
// crop
if o.Crop { if o.Crop {
left, top := calculateCrop(inWidth, inHeight, o.Width, o.Height, o.Gravity) left, top := calculateCrop(inWidth, inHeight, o.Width, o.Height, o.Gravity)
o.Width = int(math.Min(float64(inWidth), float64(o.Width))) o.Width = int(math.Min(float64(inWidth), float64(o.Width)))
@ -45,9 +51,24 @@ func Resize(buf []byte, o Options) ([]byte, error) {
} }
} }
// rotate rotation, flip := calculateRotationAndFlip(image, o.Rotate)
if flip {
o.Flip = HORIZONTAL
}
if rotation != D0 {
o.Rotate = rotation
}
if o.Rotate > 0 { if o.Rotate > 0 {
image, err = Rotate(image, Rotation{o.Rotate}) rotation := calculateRotation(o.Rotate)
image, err = vipsRotate(image, rotation)
if err != nil {
return nil, err
}
}
if o.Flip > 0 {
image, err = vipsFlip(image, o.Flip)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -62,21 +83,9 @@ func Resize(buf []byte, o Options) ([]byte, error) {
return buf, nil return buf, nil
} }
func Rotate(image *C.struct__VipsImage, r Rotation) (*C.struct__VipsImage, error) {
//vips := &Vips{}
return vipsRotate(image, r.calculate())
}
const (
CENTRE Gravity = iota
NORTH
EAST
SOUTH
WEST
)
func calculateCrop(inWidth, inHeight, outWidth, outHeight int, gravity Gravity) (int, int) { func calculateCrop(inWidth, inHeight, outWidth, outHeight int, gravity Gravity) (int, int) {
left, top := 0, 0 left, top := 0, 0
switch gravity { switch gravity {
case NORTH: case NORTH:
left = (inWidth - outWidth + 1) / 2 left = (inWidth - outWidth + 1) / 2
@ -92,5 +101,58 @@ func calculateCrop(inWidth, inHeight, outWidth, outHeight int, gravity Gravity)
left = (inWidth - outWidth + 1) / 2 left = (inWidth - outWidth + 1) / 2
top = (inHeight - outHeight + 1) / 2 top = (inHeight - outHeight + 1) / 2
} }
return left, top return left, top
} }
func calculateRotationAndFlip(image *C.struct__VipsImage, angle Angle) (Angle, bool) {
rotate := D0
flip := false
if angle == -1 {
switch vipsExifOrientation(image) {
case 6:
rotate = D90
break
case 3:
rotate = D180
break
case 8:
rotate = D270
break
case 2:
flip = true
break // flip 1
case 7:
flip = true
rotate = D90
break // flip 6
case 4:
flip = true
rotate = D180
break // flip 3
case 5:
flip = true
rotate = D270
break // flip 8
}
} else {
if angle == 90 {
rotate = D90
} else if angle == 180 {
rotate = D180
} else if angle == 270 {
rotate = D270
}
}
return rotate, flip
}
func calculateRotation(angle Angle) Angle {
divisor := angle % 90
if divisor != 0 {
angle = angle - divisor
}
return angle
}

23
vips.go
View file

@ -13,7 +13,7 @@ import (
"unsafe" "unsafe"
) )
type vipsImage *C.struct__VipsImage type vipsImage C.struct__VipsImage
func init() { func init() {
runtime.LockOSThread() runtime.LockOSThread()
@ -34,13 +34,13 @@ type Vips struct {
buf []byte buf []byte
} }
func vipsRotate(image *C.struct__VipsImage, degrees int) (*C.struct__VipsImage, error) { func vipsRotate(image *C.struct__VipsImage, angle Angle) (*C.struct__VipsImage, error) {
var out *C.struct__VipsImage var out *C.struct__VipsImage
err := C.vips_rotate(image, &out, C.int(degrees)) err := C.vips_rotate(image, &out, C.int(angle))
C.g_object_unref(C.gpointer(image)) C.g_object_unref(C.gpointer(image))
if err != 0 { if err != 0 {
return nil, vipsError() return nil, catchVipsError()
} }
defer C.g_object_unref(C.gpointer(out)) defer C.g_object_unref(C.gpointer(out))
@ -53,7 +53,7 @@ func vipsFlip(image *C.struct__VipsImage, direction Direction) (*C.struct__VipsI
err := C.vips_flip_seq(image, &out) err := C.vips_flip_seq(image, &out)
C.g_object_unref(C.gpointer(image)) C.g_object_unref(C.gpointer(image))
if err != 0 { if err != 0 {
return nil, vipsError() return nil, catchVipsError()
} }
defer C.g_object_unref(C.gpointer(out)) defer C.g_object_unref(C.gpointer(out))
@ -74,9 +74,8 @@ func vipsRead(buf []byte) (*C.struct__VipsImage, error) {
imageTypeC := C.int(imageType) imageTypeC := C.int(imageType)
err := C.vips_init_image(imageBuf, length, imageTypeC, &image) err := C.vips_init_image(imageBuf, length, imageTypeC, &image)
//err := C.vips_jpegload_buffer_seq(imageBuf, length, &image)
if err != 0 { if err != 0 {
return nil, vipsError() return nil, catchVipsError()
} }
return image, nil return image, nil
@ -88,7 +87,7 @@ func vipsExtract(image *C.struct__VipsImage, left int, top int, width int, heigh
err := C.vips_extract_area_0(image, &buf, C.int(left), C.int(top), C.int(width), C.int(height)) err := C.vips_extract_area_0(image, &buf, C.int(left), C.int(top), C.int(width), C.int(height))
C.g_object_unref(C.gpointer(image)) C.g_object_unref(C.gpointer(image))
if err != 0 { if err != 0 {
return nil, vipsError() return nil, catchVipsError()
} }
return buf, nil return buf, nil
@ -122,6 +121,10 @@ func vipsImageType(buf []byte) int {
return imageType return imageType
} }
func vipsExifOrientation(image *C.struct__VipsImage) int {
return int(C.vips_exif_orientation(image))
}
type vipsSaveOptions struct { type vipsSaveOptions struct {
Quality int Quality int
} }
@ -132,7 +135,7 @@ func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
err := C.vips_jpegsave_custom(image, &ptr, &length, 1, C.int(o.Quality), 0) err := C.vips_jpegsave_custom(image, &ptr, &length, 1, C.int(o.Quality), 0)
if err != 0 { if err != 0 {
return nil, vipsError() return nil, catchVipsError()
} }
C.g_object_unref(C.gpointer(image)) C.g_object_unref(C.gpointer(image))
@ -143,7 +146,7 @@ func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
return buf, nil return buf, nil
} }
func vipsError() error { func catchVipsError() error {
s := C.GoString(C.vips_error_buffer()) s := C.GoString(C.vips_error_buffer())
C.vips_error_clear() C.vips_error_clear()
C.vips_thread_shutdown() C.vips_thread_shutdown()

24
vips.h
View file

@ -11,6 +11,12 @@ enum types {
MAGICK MAGICK
}; };
void
vips_malloc_cb(VipsObject *object, char *buf)
{
g_free(buf);
};
int int
vips_affine_interpolator(VipsImage *in, VipsImage **out, double a, double b, double c, double d, VipsInterpolate *interpolator) vips_affine_interpolator(VipsImage *in, VipsImage **out, double a, double b, double c, double d, VipsInterpolate *interpolator)
{ {
@ -94,9 +100,27 @@ vips_init_image(void *buf, size_t len, int imageType, VipsImage **out) {
#endif #endif
} }
if (out != NULL) {
// Listen for "postclose" signal to delete input buffer
//g_signal_connect(out, "postclose", G_CALLBACK(vips_malloc_cb), buf);
}
return code; return code;
}; };
int
vips_exif_orientation(VipsImage *image) {
int orientation = 0;
const char **exif;
if (
vips_image_get_typeof(image, "exif-ifd0-Orientation") != 0 &&
!vips_image_get_string(image, "exif-ifd0-Orientation", exif)
) {
orientation = atoi(exif[0]);
}
return orientation;
};
int int
vips_embed_extend(VipsImage *in, VipsImage **out, int left, int top, int width, int height, int extend) vips_embed_extend(VipsImage *in, VipsImage **out, int left, int top, int width, int height, int extend)
{ {