mirror of
https://github.com/talgo-cloud/bimg.git
synced 2026-03-15 18:35:54 -07:00
parent
b93919d182
commit
16576f49c9
6 changed files with 170 additions and 52 deletions
|
|
@ -6,7 +6,7 @@ bimg is designed to be a small and efficient library with a generic and useful s
|
||||||
It uses internally libvips, which requires a [low memory footprint](http://www.vips.ecs.soton.ac.uk/index.php?title=Speed_and_Memory_Use)
|
It uses internally libvips, which requires a [low memory footprint](http://www.vips.ecs.soton.ac.uk/index.php?title=Speed_and_Memory_Use)
|
||||||
and it's typically 4x faster than using the quickest ImageMagick and GraphicsMagick settings or Go native `image` package, and in some cases it's even 8x faster processing JPEG images.
|
and it's typically 4x faster than using the quickest ImageMagick and GraphicsMagick settings or Go native `image` package, and in some cases it's even 8x faster processing JPEG images.
|
||||||
|
|
||||||
It can read JPEG, PNG, WEBP, TIFF and Magick formats and it can output to JPEG, PNG and WEBP. It supports common [image transformation](#supported-image-operations) operations such as crop, resize, rotate... and conversion between multiple formats.
|
It can read JPEG, PNG, WEBP and TIFF formats and output to JPEG, PNG and WEBP. It supports common [image transformation](#supported-image-operations) operations such as crop, resize, rotate... and conversion between multiple formats.
|
||||||
|
|
||||||
For getting started, take a look to the [examples](#examples) and [programmatic API](https://godoc.org/github.com/h2non/bimg) documentation.
|
For getting started, take a look to the [examples](#examples) and [programmatic API](https://godoc.org/github.com/h2non/bimg) documentation.
|
||||||
|
|
||||||
|
|
|
||||||
48
image.go
48
image.go
|
|
@ -4,6 +4,7 @@ type Image struct {
|
||||||
buffer []byte
|
buffer []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize the image to fixed width and height
|
||||||
func (i *Image) Resize(width, height int) ([]byte, error) {
|
func (i *Image) Resize(width, height int) ([]byte, error) {
|
||||||
options := Options{
|
options := Options{
|
||||||
Width: width,
|
Width: width,
|
||||||
|
|
@ -12,6 +13,7 @@ func (i *Image) Resize(width, height int) ([]byte, error) {
|
||||||
return i.Process(options)
|
return i.Process(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract area from the by X/Y axis
|
||||||
func (i *Image) Extract(top, left, width, height int) ([]byte, error) {
|
func (i *Image) Extract(top, left, width, height int) ([]byte, error) {
|
||||||
options := Options{
|
options := Options{
|
||||||
Top: top,
|
Top: top,
|
||||||
|
|
@ -22,6 +24,17 @@ func (i *Image) Extract(top, left, width, height int) ([]byte, error) {
|
||||||
return i.Process(options)
|
return i.Process(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enlarge the image from the by X/Y axis
|
||||||
|
func (i *Image) Enlarge(width, height int) ([]byte, error) {
|
||||||
|
options := Options{
|
||||||
|
Width: width,
|
||||||
|
Height: height,
|
||||||
|
Enlarge: true,
|
||||||
|
}
|
||||||
|
return i.Process(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crop an image by width and height
|
||||||
func (i *Image) Crop(width, height int) ([]byte, error) {
|
func (i *Image) Crop(width, height int) ([]byte, error) {
|
||||||
options := Options{
|
options := Options{
|
||||||
Width: width,
|
Width: width,
|
||||||
|
|
@ -31,6 +44,25 @@ func (i *Image) Crop(width, height int) ([]byte, error) {
|
||||||
return i.Process(options)
|
return i.Process(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crop an image by width (auto height)
|
||||||
|
func (i *Image) CropByWidth(width int) ([]byte, error) {
|
||||||
|
options := Options{
|
||||||
|
Width: width,
|
||||||
|
Crop: true,
|
||||||
|
}
|
||||||
|
return i.Process(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crop an image by height (auto width)
|
||||||
|
func (i *Image) CropByHeight(height int) ([]byte, error) {
|
||||||
|
options := Options{
|
||||||
|
Height: height,
|
||||||
|
Crop: true,
|
||||||
|
}
|
||||||
|
return i.Process(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thumbnail the image by the a given width by aspect ratio 4:4
|
||||||
func (i *Image) Thumbnail(pixels int) ([]byte, error) {
|
func (i *Image) Thumbnail(pixels int) ([]byte, error) {
|
||||||
options := Options{
|
options := Options{
|
||||||
Width: pixels,
|
Width: pixels,
|
||||||
|
|
@ -41,21 +73,25 @@ func (i *Image) Thumbnail(pixels int) ([]byte, error) {
|
||||||
return i.Process(options)
|
return i.Process(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rotate the image by given angle degrees (0, 90, 180 or 270)
|
||||||
func (i *Image) Rotate(a Angle) ([]byte, error) {
|
func (i *Image) Rotate(a Angle) ([]byte, error) {
|
||||||
options := Options{Rotate: a}
|
options := Options{Rotate: a}
|
||||||
return i.Process(options)
|
return i.Process(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flip the image about the vertical Y axis
|
||||||
func (i *Image) Flip() ([]byte, error) {
|
func (i *Image) Flip() ([]byte, error) {
|
||||||
options := Options{Flip: VERTICAL}
|
options := Options{Flip: VERTICAL}
|
||||||
return i.Process(options)
|
return i.Process(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flop the image about the horizontal X axis
|
||||||
func (i *Image) Convert(t ImageType) ([]byte, error) {
|
func (i *Image) Convert(t ImageType) ([]byte, error) {
|
||||||
options := Options{Type: t}
|
options := Options{Type: t}
|
||||||
return i.Process(options)
|
return i.Process(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform the image by custom options
|
||||||
func (i *Image) Process(o Options) ([]byte, error) {
|
func (i *Image) Process(o Options) ([]byte, error) {
|
||||||
image, err := Resize(i.buffer, o)
|
image, err := Resize(i.buffer, o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -65,18 +101,22 @@ func (i *Image) Process(o Options) ([]byte, error) {
|
||||||
return image, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) Type() string {
|
// Get image metadata (size, alpha channel, profile, EXIF rotation)
|
||||||
return DetermineImageTypeName(i.buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Image) Metadata() (ImageMetadata, error) {
|
func (i *Image) Metadata() (ImageMetadata, error) {
|
||||||
return Metadata(i.buffer)
|
return Metadata(i.buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get image type format (jpeg, png, webp, tiff)
|
||||||
|
func (i *Image) Type() string {
|
||||||
|
return DetermineImageTypeName(i.buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get image size
|
||||||
func (i *Image) Size() (ImageSize, error) {
|
func (i *Image) Size() (ImageSize, error) {
|
||||||
return Size(i.buffer)
|
return Size(i.buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a new image
|
||||||
func NewImage(buf []byte) *Image {
|
func NewImage(buf []byte) *Image {
|
||||||
return &Image{buf}
|
return &Image{buf}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ func TestImageResize(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Cannot process the image: %#v", err)
|
t.Errorf("Cannot process the image: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if assertSize(buf, 300, 240) {
|
||||||
|
t.Error("Invalid image size")
|
||||||
|
}
|
||||||
|
|
||||||
Write("fixtures/test_resize_out.jpg", buf)
|
Write("fixtures/test_resize_out.jpg", buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18,17 +23,79 @@ func TestImageExtract(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Cannot process the image: %#v", err)
|
t.Errorf("Cannot process the image: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if assertSize(buf, 300, 300) {
|
||||||
|
t.Error("Invalid image size")
|
||||||
|
}
|
||||||
|
|
||||||
Write("fixtures/test_extract_out.jpg", buf)
|
Write("fixtures/test_extract_out.jpg", buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImageEnlarge(t *testing.T) {
|
||||||
|
buf, err := initImage("test.png").Enlarge(500, 380)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Cannot process the image: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if assertSize(buf, 500, 380) {
|
||||||
|
t.Error("Invalid image size")
|
||||||
|
}
|
||||||
|
|
||||||
|
Write("fixtures/test_enlarge_out.jpg", buf)
|
||||||
|
}
|
||||||
|
|
||||||
func TestImageCrop(t *testing.T) {
|
func TestImageCrop(t *testing.T) {
|
||||||
buf, err := initImage("test.jpg").Crop(800, 600)
|
buf, err := initImage("test.jpg").Crop(800, 600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Cannot process the image: %#v", err)
|
t.Errorf("Cannot process the image: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if assertSize(buf, 800, 600) {
|
||||||
|
t.Error("Invalid image size")
|
||||||
|
}
|
||||||
|
|
||||||
Write("fixtures/test_crop_out.jpg", buf)
|
Write("fixtures/test_crop_out.jpg", buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImageCropByWidth(t *testing.T) {
|
||||||
|
buf, err := initImage("test.jpg").CropByWidth(600)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Cannot process the image: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if assertSize(buf, 600, 375) {
|
||||||
|
t.Error("Invalid image size")
|
||||||
|
}
|
||||||
|
|
||||||
|
Write("fixtures/test_crop_width_out.jpg", buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImageCropByHeight(t *testing.T) {
|
||||||
|
buf, err := initImage("test.jpg").CropByHeight(300)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Cannot process the image: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if assertSize(buf, 800, 480) {
|
||||||
|
t.Error("Invalid image size")
|
||||||
|
}
|
||||||
|
|
||||||
|
Write("fixtures/test_crop_height_out.jpg", buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImageThumbnail(t *testing.T) {
|
||||||
|
buf, err := initImage("test.jpg").Thumbnail(100)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Cannot process the image: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if assertSize(buf, 100, 100) {
|
||||||
|
t.Error("Invalid image size")
|
||||||
|
}
|
||||||
|
|
||||||
|
Write("fixtures/test_thumbnail_out.jpg", buf)
|
||||||
|
}
|
||||||
|
|
||||||
func TestImageFlip(t *testing.T) {
|
func TestImageFlip(t *testing.T) {
|
||||||
buf, err := initImage("test.jpg").Flip()
|
buf, err := initImage("test.jpg").Flip()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -37,14 +104,6 @@ func TestImageFlip(t *testing.T) {
|
||||||
Write("fixtures/test_flip_out.jpg", buf)
|
Write("fixtures/test_flip_out.jpg", buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImageThumbnail(t *testing.T) {
|
|
||||||
buf, err := initImage("test.jpg").Thumbnail(100)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Cannot process the image: %#v", err)
|
|
||||||
}
|
|
||||||
Write("fixtures/test_thumbnail_out.jpg", buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImageRotate(t *testing.T) {
|
func TestImageRotate(t *testing.T) {
|
||||||
buf, err := initImage("test_flip_out.jpg").Rotate(90)
|
buf, err := initImage("test_flip_out.jpg").Rotate(90)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -81,3 +140,14 @@ func initImage(file string) *Image {
|
||||||
buf, _ := Read(path.Join("fixtures", file))
|
buf, _ := Read(path.Join("fixtures", file))
|
||||||
return NewImage(buf)
|
return NewImage(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertSize(buf []byte, width, height int) bool {
|
||||||
|
size, err := NewImage(buf).Size()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if size.Width != 220 || size.Height != 300 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,14 +45,14 @@ func Resize(buf []byte, o Options) ([]byte, error) {
|
||||||
inHeight := int(image.Ysize)
|
inHeight := int(image.Ysize)
|
||||||
|
|
||||||
// image calculations
|
// image calculations
|
||||||
factor := imageCalculations(o, inWidth, inHeight)
|
factor := imageCalculations(&o, inWidth, inHeight)
|
||||||
shrink := int(math.Max(math.Floor(factor), 1))
|
shrink := int(math.Max(math.Floor(factor), 1))
|
||||||
residual := float64(shrink) / factor
|
residual := float64(shrink) / factor
|
||||||
|
|
||||||
// Do not enlarge the output if the input width *or* height are already less than the required dimensions
|
// Do not enlarge the output if the input width *or* height are already less than the required dimensions
|
||||||
if o.Enlarge == false {
|
if o.Enlarge == false {
|
||||||
if inWidth < o.Width && inHeight < o.Height {
|
if inWidth < o.Width && inHeight < o.Height {
|
||||||
factor = 1
|
factor = 1.0
|
||||||
shrink = 1
|
shrink = 1
|
||||||
residual = 0
|
residual = 0
|
||||||
o.Width = inWidth
|
o.Width = inWidth
|
||||||
|
|
@ -169,7 +169,6 @@ func rotateImage(image *C.struct__VipsImage, o Options) (*C.struct__VipsImage, e
|
||||||
if o.Rotate > 0 {
|
if o.Rotate > 0 {
|
||||||
image, err = vipsRotate(image, getAngle(o.Rotate))
|
image, err = vipsRotate(image, getAngle(o.Rotate))
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.Flip > 0 {
|
if o.Flip > 0 {
|
||||||
image, err = vipsFlip(image, o.Flip)
|
image, err = vipsFlip(image, o.Flip)
|
||||||
}
|
}
|
||||||
|
|
@ -223,7 +222,7 @@ func shrinkJpegImage(buf []byte, input *C.struct__VipsImage, factor float64, shr
|
||||||
return image, factor, err
|
return image, factor, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func imageCalculations(o Options, inWidth, inHeight int) float64 {
|
func imageCalculations(o *Options, inWidth, inHeight int) float64 {
|
||||||
factor := 1.0
|
factor := 1.0
|
||||||
xfactor := float64(inWidth) / float64(o.Width)
|
xfactor := float64(inWidth) / float64(o.Width)
|
||||||
yfactor := float64(inHeight) / float64(o.Height)
|
yfactor := float64(inHeight) / float64(o.Height)
|
||||||
|
|
|
||||||
77
vips.go
77
vips.go
|
|
@ -8,7 +8,6 @@ import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
//"fmt"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -20,44 +19,51 @@ var (
|
||||||
initialized bool = false
|
initialized bool = false
|
||||||
)
|
)
|
||||||
|
|
||||||
type vipsImage C.struct__VipsImage
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runtime.LockOSThread()
|
|
||||||
defer runtime.UnlockOSThread()
|
|
||||||
|
|
||||||
if C.VIPS_MAJOR_VERSION <= 7 && C.VIPS_MINOR_VERSION < 40 {
|
if C.VIPS_MAJOR_VERSION <= 7 && C.VIPS_MINOR_VERSION < 40 {
|
||||||
panic("unsupported old vips version")
|
panic("unsupported old vips version!")
|
||||||
}
|
}
|
||||||
|
|
||||||
Initialize()
|
Initialize()
|
||||||
|
|
||||||
C.vips_concurrency_set(0) // default
|
|
||||||
C.vips_cache_set_max_mem(100 * 1024 * 1024) // 100 MB
|
|
||||||
C.vips_cache_set_max(500) // 500 operations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicit thread-safe start of libvips.
|
||||||
|
// You should only call this function if you previously shutdown libvips
|
||||||
func Initialize() {
|
func Initialize() {
|
||||||
|
m.Lock()
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer m.Unlock()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
err := C.vips_init(C.CString("bimg"))
|
err := C.vips_init(C.CString("bimg"))
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
Shutdown()
|
Shutdown()
|
||||||
panic("unable to start vips!")
|
panic("unable to start vips!")
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Lock()
|
C.vips_concurrency_set(0) // default
|
||||||
defer m.Unlock()
|
C.vips_cache_set_max_mem(100 * 1024 * 1024) // 100 MB
|
||||||
|
C.vips_cache_set_max(500) // 500 operations
|
||||||
initialized = true
|
initialized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicit thread-safe libvips shutdown. Call this to drop caches.
|
||||||
|
// If libvips was already initialized, the function is no-op
|
||||||
func Shutdown() {
|
func Shutdown() {
|
||||||
|
m.Lock()
|
||||||
|
defer m.Unlock()
|
||||||
|
|
||||||
if initialized == true {
|
if initialized == true {
|
||||||
m.Lock()
|
|
||||||
defer m.Unlock()
|
|
||||||
C.vips_shutdown()
|
C.vips_shutdown()
|
||||||
initialized = false
|
initialized = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output to stdout collected data for debugging purposes
|
||||||
|
func VipsDebug() {
|
||||||
|
C.im__print_all()
|
||||||
|
}
|
||||||
|
|
||||||
func vipsRotate(image *C.struct__VipsImage, angle Angle) (*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
|
||||||
defer C.g_object_unref(C.gpointer(image))
|
defer C.g_object_unref(C.gpointer(image))
|
||||||
|
|
@ -197,26 +203,6 @@ func vipsImageType(buf []byte) ImageType {
|
||||||
return imageType
|
return imageType
|
||||||
}
|
}
|
||||||
|
|
||||||
func vipsExifOrientation(image *C.struct__VipsImage) int {
|
|
||||||
return int(C.vips_exif_orientation(image))
|
|
||||||
}
|
|
||||||
|
|
||||||
func vipsHasAlpha(image *C.struct__VipsImage) bool {
|
|
||||||
return int(C.has_alpha_channel(image)) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func vipsHasProfile(image *C.struct__VipsImage) bool {
|
|
||||||
return int(C.has_profile_embed(image)) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func vipsWindowSize(name string) float64 {
|
|
||||||
return float64(C.interpolator_window_size(C.CString(name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func vipsSpace(image *C.struct__VipsImage) string {
|
|
||||||
return C.GoString(C.vips_enum_nick_bridge(image))
|
|
||||||
}
|
|
||||||
|
|
||||||
type vipsSaveOptions struct {
|
type vipsSaveOptions struct {
|
||||||
Quality int
|
Quality int
|
||||||
Compression int
|
Compression int
|
||||||
|
|
@ -255,9 +241,30 @@ func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func vipsExifOrientation(image *C.struct__VipsImage) int {
|
||||||
|
return int(C.vips_exif_orientation(image))
|
||||||
|
}
|
||||||
|
|
||||||
|
func vipsHasAlpha(image *C.struct__VipsImage) bool {
|
||||||
|
return int(C.has_alpha_channel(image)) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func vipsHasProfile(image *C.struct__VipsImage) bool {
|
||||||
|
return int(C.has_profile_embed(image)) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func vipsWindowSize(name string) float64 {
|
||||||
|
return float64(C.interpolator_window_size(C.CString(name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func vipsSpace(image *C.struct__VipsImage) string {
|
||||||
|
return C.GoString(C.vips_enum_nick_bridge(image))
|
||||||
|
}
|
||||||
|
|
||||||
func catchVipsError() 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()
|
||||||
|
// clean image memory buffer?
|
||||||
return errors.New(s)
|
return errors.New(s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
vips.h
2
vips.h
|
|
@ -151,8 +151,10 @@ vips_init_image(void *buf, size_t len, int imageType, VipsImage **out) {
|
||||||
code = vips_webpload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
|
code = vips_webpload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
|
||||||
} else if (imageType == TIFF) {
|
} else if (imageType == TIFF) {
|
||||||
code = vips_tiffload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
|
code = vips_tiffload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
|
||||||
|
#if (VIPS_MAJOR_VERSION >= 8)
|
||||||
} else if (imageType == MAGICK) {
|
} else if (imageType == MAGICK) {
|
||||||
code = vips_magickload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
|
code = vips_magickload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for "postclose" signal to delete input buffer
|
// Listen for "postclose" signal to delete input buffer
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue