Skip to content

Commit

Permalink
When implicitly converting the image type (BMP to PNG), keep the orig…
Browse files Browse the repository at this point in the history
…inal format available for query
  • Loading branch information
elad laufer committed Aug 3, 2022
1 parent 25f3e8c commit df634a6
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 20 deletions.
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
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 df634a6

Please sign in to comment.