refactor(#47): minor refactors, code normalization and test coverage

master
Tomas Aparicio 11 years ago
parent 6edd96ee41
commit ed4faadba6

@ -238,7 +238,7 @@ bimg.Write("new.jpg", newImage)
Run the process passing the `DEBUG` environment variable Run the process passing the `DEBUG` environment variable
``` ```
DEBUG=* ./app DEBUG=bimg ./app
``` ```
Enable libvips traces (note that a lot of data will be written in stdout): Enable libvips traces (note that a lot of data will be written in stdout):
@ -248,6 +248,12 @@ VIPS_TRACE=1 ./app
### Programmatic API ### Programmatic API
#### func ColourspaceIsSupported
```go
func ColourspaceIsSupported(buf []byte) (bool, error)
```
Check in the image colourspace is supported by libvips
#### func DetermineImageTypeName #### func DetermineImageTypeName
@ -295,7 +301,7 @@ func Resize(buf []byte, o Options) ([]byte, error)
```go ```go
func Shutdown() func Shutdown()
``` ```
Thread-safe function to shutdown libvips. You could call this to drop caches as Thread-safe function to shutdown libvips. You can call this to drop caches as
well. If libvips was already initialized, the function is no-op well. If libvips was already initialized, the function is no-op
#### func VipsDebugInfo #### func VipsDebugInfo
@ -383,6 +389,20 @@ func NewImage(buf []byte) *Image
``` ```
Creates a new image Creates a new image
#### func (*Image) Colourspace
```go
func (i *Image) Colourspace(c Interpretation) ([]byte, error)
```
Colour space conversion
#### func (*Image) ColourspaceIsSupported
```go
func (i *Image) ColourspaceIsSupported() (bool, error)
```
Check if the current image has a valid colourspace
#### func (*Image) Convert #### func (*Image) Convert
```go ```go
@ -453,6 +473,14 @@ func (i *Image) Image() []byte
``` ```
Get image buffer Get image buffer
#### func (*Image) Interpretation
```go
func (i *Image) Interpretation() (Interpretation, error)
```
Get the image interpretation type See:
http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
#### func (*Image) Metadata #### func (*Image) Metadata
```go ```go
@ -533,6 +561,7 @@ type ImageMetadata struct {
Profile bool Profile bool
Type string Type string
Space string Space string
Colourspace string
Size ImageSize Size ImageSize
} }
``` ```
@ -609,33 +638,65 @@ const (
func (i Interpolator) String() string func (i Interpolator) String() string
``` ```
#### type Interpretation
```go
type Interpretation int
```
Image interpretation type See:
http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
```go
const (
INTERPRETATION_ERROR Interpretation = C.VIPS_INTERPRETATION_ERROR
INTERPRETATION_MULTIBAND Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
INTERPRETATION_B_W Interpretation = C.VIPS_INTERPRETATION_B_W
INTERPRETATION_CMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
INTERPRETATION_RGB Interpretation = C.VIPS_INTERPRETATION_RGB
INTERPRETATION_sRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
INTERPRETATION_RGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
INTERPRETATION_GREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16
INTERPRETATION_scRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
)
```
#### func ImageInterpretation
```go
func ImageInterpretation(buf []byte) (Interpretation, error)
```
Get the image interpretation type See:
http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
#### type Options #### type Options
```go ```go
type Options struct { type Options struct {
Height int Height int
Width int Width int
AreaHeight int AreaHeight int
AreaWidth int AreaWidth int
Top int Top int
Left int Left int
Extend int Extend int
Quality int Quality int
Compression int Compression int
Zoom int Zoom int
Crop bool Crop bool
Enlarge bool Enlarge bool
Embed bool Embed bool
Flip bool Flip bool
Flop bool Flop bool
NoAutoRotate bool NoAutoRotate bool
NoProfile bool NoProfile bool
Interlace bool Interlace bool
Rotate Angle Rotate Angle
Gravity Gravity Gravity Gravity
Watermark Watermark Watermark Watermark
Type ImageType Type ImageType
Interpolator Interpolator Interpolator Interpolator
Interpretation Interpretation
} }
``` ```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

@ -155,6 +155,17 @@ func (i *Image) Metadata() (ImageMetadata, error) {
return Metadata(i.buffer) return Metadata(i.buffer)
} }
// Get the image interpretation type
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
func (i *Image) Interpretation() (Interpretation, error) {
return ImageInterpretation(i.buffer)
}
// Check if the current image has a valid colourspace
func (i *Image) ColourspaceIsSupported() (bool, error) {
return ColourspaceIsSupported(i.buffer)
}
// Get image type format (jpeg, png, webp, tiff) // Get image type format (jpeg, png, webp, tiff)
func (i *Image) Type() string { func (i *Image) Type() string {
return DetermineImageTypeName(i.buffer) return DetermineImageTypeName(i.buffer)

@ -262,12 +262,36 @@ func TestImageMetadata(t *testing.T) {
} }
} }
func TestInterpretation(t *testing.T) {
interpretation, err := initImage("test.jpg").Interpretation()
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}
if interpretation != INTERPRETATION_sRGB {
t.Errorf("Invalid interpretation: %d", interpretation)
}
}
func TestImageColourspaceBW(t *testing.T) { func TestImageColourspaceBW(t *testing.T) {
buf, err := initImage("test.jpg").Colourspace(B_W) buf, err := initImage("test.jpg").Colourspace(INTERPRETATION_B_W)
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}
interpretation, err := ImageInterpretation(buf)
if interpretation != INTERPRETATION_B_W {
t.Errorf("Invalid colourspace")
}
}
func TestImageColourspaceIsSupported(t *testing.T) {
supported, err := initImage("test.jpg").ColourspaceIsSupported()
if err != nil { if err != nil {
t.Errorf("Cannot process the image: %#v", err) t.Errorf("Cannot process the image: %#v", err)
} }
Write("fixtures/test_image_colourspace_b_w.jpg", buf) if supported != true {
t.Errorf("Non-supported colourspace")
}
} }
func TestFluentInterface(t *testing.T) { func TestFluentInterface(t *testing.T) {

@ -18,6 +18,7 @@ type ImageMetadata struct {
Profile bool Profile bool
Type string Type string
Space string Space string
Colourspace string
Size ImageSize Size ImageSize
} }
@ -34,6 +35,17 @@ func Size(buf []byte) (ImageSize, error) {
}, nil }, nil
} }
// Check in the image colourspace is supported by libvips
func ColourspaceIsSupported(buf []byte) (bool, error) {
return vipsColourspaceIsSupportedBuffer(buf)
}
// Get the image interpretation type
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
func ImageInterpretation(buf []byte) (Interpretation, error) {
return vipsInterpretationBuffer(buf)
}
// Extract the image metadata (size, type, alpha channel, profile, EXIF orientation...) // Extract the image metadata (size, type, alpha channel, profile, EXIF orientation...)
func Metadata(buf []byte) (ImageMetadata, error) { func Metadata(buf []byte) (ImageMetadata, error) {
defer C.vips_thread_shutdown() defer C.vips_thread_shutdown()

@ -38,9 +38,9 @@ func TestMetadata(t *testing.T) {
profile bool profile bool
space string space string
}{ }{
{"test.jpg", "jpeg", 0, false, false, "bicubic"}, {"test.jpg", "jpeg", 0, false, false, "srgb"},
{"test.png", "png", 0, true, false, "bicubic"}, {"test.png", "png", 0, true, false, "srgb"},
{"test.webp", "webp", 0, false, false, "bicubic"}, {"test.webp", "webp", 0, false, false, "srgb"},
} }
for _, file := range files { for _, file := range files {
@ -61,6 +61,58 @@ func TestMetadata(t *testing.T) {
if metadata.Profile != file.profile { if metadata.Profile != file.profile {
t.Fatalf("Unexpected image profile: %s != %s", metadata.Profile, file.profile) t.Fatalf("Unexpected image profile: %s != %s", metadata.Profile, file.profile)
} }
if metadata.Space != file.space {
t.Fatalf("Unexpected image profile: %s != %s", metadata.Profile, file.profile)
}
}
}
func TestImageInterpretation(t *testing.T) {
files := []struct {
name string
interpretation Interpretation
}{
{"test.jpg", INTERPRETATION_sRGB},
{"test.png", INTERPRETATION_sRGB},
{"test.webp", INTERPRETATION_sRGB},
}
for _, file := range files {
interpretation, err := ImageInterpretation(readFile(file.name))
if err != nil {
t.Fatalf("Cannot read the image: %s -> %s", file.name, err)
}
if interpretation != file.interpretation {
t.Fatalf("Unexpected image interpretation")
}
}
}
func TestColourspaceIsSupported(t *testing.T) {
files := []struct {
name string
}{
{"test.jpg"},
{"test.png"},
{"test.webp"},
}
for _, file := range files {
supported, err := ColourspaceIsSupported(readFile(file.name))
if err != nil {
t.Fatalf("Cannot read the image: %s -> %s", file.name, err)
}
if supported != true {
t.Fatalf("Unsupported image colourspace")
}
}
supported, err := initImage("test.jpg").ColourspaceIsSupported()
if err != nil {
t.Errorf("Cannot process the image: %#v", err)
}
if supported != true {
t.Errorf("Non-supported colourspace")
} }
} }

@ -55,18 +55,20 @@ const (
VERTICAL Direction = C.VIPS_DIRECTION_VERTICAL VERTICAL Direction = C.VIPS_DIRECTION_VERTICAL
) )
// Image interpretation type
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
type Interpretation int type Interpretation int
const ( const (
ERROR Interpretation = C.VIPS_INTERPRETATION_ERROR INTERPRETATION_ERROR Interpretation = C.VIPS_INTERPRETATION_ERROR
MULTIBAND Interpretation = C.VIPS_INTERPRETATION_MULTIBAND INTERPRETATION_MULTIBAND Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
B_W Interpretation = C.VIPS_INTERPRETATION_B_W INTERPRETATION_B_W Interpretation = C.VIPS_INTERPRETATION_B_W
CMYK Interpretation = C.VIPS_INTERPRETATION_CMYK INTERPRETATION_CMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
RGB Interpretation = C.VIPS_INTERPRETATION_RGB INTERPRETATION_RGB Interpretation = C.VIPS_INTERPRETATION_RGB
sRGB Interpretation = C.VIPS_INTERPRETATION_sRGB INTERPRETATION_sRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
RGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16 INTERPRETATION_RGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
GREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16 INTERPRETATION_GREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16
scRGB Interpretation = C.VIPS_INTERPRETATION_scRGB INTERPRETATION_scRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
) )
const WATERMARK_FONT = "sans 10" const WATERMARK_FONT = "sans 10"
@ -88,28 +90,28 @@ type Watermark struct {
} }
type Options struct { type Options struct {
Height int Height int
Width int Width int
AreaHeight int AreaHeight int
AreaWidth int AreaWidth int
Top int Top int
Left int Left int
Extend int Extend int
Quality int Quality int
Compression int Compression int
Zoom int Zoom int
Crop bool Crop bool
Enlarge bool Enlarge bool
Embed bool Embed bool
Flip bool Flip bool
Flop bool Flop bool
NoAutoRotate bool NoAutoRotate bool
NoProfile bool NoProfile bool
Interlace bool Interlace bool
Rotate Angle Rotate Angle
Gravity Gravity Gravity Gravity
Watermark Watermark Watermark Watermark
Type ImageType Type ImageType
Interpolator Interpolator Interpolator Interpolator
Interpretation Interpretation Interpretation Interpretation
} }

@ -117,15 +117,15 @@ func Resize(buf []byte, o Options) ([]byte, error) {
} }
saveOptions := vipsSaveOptions{ saveOptions := vipsSaveOptions{
Quality: o.Quality, Quality: o.Quality,
Type: o.Type, Type: o.Type,
Compression: o.Compression, Compression: o.Compression,
Interlace: o.Interlace, Interlace: o.Interlace,
NoProfile: o.NoProfile, NoProfile: o.NoProfile,
Interpretation: o.Interpretation, Interpretation: o.Interpretation,
} }
// Finally save as buffer // Finally get the resultant buffer
buf, err = vipsSave(image, saveOptions) buf, err = vipsSave(image, saveOptions)
if err != nil { if err != nil {
return nil, err return nil, err
@ -145,7 +145,7 @@ func applyDefaults(o *Options, imageType ImageType) {
o.Type = imageType o.Type = imageType
} }
if o.Interpretation == 0 { if o.Interpretation == 0 {
o.Interpretation = sRGB o.Interpretation = INTERPRETATION_sRGB
} }
} }

@ -32,11 +32,11 @@ type VipsMemoryInfo struct {
} }
type vipsSaveOptions struct { type vipsSaveOptions struct {
Quality int Quality int
Compression int Compression int
Type ImageType Type ImageType
Interlace bool Interlace bool
NoProfile bool NoProfile bool
Interpretation Interpretation Interpretation Interpretation
} }
@ -224,41 +224,85 @@ func vipsRead(buf []byte) (*C.struct__VipsImage, ImageType, error) {
return image, imageType, nil return image, imageType, nil
} }
func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) { func vipsColourspaceIsSupportedBuffer(buf []byte) (bool, error) {
length := C.size_t(0) image, _, err := vipsRead(buf)
err := C.int(0) defer C.g_object_unref(C.gpointer(image))
interlace := C.int(boolToInt(o.Interlace)) if err != nil {
if o.Interpretation == 0 { return false, err
o.Interpretation = sRGB
} }
interpretation := C.VipsInterpretation(o.Interpretation) return vipsColourspaceIsSupported(image), nil
}
func vipsColourspaceIsSupported(image *C.struct__VipsImage) bool {
return int(C.vips_colourspace_issupported_bridge(image)) == 1
}
func vipsInterpretationBuffer(buf []byte) (Interpretation, error) {
image, _, err := vipsRead(buf)
defer C.g_object_unref(C.gpointer(image))
if err != nil {
return Interpretation(-1), err
}
return vipsInterpretation(image), nil
}
func vipsInterpretation(image *C.struct__VipsImage) Interpretation {
return Interpretation(C.vips_image_guess_interpretation_bridge(image))
}
func vipsPreSave(image *C.struct__VipsImage, o *vipsSaveOptions) (*C.struct__VipsImage, error) {
// Remove ICC profile metadata // Remove ICC profile metadata
if o.NoProfile { if o.NoProfile {
C.remove_profile(image) C.remove_profile(image)
} }
// Force RGB color space // Use a default interpretation and cast it to C type
if o.Interpretation == 0 {
o.Interpretation = INTERPRETATION_sRGB
}
interpretation := C.VipsInterpretation(o.Interpretation)
// Apply the proper colour space
var outImage *C.struct__VipsImage var outImage *C.struct__VipsImage
C.vips_colourspace_bridge(image, &outImage, interpretation) if vipsColourspaceIsSupported(image) {
err := int(C.vips_colourspace_bridge(image, &outImage, interpretation))
C.g_object_unref(C.gpointer(image))
if err != 0 {
return nil, catchVipsError()
}
image = outImage
}
return image, nil
}
func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
defer C.g_object_unref(C.gpointer(image)) defer C.g_object_unref(C.gpointer(image))
defer C.g_object_unref(C.gpointer(outImage))
image, err := vipsPreSave(image, &o)
if err != nil {
return nil, err
}
length := C.size_t(0)
saveErr := C.int(0)
interlace := C.int(boolToInt(o.Interlace))
quality := C.int(o.Quality)
var ptr unsafe.Pointer var ptr unsafe.Pointer
switch o.Type { switch o.Type {
case PNG:
err = C.vips_pngsave_bridge(outImage, &ptr, &length, 1, C.int(o.Compression), C.int(o.Quality), interlace)
break
case WEBP: case WEBP:
err = C.vips_webpsave_bridge(outImage, &ptr, &length, 1, C.int(o.Quality)) saveErr = C.vips_webpsave_bridge(image, &ptr, &length, 1, quality)
break
case PNG:
saveErr = C.vips_pngsave_bridge(image, &ptr, &length, 1, C.int(o.Compression), quality, interlace)
break break
default: default:
err = C.vips_jpegsave_bridge(outImage, &ptr, &length, 1, C.int(o.Quality), interlace) saveErr = C.vips_jpegsave_bridge(image, &ptr, &length, 1, quality, interlace)
break break
} }
if int(err) != 0 { if int(saveErr) != 0 {
return nil, catchVipsError() return nil, catchVipsError()
} }

@ -134,6 +134,17 @@ vips_extract_area_bridge(VipsImage *in, VipsImage **out, int left, int top, int
return vips_extract_area(in, out, left, top, width, height, NULL); return vips_extract_area(in, out, left, top, width, height, NULL);
}; };
int
vips_colourspace_issupported_bridge(VipsImage *in)
{
return vips_colourspace_issupported(in) ? 1 : 0;
};
VipsInterpretation
vips_image_guess_interpretation_bridge(VipsImage *in) {
return vips_image_guess_interpretation(in);
};
int int
vips_colourspace_bridge(VipsImage *in, VipsImage **out, VipsInterpretation space) vips_colourspace_bridge(VipsImage *in, VipsImage **out, VipsInterpretation space)
{ {

Loading…
Cancel
Save