Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Original image type #299

Merged
merged 10 commits into from
Aug 5, 2022
7 changes: 2 additions & 5 deletions vips/color.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package vips

// #include "color.h"
import "C"
import (
"unsafe"
)

// Color represents an RGB
type Color struct {
Expand Down Expand Up @@ -80,11 +77,11 @@ func vipsICCTransform(in *C.VipsImage, outputProfile string, inputProfile string
var cEmbedded C.gboolean

cOutputProfile := C.CString(outputProfile)
defer C.free(unsafe.Pointer(cOutputProfile))
defer freeCString(cOutputProfile)

if inputProfile != "" {
cInputProfile = C.CString(inputProfile)
defer C.free(unsafe.Pointer(cInputProfile))
defer freeCString(cInputProfile)
}

if embedded {
Expand Down
21 changes: 11 additions & 10 deletions vips/foreign.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,36 +252,37 @@ func isJP2K(buf []byte) bool {
return bytes.HasPrefix(buf, jp2kHeader)
}

func vipsLoadFromBuffer(buf []byte, params *ImportParams) (*C.VipsImage, ImageType, error) {
func vipsLoadFromBuffer(buf []byte, params *ImportParams) (*C.VipsImage, ImageType, ImageType, error) {
src := buf
// Reference src here so it's not garbage collected during image initialization.
defer runtime.KeepAlive(src)

var err error

imageType := DetermineImageType(src)
originalType := DetermineImageType(src)
currentType := originalType

if imageType == ImageTypeBMP {
if originalType == ImageTypeBMP {
src, err = bmpToPNG(src)
if err != nil {
return nil, ImageTypeUnknown, err
return nil, currentType, originalType, err
}

imageType = ImageTypePNG
currentType = ImageTypePNG
}

if !IsTypeSupported(imageType) {
if !IsTypeSupported(currentType) {
govipsLog("govips", LogLevelInfo, fmt.Sprintf("failed to understand image format size=%d", len(src)))
return nil, ImageTypeUnknown, ErrUnsupportedImageFormat
return nil, currentType, originalType, ErrUnsupportedImageFormat
}

importParams := createImportParams(imageType, params)
importParams := createImportParams(currentType, params)

if err := C.load_from_buffer(&importParams, unsafe.Pointer(&src[0]), C.size_t(len(src))); err != 0 {
return nil, ImageTypeUnknown, handleImageError(importParams.outputImage)
return nil, currentType, originalType, handleImageError(importParams.outputImage)
}

return importParams.outputImage, imageType, nil
return importParams.outputImage, currentType, originalType, nil
}

func bmpToPNG(src []byte) ([]byte, error) {
Expand Down
2 changes: 1 addition & 1 deletion vips/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func vipsSetPageHeight(in *C.VipsImage, height int) {

func vipsImageGetMetaLoader(in *C.VipsImage) (string, bool) {
var out *C.char
defer gFreePointer(unsafe.Pointer(out))
defer freeCString(out)
code := int(C.get_meta_loader(in, &out))
return C.GoString(out), code == 0
}
Expand Down
32 changes: 22 additions & 10 deletions vips/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type ImageRef struct {
buf []byte
image *C.VipsImage
format ImageType
originalFormat ImageType
lock sync.Mutex
preMultiplication *PreMultiplicationState
optimizedIccProfile string
Expand Down Expand Up @@ -412,12 +413,12 @@ func LoadImageFromBuffer(buf []byte, params *ImportParams) (*ImageRef, error) {
params = NewImportParams()
}

vipsImage, format, err := vipsLoadFromBuffer(buf, params)
vipsImage, currentFormat, originalFormat, err := vipsLoadFromBuffer(buf, params)
if err != nil {
return nil, err
}

ref := newImageRef(vipsImage, format, buf)
ref := newImageRef(vipsImage, currentFormat, originalFormat, buf)

govipsLog("govips", LogLevelDebug, fmt.Sprintf("created imageRef %p", ref))
return ref, nil
Expand Down Expand Up @@ -447,7 +448,7 @@ func LoadThumbnailFromFile(file string, width, height int, crop Interesting, siz
return nil, err
}

ref := newImageRef(vipsImage, format, nil)
ref := newImageRef(vipsImage, format, format, nil)

govipsLog("govips", LogLevelDebug, fmt.Sprintf("created imageref %p", ref))
return ref, nil
Expand All @@ -467,7 +468,7 @@ func LoadThumbnailFromBuffer(buf []byte, width, height int, crop Interesting, si
return nil, err
}

ref := newImageRef(vipsImage, format, buf)
ref := newImageRef(vipsImage, format, format, buf)

govipsLog("govips", LogLevelDebug, fmt.Sprintf("created imageref %p", ref))
return ref, nil
Expand All @@ -492,7 +493,7 @@ func (r *ImageRef) Copy() (*ImageRef, error) {
return nil, err
}

return newImageRef(out, r.format, r.buf), nil
return newImageRef(out, r.format, r.originalFormat, r.buf), nil
}

// XYZ creates a two-band uint32 image where the elements in the first band have the value of their x coordinate
Expand All @@ -515,13 +516,15 @@ func Black(width, height int) (*ImageRef, error) {
return &ImageRef{image: vipsImage}, err
}

func newImageRef(vipsImage *C.VipsImage, format ImageType, buf []byte) *ImageRef {
func newImageRef(vipsImage *C.VipsImage, currentFormat ImageType, originalFormat ImageType, buf []byte) *ImageRef {
imageRef := &ImageRef{
image: vipsImage,
format: format,
buf: buf,
image: vipsImage,
format: currentFormat,
originalFormat: originalFormat,
buf: buf,
}
runtime.SetFinalizer(imageRef, finalizeImage)

return imageRef
}

Expand All @@ -546,11 +549,19 @@ func (r *ImageRef) Close() {
r.lock.Unlock()
}

// Format returns the initial format of the vips image when loaded.
// Format returns the current format of the vips image.
func (r *ImageRef) Format() ImageType {
return r.format
}

// OriginalFormat returns the original format of the image when loaded.
// In some cases the loaded image is converted on load, for example, a BMP is automatically converted to PNG
// This method returns the format of the original buffer, as opposed to Format() with will return the format of the
// currently held buffer content.
func (r *ImageRef) OriginalFormat() ImageType {
return r.originalFormat
}

// Width returns the width of this image.
func (r *ImageRef) Width() int {
return int(r.image.Xsize)
Expand Down Expand Up @@ -1798,6 +1809,7 @@ func clearImage(ref *C.VipsImage) {
type Coding int

// Coding enum
//goland:noinspection GoUnusedConst
const (
CodingError Coding = C.VIPS_CODING_ERROR
CodingNone Coding = C.VIPS_CODING_NONE
Expand Down
1 change: 1 addition & 0 deletions vips/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func TestImageRef_BMP__ImplicitConversionToPNG(t *testing.T) {
exported, metadata, err := img.ExportNative()
assert.NoError(t, err)
assert.Equal(t, ImageTypePNG, metadata.Format)
assert.Equal(t, ImageTypeBMP, img.OriginalFormat())
assert.NotNil(t, exported)
}

Expand Down