Skip to content

Commit

Permalink
Original image type (#299)
Browse files Browse the repository at this point in the history
* - add golden

* - freeCString abstraction

* When implicitly converting the image type (BMP to PNG), keep the original format available for query
  • Loading branch information
Elad Laufer authored Aug 5, 2022
1 parent 810eeb0 commit 8d6122f
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 26 deletions.
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

0 comments on commit 8d6122f

Please sign in to comment.