diff --git a/resize.go b/resize.go index 8d732fb..9d78f7d 100644 --- a/resize.go +++ b/resize.go @@ -28,7 +28,7 @@ func Resize(buf []byte, o Options) ([]byte, error) { // Clone and define default options o = applyDefaults(o, imageType) - if IsTypeSupported(o.Type) == false { + if !IsTypeSupported(o.Type) { return nil, errors.New("Unsupported image output type") } diff --git a/type.go b/type.go index 60722eb..b660e4e 100644 --- a/type.go +++ b/type.go @@ -1,7 +1,9 @@ package bimg -// ImageType represents an image type value. -type ImageType int +import ( + "regexp" + "unicode/utf8" +) const ( // UNKNOWN represents an unknow image type value. @@ -24,6 +26,14 @@ const ( MAGICK ) +// ImageType represents an image type value. +type ImageType int + +var ( + htmlCommentRegex = regexp.MustCompile("") + svgRegex = regexp.MustCompile(`^\s*(?:<\?xml[^>]*>\s*)?(?:]*>\s*)?]*>[^*]*<\/svg>\s*$`) +) + // ImageTypes stores as pairs of image types supported and its alias names. var ImageTypes = map[ImageType]string{ JPEG: "jpeg", @@ -36,6 +46,35 @@ var ImageTypes = map[ImageType]string{ MAGICK: "magick", } +// SupportedImageTypes stores the optional image type supported +// by the current libvips compilation. +var SupportedImageTypes = map[ImageType]bool{ + JPEG: HasJPEGSupport, + PNG: HasPNGSupport, + WEBP: HasWEBPSupport, + TIFF: HasTIFFSupport, + GIF: HasGIFSupport, + SVG: HasSVGSupport, + PDF: HasPDFSupport, + MAGICK: HasMagickSupport, +} + +// isBinary checks if the given buffer is a binary file. +func isBinary(buf []byte) bool { + for i := 0; i < 24; i++ { + charCode, _ := utf8.DecodeRuneInString(string(buf[i])) + if charCode == 65533 || charCode <= 8 { + return true + } + } + return false +} + +// IsSVGImage returns true if the given buffer is a valid SVG image. +func IsSVGImage(buf []byte) bool { + return !isBinary(buf) && svgRegex.Match(htmlCommentRegex.ReplaceAll(buf, []byte{0})) +} + // DetermineImageType determines the image type format (jpeg, png, webp or tiff) func DetermineImageType(buf []byte) ImageType { return vipsImageType(buf) @@ -46,9 +85,17 @@ func DetermineImageTypeName(buf []byte) string { return ImageTypeName(vipsImageType(buf)) } +// IsImageTypeSupportedByVips returns true if the given image type +// is supported by current libvips compilation. +func IsImageTypeSupportedByVips(t ImageType) bool { + isSupported, ok := SupportedImageTypes[t] + return ok && isSupported +} + // IsTypeSupported checks if a given image type is supported func IsTypeSupported(t ImageType) bool { - return ImageTypes[t] != "" + _, ok := ImageTypes[t] + return ok } // IsTypeNameSupported checks if a given image type name is supported diff --git a/vips.go b/vips.go index 1fec575..c494aa3 100644 --- a/vips.go +++ b/vips.go @@ -30,10 +30,38 @@ const VipsMajorVersion = int(C.VIPS_MAJOR_VERSION) // VipsMinorVersion exposes the current libvips minor version number const VipsMinorVersion = int(C.VIPS_MINOR_VERSION) +// HasJPEGSupport exposes if the current libvips compilation +// supports JPEG images. +const HasJPEGSupport = int(C.VIPS_JPEG_SUPPORT) == 1 + +// HasWEBPSupport exposes if the current libvips compilation +// supports WEBP images. +const HasWEBPSupport = int(C.VIPS_WEBP_SUPPORT) == 1 + +// HasPNGSupport exposes if the current libvips compilation +// supports PNG images. +const HasPNGSupport = int(C.VIPS_PNG_SUPPORT) == 1 + // HasMagickSupport exposes if the current libvips compilation // supports libmagick bindings. const HasMagickSupport = int(C.VIPS_MAGICK_SUPPORT) == 1 +// HasGIFSupport exposes if the current libvips compilation +// supports GIF images. +const HasGIFSupport = int(C.VIPS_GIF_SUPPORT) == 1 + +// HasSVGSupport exposes if the current libvips compilation +// supports SVG images. +const HasSVGSupport = int(C.VIPS_SVG_SUPPORT) == 1 + +// HasPDFSupport exposes if the current libvips compilation +// supports PDF images. +const HasPDFSupport = int(C.VIPS_PDF_SUPPORT) == 1 + +// HasTIFFSupport exposes if the current libvips compilation +// supports TIFF images. +const HasTIFFSupport = int(C.VIPS_TIFF_SUPPORT) == 1 + const ( maxCacheMem = 100 * 1024 * 1024 maxCacheSize = 500 @@ -461,39 +489,36 @@ func vipsAffine(input *C.VipsImage, residualx, residualy float64, i Interpolator return image, nil } -func vipsImageType(bytes []byte) ImageType { - if len(bytes) == 0 { +func vipsImageType(buf []byte) ImageType { + if len(buf) == 0 { return UNKNOWN } - if bytes[0] == 0x89 && bytes[1] == 0x50 && bytes[2] == 0x4E && bytes[3] == 0x47 { + if buf[0] == 0x89 && buf[1] == 0x50 && buf[2] == 0x4E && buf[3] == 0x47 { return PNG } - if bytes[0] == 0xFF && bytes[1] == 0xD8 && bytes[2] == 0xFF { + if buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF { return JPEG } - if bytes[8] == 0x57 && bytes[9] == 0x45 && bytes[10] == 0x42 && bytes[11] == 0x50 { + if buf[8] == 0x57 && buf[9] == 0x45 && buf[10] == 0x42 && buf[11] == 0x50 { return WEBP } - if (bytes[0] == 0x49 && bytes[1] == 0x49 && bytes[2] == 0x2A && bytes[3] == 0x0) || - (bytes[0] == 0x4D && bytes[1] == 0x4D && bytes[2] == 0x0 && bytes[3] == 0x2A) { + if (buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0) || + (buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A) { return TIFF } - if bytes[0] == 'G' && bytes[1] == 'I' && bytes[2] == 'F' && bytes[3] == '8' && - bytes[4] == '9' && bytes[5] == 'a' { + if buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46 { return GIF } - if bytes[0] == '%' && bytes[1] == 'P' && bytes[2] == 'D' && bytes[3] == 'F' { + if buf[0] == 0x25 && buf[1] == 0x50 && buf[2] == 0x44 && buf[3] == 0x46 { return PDF } - if bytes[0] == '<' && bytes[1] == '?' && bytes[2] == 'x' && bytes[3] == 'm' && - bytes[4] == 'l' && bytes[5] == ' ' { + if IsSVGImage(buf) { return SVG } - if HasMagickSupport && strings.HasSuffix(readImageType(bytes), "MagickBuffer") { + if HasMagickSupport && strings.HasSuffix(readImageType(buf), "MagickBuffer") { return MAGICK } - return UNKNOWN } diff --git a/vips.h b/vips.h index b5b3bb2..ab1054e 100644 --- a/vips.h +++ b/vips.h @@ -1,5 +1,6 @@ #include #include +#include #include #ifdef VIPS_MAGICK_H @@ -8,6 +9,48 @@ #define VIPS_MAGICK_SUPPORT 0 #endif +#ifdef HAVE_JPEG +#define VIPS_JPEG_SUPPORT 1 +#else +#define VIPS_JPEG_SUPPORT 0 +#endif + +#ifdef HAVE_PNG +#define VIPS_PNG_SUPPORT 1 +#else +#define VIPS_PNG_SUPPORT 0 +#endif + +#ifdef HAVE_LIBWEBP +#define VIPS_WEBP_SUPPORT 1 +#else +#define VIPS_WEBP_SUPPORT 0 +#endif + +#ifdef HAVE_GIFLIB +#define VIPS_GIF_SUPPORT 1 +#else +#define VIPS_GIF_SUPPORT 0 +#endif + +#ifdef HAVE_RSVG +#define VIPS_SVG_SUPPORT 1 +#else +#define VIPS_SVG_SUPPORT 0 +#endif + +#ifdef HAVE_POPPLER +#define VIPS_PDF_SUPPORT 1 +#else +#define VIPS_PDF_SUPPORT 0 +#endif + +#ifdef HAVE_TIFF +#define VIPS_TIFF_SUPPORT 1 +#else +#define VIPS_TIFF_SUPPORT 0 +#endif + /** * Starting libvips 7.41, VIPS_ANGLE_x has been renamed to VIPS_ANGLE_Dx * "to help python". So we provide the macro to correctly build for versions