mirror of
https://github.com/talgo-cloud/bimg.git
synced 2026-03-16 10:55:54 -07:00
parent
63f4b01c8d
commit
61997bc68b
7 changed files with 107 additions and 53 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 64 KiB |
32
options.go
32
options.go
|
|
@ -1,5 +1,11 @@
|
||||||
package bimg
|
package bimg
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo pkg-config: vips
|
||||||
|
#include "vips/vips.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
const QUALITY = 80
|
const QUALITY = 80
|
||||||
|
|
||||||
type Gravity int
|
type Gravity int
|
||||||
|
|
@ -16,6 +22,26 @@ func (i Interpolator) String() string {
|
||||||
return interpolations[i]
|
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 {
|
type Options struct {
|
||||||
Height int
|
Height int
|
||||||
Width int
|
Width int
|
||||||
|
|
@ -23,7 +49,9 @@ type Options struct {
|
||||||
Enlarge bool
|
Enlarge bool
|
||||||
Extend int
|
Extend int
|
||||||
Embed bool
|
Embed bool
|
||||||
Interpolator Interpolator
|
|
||||||
Gravity Gravity
|
|
||||||
Quality int
|
Quality int
|
||||||
|
Rotate int
|
||||||
|
Flip Direction
|
||||||
|
Gravity Gravity
|
||||||
|
Interpolator Interpolator
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
resize.go
50
resize.go
|
|
@ -18,7 +18,6 @@ const (
|
||||||
|
|
||||||
func Resize(buf []byte, o Options) ([]byte, error) {
|
func Resize(buf []byte, o Options) ([]byte, error) {
|
||||||
// detect (if possible) the file type
|
// detect (if possible) the file type
|
||||||
|
|
||||||
defer C.vips_thread_shutdown()
|
defer C.vips_thread_shutdown()
|
||||||
|
|
||||||
image, err := vipsRead(buf)
|
image, err := vipsRead(buf)
|
||||||
|
|
@ -26,16 +25,6 @@ func Resize(buf []byte, o Options) ([]byte, error) {
|
||||||
return nil, err
|
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
|
// defaults
|
||||||
if o.Quality == 0 {
|
if o.Quality == 0 {
|
||||||
o.Quality = QUALITY
|
o.Quality = QUALITY
|
||||||
|
|
@ -46,7 +35,6 @@ func Resize(buf []byte, o Options) ([]byte, error) {
|
||||||
inHeight := int(image.Ysize)
|
inHeight := int(image.Ysize)
|
||||||
|
|
||||||
// crop
|
// 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)))
|
||||||
|
|
@ -55,31 +43,16 @@ func Resize(buf []byte, o Options) ([]byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// rotate
|
||||||
r := Rotation{180}
|
if o.Rotate > 0 {
|
||||||
image, err = Rotate(image, r)
|
image, err = Rotate(image, Rotation{o.Rotate})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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})
|
buf, err = vipsSave(image, vipsSaveOptions{Quality: o.Quality})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -89,19 +62,6 @@ func Resize(buf []byte, o Options) ([]byte, error) {
|
||||||
return buf, nil
|
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) {
|
func Rotate(image *C.struct__VipsImage, r Rotation) (*C.struct__VipsImage, error) {
|
||||||
//vips := &Vips{}
|
//vips := &Vips{}
|
||||||
return vipsRotate(image, r.calculate())
|
return vipsRotate(image, r.calculate())
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResize(t *testing.T) {
|
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")
|
img, err := os.Open("fixtures/space.jpg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
9
type.go
9
type.go
|
|
@ -1,5 +1,14 @@
|
||||||
package bimg
|
package bimg
|
||||||
|
|
||||||
|
const (
|
||||||
|
UNKNOWN = "unknown"
|
||||||
|
JPEG = "jpeg"
|
||||||
|
WEBP = "webp"
|
||||||
|
PNG = "png"
|
||||||
|
TIFF = "tiff"
|
||||||
|
MAGICK = "magick"
|
||||||
|
)
|
||||||
|
|
||||||
type Type struct {
|
type Type struct {
|
||||||
Name string
|
Name string
|
||||||
Mime string
|
Mime string
|
||||||
|
|
|
||||||
44
vips.go
44
vips.go
|
|
@ -9,6 +9,7 @@ import "C"
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,9 +45,24 @@ func vipsRotate(image *C.struct__VipsImage, degrees int) (*C.struct__VipsImage,
|
||||||
return out, nil
|
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) {
|
func vipsRead(buf []byte) (*C.struct__VipsImage, error) {
|
||||||
var image *C.struct__VipsImage
|
var image *C.struct__VipsImage
|
||||||
|
|
||||||
|
debug("Format: %s", vipsImageType(buf))
|
||||||
|
|
||||||
// feed it
|
// feed it
|
||||||
length := C.size_t(len(buf))
|
length := C.size_t(len(buf))
|
||||||
imageBuf := unsafe.Pointer(&buf[0])
|
imageBuf := unsafe.Pointer(&buf[0])
|
||||||
|
|
@ -75,6 +91,34 @@ type vipsSaveOptions struct {
|
||||||
Quality int
|
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) {
|
func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
|
||||||
var ptr unsafe.Pointer
|
var ptr unsafe.Pointer
|
||||||
length := C.size_t(0)
|
length := C.size_t(0)
|
||||||
|
|
|
||||||
23
vips.h
23
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);
|
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
|
int
|
||||||
vips_jpegload_buffer_shrink(void *buf, size_t len, VipsImage **out, int shrink)
|
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);
|
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
|
int
|
||||||
vips_pngload_buffer_seq(void *buf, size_t len, VipsImage **out)
|
vips_pngload_buffer_seq(void *buf, size_t len, VipsImage **out)
|
||||||
{
|
{
|
||||||
|
|
@ -48,7 +61,7 @@ int
|
||||||
vips_copy_0(VipsImage *in, VipsImage **out)
|
vips_copy_0(VipsImage *in, VipsImage **out)
|
||||||
{
|
{
|
||||||
return vips_copy(in, out, NULL);
|
return vips_copy(in, out, NULL);
|
||||||
}
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
vips_rotate(VipsImage *in, VipsImage **buf, int angle)
|
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);
|
return vips_rot(in, buf, rotate, NULL);
|
||||||
}
|
};
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
return vips_embed(in, out, left, top, width, height, "extend", extend, NULL);
|
return vips_embed(in, out, left, top, width, height, "extend", extend, NULL);
|
||||||
}
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
vips_colourspace_0(VipsImage *in, VipsImage **out, VipsInterpretation space)
|
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)
|
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);
|
return vips_extract_area(in, out, left, top, width, height, NULL);
|
||||||
}
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
vips_jpegsave_custom(VipsImage *in, void **buf, size_t *len, int strip, int quality, int interlace)
|
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);
|
return vips_jpegsave_buffer(in, buf, len, "strip", strip, "Q", quality, "optimize_coding", TRUE, "interlace", interlace, NULL);
|
||||||
}
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue