mirror of
https://github.com/talgo-cloud/bimg.git
synced 2026-03-11 00:10:27 -07:00
commit
45e4ce45fd
6 changed files with 167 additions and 41 deletions
12
History.md
12
History.md
|
|
@ -1,7 +1,15 @@
|
|||
## 1.0.3 / 28-09-2016
|
||||
|
||||
- fix(#95): better image type inference and support check.
|
||||
- fix(background): pass proper background RGB color for PNG image conversion.
|
||||
- feat(types): validate supported image types by current `libvips` compilation.
|
||||
- feat(types): consistent SVG image checking.
|
||||
- feat(api): add public functions `VipsIsTypeSupported()`, `IsImageTypeSupportedByVips()` and `IsSVGImage()`.
|
||||
|
||||
## 1.0.2 / 27-09-2016
|
||||
|
||||
- feat(#95): support GIF, SVG and PDF formats
|
||||
- fix(#108): auto-width and height calculations now round instead of floor
|
||||
- feat(#95): support GIF, SVG and PDF formats.
|
||||
- fix(#108): auto-width and height calculations now round instead of floor.
|
||||
|
||||
## 1.0.1 / 22-06-2016
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
@ -330,7 +330,6 @@ func imageFlatten(image *C.VipsImage, imageType ImageType, o Options) (*C.VipsIm
|
|||
if imageType != PNG || o.Background == ColorBlack {
|
||||
return image, nil
|
||||
}
|
||||
|
||||
return vipsFlattenBackground(image, o.Background)
|
||||
}
|
||||
|
||||
|
|
|
|||
86
type.go
86
type.go
|
|
@ -1,7 +1,10 @@
|
|||
package bimg
|
||||
|
||||
// ImageType represents an image type value.
|
||||
type ImageType int
|
||||
import (
|
||||
"regexp"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
// UNKNOWN represents an unknow image type value.
|
||||
|
|
@ -24,6 +27,14 @@ const (
|
|||
MAGICK
|
||||
)
|
||||
|
||||
// ImageType represents an image type value.
|
||||
type ImageType int
|
||||
|
||||
var (
|
||||
htmlCommentRegex = regexp.MustCompile("(?i)<!--([\\s\\S]*?)-->")
|
||||
svgRegex = regexp.MustCompile(`(?i)^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*>\s*)?<svg[^>]*>[^*]*<\/svg>\s*$`)
|
||||
)
|
||||
|
||||
// ImageTypes stores as pairs of image types supported and its alias names.
|
||||
var ImageTypes = map[ImageType]string{
|
||||
JPEG: "jpeg",
|
||||
|
|
@ -36,6 +47,49 @@ var ImageTypes = map[ImageType]string{
|
|||
MAGICK: "magick",
|
||||
}
|
||||
|
||||
// imageMutex is used to provide thread-safe synchronization
|
||||
// for SupportedImageTypes map.
|
||||
var imageMutex = &sync.RWMutex{}
|
||||
|
||||
// SupportedImageTypes stores the optional image type supported
|
||||
// by the current libvips compilation.
|
||||
// Note: lazy evaluation as demand is required due
|
||||
// to bootstrap runtime limitation with C/libvips world.
|
||||
var SupportedImageTypes = map[ImageType]bool{}
|
||||
|
||||
// discoverSupportedImageTypes is used to fill SupportedImageTypes map.
|
||||
func discoverSupportedImageTypes() {
|
||||
imageMutex.Lock()
|
||||
SupportedImageTypes[JPEG] = VipsIsTypeSupported(JPEG)
|
||||
SupportedImageTypes[PNG] = VipsIsTypeSupported(PNG)
|
||||
SupportedImageTypes[GIF] = VipsIsTypeSupported(GIF)
|
||||
SupportedImageTypes[WEBP] = VipsIsTypeSupported(WEBP)
|
||||
SupportedImageTypes[SVG] = VipsIsTypeSupported(SVG)
|
||||
SupportedImageTypes[TIFF] = VipsIsTypeSupported(TIFF)
|
||||
SupportedImageTypes[PDF] = VipsIsTypeSupported(PDF)
|
||||
SupportedImageTypes[MAGICK] = VipsIsTypeSupported(MAGICK)
|
||||
imageMutex.Unlock()
|
||||
}
|
||||
|
||||
// isBinary checks if the given buffer is a binary file.
|
||||
func isBinary(buf []byte) bool {
|
||||
if len(buf) < 24 {
|
||||
return false
|
||||
}
|
||||
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{}))
|
||||
}
|
||||
|
||||
// DetermineImageType determines the image type format (jpeg, png, webp or tiff)
|
||||
func DetermineImageType(buf []byte) ImageType {
|
||||
return vipsImageType(buf)
|
||||
|
|
@ -46,16 +100,38 @@ 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 {
|
||||
imageMutex.RLock()
|
||||
|
||||
// Discover supported image types and cache the result
|
||||
itShouldDiscovery := len(SupportedImageTypes) == 0
|
||||
if itShouldDiscovery {
|
||||
imageMutex.RUnlock()
|
||||
discoverSupportedImageTypes()
|
||||
}
|
||||
|
||||
// Check if image type is actually supported
|
||||
isSupported, ok := SupportedImageTypes[t]
|
||||
if !itShouldDiscovery {
|
||||
imageMutex.RUnlock()
|
||||
}
|
||||
|
||||
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 && IsImageTypeSupportedByVips(t)
|
||||
}
|
||||
|
||||
// IsTypeNameSupported checks if a given image type name is supported
|
||||
func IsTypeNameSupported(t string) bool {
|
||||
for _, name := range ImageTypes {
|
||||
for imageType, name := range ImageTypes {
|
||||
if name == t {
|
||||
return true
|
||||
return IsImageTypeSupportedByVips(imageType)
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package bimg
|
||||
|
||||
// Version represents the current package semantic version.
|
||||
const Version = "1.0.2"
|
||||
const Version = "1.0.3"
|
||||
|
|
|
|||
61
vips.go
61
vips.go
|
|
@ -30,10 +30,6 @@ const VipsMajorVersion = int(C.VIPS_MAJOR_VERSION)
|
|||
// VipsMinorVersion exposes the current libvips minor version number
|
||||
const VipsMinorVersion = int(C.VIPS_MINOR_VERSION)
|
||||
|
||||
// HasMagickSupport exposes if the current libvips compilation
|
||||
// supports libmagick bindings.
|
||||
const HasMagickSupport = int(C.VIPS_MAGICK_SUPPORT) == 1
|
||||
|
||||
const (
|
||||
maxCacheMem = 100 * 1024 * 1024
|
||||
maxCacheSize = 500
|
||||
|
|
@ -141,6 +137,33 @@ func VipsMemory() VipsMemoryInfo {
|
|||
}
|
||||
}
|
||||
|
||||
// VipsIsTypeSupported returns true if the given image type
|
||||
// is supported by the current libvips compilation.
|
||||
func VipsIsTypeSupported(t ImageType) bool {
|
||||
if t == JPEG {
|
||||
return int(C.vips_type_find_bridge(C.JPEG)) != 0
|
||||
}
|
||||
if t == WEBP {
|
||||
return int(C.vips_type_find_bridge(C.WEBP)) != 0
|
||||
}
|
||||
if t == PNG {
|
||||
return int(C.vips_type_find_bridge(C.PNG)) != 0
|
||||
}
|
||||
if t == GIF {
|
||||
return int(C.vips_type_find_bridge(C.GIF)) != 0
|
||||
}
|
||||
if t == PDF {
|
||||
return int(C.vips_type_find_bridge(C.PDF)) != 0
|
||||
}
|
||||
if t == SVG {
|
||||
return int(C.vips_type_find_bridge(C.SVG)) != 0
|
||||
}
|
||||
if t == TIFF {
|
||||
return int(C.vips_type_find_bridge(C.TIFF)) != 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func vipsExifOrientation(image *C.VipsImage) int {
|
||||
return int(C.vips_exif_orientation(image))
|
||||
}
|
||||
|
|
@ -281,7 +304,8 @@ func vipsFlattenBackground(image *C.VipsImage, background Color) (*C.VipsImage,
|
|||
}
|
||||
|
||||
if vipsHasAlpha(image) {
|
||||
err := C.vips_flatten_background_brigde(image, &outImage, (*C.double)(&backgroundC[0]))
|
||||
err := C.vips_flatten_background_brigde(image, &outImage,
|
||||
backgroundC[0], backgroundC[1], backgroundC[2])
|
||||
if int(err) != 0 {
|
||||
return nil, catchVipsError()
|
||||
}
|
||||
|
|
@ -461,39 +485,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 IsImageTypeSupportedByVips(WEBP) && 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 IsImageTypeSupportedByVips(TIFF) &&
|
||||
((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 IsImageTypeSupportedByVips(GIF) && buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46 {
|
||||
return GIF
|
||||
}
|
||||
if bytes[0] == '%' && bytes[1] == 'P' && bytes[2] == 'D' && bytes[3] == 'F' {
|
||||
if IsImageTypeSupportedByVips(PDF) && 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 IsImageTypeSupportedByVips(SVG) && IsSVGImage(buf) {
|
||||
return SVG
|
||||
}
|
||||
if HasMagickSupport && strings.HasSuffix(readImageType(bytes), "MagickBuffer") {
|
||||
if strings.HasSuffix(readImageType(buf), "MagickBuffer") {
|
||||
return MAGICK
|
||||
}
|
||||
|
||||
return UNKNOWN
|
||||
}
|
||||
|
||||
|
|
|
|||
44
vips.h
44
vips.h
|
|
@ -1,13 +1,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <vips/vips.h>
|
||||
#include <vips/foreign.h>
|
||||
#include <vips/vips7compat.h>
|
||||
|
||||
#ifdef VIPS_MAGICK_H
|
||||
#define VIPS_MAGICK_SUPPORT 1
|
||||
#else
|
||||
#define VIPS_MAGICK_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
|
||||
|
|
@ -120,6 +115,35 @@ vips_shrink_bridge(VipsImage *in, VipsImage **out, double xshrink, double yshrin
|
|||
return vips_shrink(in, out, xshrink, yshrink, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
vips_type_find_bridge(int t) {
|
||||
if (t == GIF) {
|
||||
return vips_type_find("VipsOperation", "gifload");
|
||||
}
|
||||
if (t == PDF) {
|
||||
return vips_type_find("VipsOperation", "pdfload");
|
||||
}
|
||||
if (t == TIFF) {
|
||||
return vips_type_find("VipsOperation", "tiffload");
|
||||
}
|
||||
if (t == SVG) {
|
||||
return vips_type_find("VipsOperation", "svgload");
|
||||
}
|
||||
if (t == WEBP) {
|
||||
return vips_type_find("VipsOperation", "webpload");
|
||||
}
|
||||
if (t == PNG) {
|
||||
return vips_type_find("VipsOperation", "pngload");
|
||||
}
|
||||
if (t == JPEG) {
|
||||
return vips_type_find("VipsOperation", "jpegload");
|
||||
}
|
||||
if (t == MAGICK) {
|
||||
return vips_type_find("VipsOperation", "magickload");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
vips_rotate(VipsImage *in, VipsImage **out, int angle) {
|
||||
int rotate = VIPS_ANGLE_D0;
|
||||
|
|
@ -253,12 +277,10 @@ vips_is_16bit (VipsInterpretation interpretation) {
|
|||
}
|
||||
|
||||
int
|
||||
vips_flatten_background_brigde(VipsImage *in, VipsImage **out, double background[3]) {
|
||||
background[0] *= 256;
|
||||
background[1] *= 256;
|
||||
background[2] *= 256;
|
||||
|
||||
vips_flatten_background_brigde(VipsImage *in, VipsImage **out, double r, double g, double b) {
|
||||
double background[3] = {r, g, b};
|
||||
VipsArrayDouble *vipsBackground = vips_array_double_new(background, 3);
|
||||
|
||||
return vips_flatten(in, out,
|
||||
"background", vipsBackground,
|
||||
"max_alpha", vips_is_16bit(in->Type) ? 65535.0 : 255.0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue