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,6 +638,37 @@ 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
@ -636,6 +696,7 @@ type Options struct {
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"

@ -125,7 +125,7 @@ func Resize(buf []byte, o Options) ([]byte, error) {
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
} }
} }

@ -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 }
return vipsColourspaceIsSupported(image), nil
}
func vipsColourspaceIsSupported(image *C.struct__VipsImage) bool {
return int(C.vips_colourspace_issupported_bridge(image)) == 1
} }
interpretation := C.VipsInterpretation(o.Interpretation)
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