mirror of https://mirror.trustie.net/root/bimg.git
parent
885b315035
commit
d471c49348
50
image.go
50
image.go
|
@ -1,12 +1,46 @@
|
|||
package bimg
|
||||
|
||||
/*
|
||||
#cgo pkg-config: vips
|
||||
#include "vips/vips.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type Image struct {
|
||||
buf []byte
|
||||
image *C.struct__VipsImage
|
||||
buffer []byte
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
|
22
options.go
22
options.go
|
@ -22,18 +22,14 @@ func (i Interpolator) String() string {
|
|||
return interpolations[i]
|
||||
}
|
||||
|
||||
type Rotation struct {
|
||||
angle int
|
||||
}
|
||||
type Angle int
|
||||
|
||||
func (a Rotation) calculate() int {
|
||||
angle := a.angle
|
||||
divisor := angle % 90
|
||||
if divisor != 0 {
|
||||
angle = a.angle - divisor
|
||||
}
|
||||
return angle
|
||||
}
|
||||
const (
|
||||
D0 Angle = C.VIPS_ANGLE_D0
|
||||
D90 Angle = C.VIPS_ANGLE_D90
|
||||
D180 Angle = C.VIPS_ANGLE_D180
|
||||
D270 Angle = C.VIPS_ANGLE_D270
|
||||
)
|
||||
|
||||
type Direction int
|
||||
|
||||
|
@ -45,12 +41,14 @@ const (
|
|||
type Options struct {
|
||||
Height int
|
||||
Width int
|
||||
Top int
|
||||
Left int
|
||||
Crop bool
|
||||
Enlarge bool
|
||||
Extend int
|
||||
Embed bool
|
||||
Quality int
|
||||
Rotate int
|
||||
Rotate Angle
|
||||
Flip Direction
|
||||
Gravity Gravity
|
||||
Interpolator Interpolator
|
||||
|
|
96
resize.go
96
resize.go
|
@ -16,8 +16,15 @@ const (
|
|||
NOHALO
|
||||
)
|
||||
|
||||
const (
|
||||
CENTRE Gravity = iota
|
||||
NORTH
|
||||
EAST
|
||||
SOUTH
|
||||
WEST
|
||||
)
|
||||
|
||||
func Resize(buf []byte, o Options) ([]byte, error) {
|
||||
// detect (if possible) the file type
|
||||
defer C.vips_thread_shutdown()
|
||||
|
||||
image, err := vipsRead(buf)
|
||||
|
@ -34,7 +41,6 @@ func Resize(buf []byte, o Options) ([]byte, error) {
|
|||
inWidth := int(image.Xsize)
|
||||
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)))
|
||||
|
@ -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 {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -62,21 +83,9 @@ func Resize(buf []byte, o Options) ([]byte, error) {
|
|||
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) {
|
||||
left, top := 0, 0
|
||||
|
||||
switch gravity {
|
||||
case NORTH:
|
||||
left = (inWidth - outWidth + 1) / 2
|
||||
|
@ -92,5 +101,58 @@ func calculateCrop(inWidth, inHeight, outWidth, outHeight int, gravity Gravity)
|
|||
left = (inWidth - outWidth + 1) / 2
|
||||
top = (inHeight - outHeight + 1) / 2
|
||||
}
|
||||
|
||||
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
23
vips.go
|
@ -13,7 +13,7 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
type vipsImage *C.struct__VipsImage
|
||||
type vipsImage C.struct__VipsImage
|
||||
|
||||
func init() {
|
||||
runtime.LockOSThread()
|
||||
|
@ -34,13 +34,13 @@ type Vips struct {
|
|||
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
|
||||
|
||||
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))
|
||||
if err != 0 {
|
||||
return nil, vipsError()
|
||||
return nil, catchVipsError()
|
||||
}
|
||||
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)
|
||||
C.g_object_unref(C.gpointer(image))
|
||||
if err != 0 {
|
||||
return nil, vipsError()
|
||||
return nil, catchVipsError()
|
||||
}
|
||||
defer C.g_object_unref(C.gpointer(out))
|
||||
|
||||
|
@ -74,9 +74,8 @@ func vipsRead(buf []byte) (*C.struct__VipsImage, error) {
|
|||
imageTypeC := C.int(imageType)
|
||||
|
||||
err := C.vips_init_image(imageBuf, length, imageTypeC, &image)
|
||||
//err := C.vips_jpegload_buffer_seq(imageBuf, length, &image)
|
||||
if err != 0 {
|
||||
return nil, vipsError()
|
||||
return nil, catchVipsError()
|
||||
}
|
||||
|
||||
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))
|
||||
C.g_object_unref(C.gpointer(image))
|
||||
if err != 0 {
|
||||
return nil, vipsError()
|
||||
return nil, catchVipsError()
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
|
@ -122,6 +121,10 @@ func vipsImageType(buf []byte) int {
|
|||
return imageType
|
||||
}
|
||||
|
||||
func vipsExifOrientation(image *C.struct__VipsImage) int {
|
||||
return int(C.vips_exif_orientation(image))
|
||||
}
|
||||
|
||||
type vipsSaveOptions struct {
|
||||
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)
|
||||
if err != 0 {
|
||||
return nil, vipsError()
|
||||
return nil, catchVipsError()
|
||||
}
|
||||
C.g_object_unref(C.gpointer(image))
|
||||
|
||||
|
@ -143,7 +146,7 @@ func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
|
|||
return buf, nil
|
||||
}
|
||||
|
||||
func vipsError() error {
|
||||
func catchVipsError() error {
|
||||
s := C.GoString(C.vips_error_buffer())
|
||||
C.vips_error_clear()
|
||||
C.vips_thread_shutdown()
|
||||
|
|
24
vips.h
24
vips.h
|
@ -11,6 +11,12 @@ enum types {
|
|||
MAGICK
|
||||
};
|
||||
|
||||
void
|
||||
vips_malloc_cb(VipsObject *object, char *buf)
|
||||
{
|
||||
g_free(buf);
|
||||
};
|
||||
|
||||
int
|
||||
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
|
||||
}
|
||||
|
||||
if (out != NULL) {
|
||||
// Listen for "postclose" signal to delete input buffer
|
||||
//g_signal_connect(out, "postclose", G_CALLBACK(vips_malloc_cb), buf);
|
||||
}
|
||||
|
||||
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
|
||||
vips_embed_extend(VipsImage *in, VipsImage **out, int left, int top, int width, int height, int extend)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue