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
```
DEBUG=* ./app
DEBUG=bimg ./app
```
Enable libvips traces (note that a lot of data will be written in stdout):
@ -248,6 +248,12 @@ VIPS_TRACE=1 ./app
### Programmatic API
#### func ColourspaceIsSupported
```go
func ColourspaceIsSupported(buf []byte) (bool, error)
```
Check in the image colourspace is supported by libvips
#### func DetermineImageTypeName
@ -295,7 +301,7 @@ func Resize(buf []byte, o Options) ([]byte, error)
```go
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
#### func VipsDebugInfo
@ -383,6 +389,20 @@ func NewImage(buf []byte) *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
```go
@ -453,6 +473,14 @@ func (i *Image) Image() []byte
```
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
```go
@ -533,6 +561,7 @@ type ImageMetadata struct {
Profile bool
Type string
Space string
Colourspace string
Size ImageSize
}
```
@ -609,33 +638,65 @@ const (
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
```go
type Options struct {
Height int
Width int
AreaHeight int
AreaWidth int
Top int
Left int
Extend int
Quality int
Compression int
Zoom int
Crop bool
Enlarge bool
Embed bool
Flip bool
Flop bool
NoAutoRotate bool
NoProfile bool
Interlace bool
Rotate Angle
Gravity Gravity
Watermark Watermark
Type ImageType
Interpolator Interpolator
Height int
Width int
AreaHeight int
AreaWidth int
Top int
Left int
Extend int
Quality int
Compression int
Zoom int
Crop bool
Enlarge bool
Embed bool
Flip bool
Flop bool
NoAutoRotate bool
NoProfile bool
Interlace bool
Rotate Angle
Gravity Gravity
Watermark Watermark
Type ImageType
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)
}
// 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)
func (i *Image) Type() string {
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) {
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 {
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) {

@ -18,6 +18,7 @@ type ImageMetadata struct {
Profile bool
Type string
Space string
Colourspace string
Size ImageSize
}
@ -34,6 +35,17 @@ func Size(buf []byte) (ImageSize, error) {
}, 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...)
func Metadata(buf []byte) (ImageMetadata, error) {
defer C.vips_thread_shutdown()

@ -38,9 +38,9 @@ func TestMetadata(t *testing.T) {
profile bool
space string
}{
{"test.jpg", "jpeg", 0, false, false, "bicubic"},
{"test.png", "png", 0, true, false, "bicubic"},
{"test.webp", "webp", 0, false, false, "bicubic"},
{"test.jpg", "jpeg", 0, false, false, "srgb"},
{"test.png", "png", 0, true, false, "srgb"},
{"test.webp", "webp", 0, false, false, "srgb"},
}
for _, file := range files {
@ -61,6 +61,58 @@ func TestMetadata(t *testing.T) {
if 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
)
// Image interpretation type
// See: http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/VipsImage.html#VipsInterpretation
type Interpretation int
const (
ERROR Interpretation = C.VIPS_INTERPRETATION_ERROR
MULTIBAND Interpretation = C.VIPS_INTERPRETATION_MULTIBAND
B_W Interpretation = C.VIPS_INTERPRETATION_B_W
CMYK Interpretation = C.VIPS_INTERPRETATION_CMYK
RGB Interpretation = C.VIPS_INTERPRETATION_RGB
sRGB Interpretation = C.VIPS_INTERPRETATION_sRGB
RGB16 Interpretation = C.VIPS_INTERPRETATION_RGB16
GREY16 Interpretation = C.VIPS_INTERPRETATION_GREY16
scRGB Interpretation = C.VIPS_INTERPRETATION_scRGB
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
)
const WATERMARK_FONT = "sans 10"
@ -88,28 +90,28 @@ type Watermark struct {
}
type Options struct {
Height int
Width int
AreaHeight int
AreaWidth int
Top int
Left int
Extend int
Quality int
Compression int
Zoom int
Crop bool
Enlarge bool
Embed bool
Flip bool
Flop bool
NoAutoRotate bool
NoProfile bool
Interlace bool
Rotate Angle
Gravity Gravity
Watermark Watermark
Type ImageType
Interpolator Interpolator
Height int
Width int
AreaHeight int
AreaWidth int
Top int
Left int
Extend int
Quality int
Compression int
Zoom int
Crop bool
Enlarge bool
Embed bool
Flip bool
Flop bool
NoAutoRotate bool
NoProfile bool
Interlace bool
Rotate Angle
Gravity Gravity
Watermark Watermark
Type ImageType
Interpolator Interpolator
Interpretation Interpretation
}

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

@ -32,11 +32,11 @@ type VipsMemoryInfo struct {
}
type vipsSaveOptions struct {
Quality int
Compression int
Type ImageType
Interlace bool
NoProfile bool
Quality int
Compression int
Type ImageType
Interlace bool
NoProfile bool
Interpretation Interpretation
}
@ -224,41 +224,85 @@ func vipsRead(buf []byte) (*C.struct__VipsImage, ImageType, error) {
return image, imageType, nil
}
func vipsSave(image *C.struct__VipsImage, o vipsSaveOptions) ([]byte, error) {
length := C.size_t(0)
err := C.int(0)
interlace := C.int(boolToInt(o.Interlace))
if o.Interpretation == 0 {
o.Interpretation = sRGB
func vipsColourspaceIsSupportedBuffer(buf []byte) (bool, error) {
image, _, err := vipsRead(buf)
defer C.g_object_unref(C.gpointer(image))
if err != nil {
return false, err
}
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
if o.NoProfile {
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
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(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
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:
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
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
}
if int(err) != 0 {
if int(saveErr) != 0 {
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);
};
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
vips_colourspace_bridge(VipsImage *in, VipsImage **out, VipsInterpretation space)
{

Loading…
Cancel
Save