1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-03-22 20:21:28 +02:00

SVG sources support

This commit is contained in:
DarthSim 2018-12-11 16:02:23 +06:00
parent 280c64a55b
commit 5501c3cff7
7 changed files with 77 additions and 21 deletions

View File

@ -11,7 +11,7 @@ WORKDIR /go/src/github.com/DarthSim/imgproxy
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \
&& apk --no-cache upgrade \
&& apk add --no-cache curl ca-certificates go gcc g++ make musl-dev fftw-dev glib-dev expat-dev \
libjpeg-turbo-dev libpng-dev libwebp-dev giflib-dev libexif-dev lcms2-dev
libjpeg-turbo-dev libpng-dev libwebp-dev giflib-dev librsvg-dev libexif-dev lcms2-dev
# Build ImageMagick
RUN cd /root \
@ -77,7 +77,7 @@ LABEL maintainer="Sergey Alexandrovich <darthsim@gmail.com>"
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \
&& apk --no-cache upgrade \
&& apk add --no-cache bash ca-certificates fftw glib expat libjpeg-turbo libpng \
libwebp giflib libexif lcms2 \
libwebp giflib librsvg libgsf libexif lcms2 \
&& rm -rf /var/cache/apk*
COPY --from=0 /usr/local/bin/imgproxy /usr/local/bin/

View File

@ -6,7 +6,8 @@ At the moment, imgproxy supports only the most popular Web image formats:
* JPEG;
* WebP;
* GIF;
* ICO.
* ICO;
* SVG _(source only)_.
## GIF support

View File

@ -4,5 +4,6 @@ enum types {
PNG,
WEBP,
GIF,
ICO
ICO,
SVG
};

View File

@ -73,6 +73,9 @@ func initVips() {
if int(C.vips_type_find_load_go(C.int(imageTypeGIF))) != 0 {
vipsTypeSupportLoad[imageTypeGIF] = true
}
if int(C.vips_type_find_load_go(C.int(imageTypeSVG))) != 0 {
vipsTypeSupportLoad[imageTypeSVG] = true
}
// we load ICO with github.com/mat/besticon/ico and send decoded data to vips
vipsTypeSupportLoad[imageTypeICO] = true
@ -140,7 +143,7 @@ func extractMeta(img *C.VipsImage) (int, int, int, bool) {
return width, height, angle, flip
}
func calcScale(width, height int, po *processingOptions) float64 {
func calcScale(width, height int, po *processingOptions, imgtype imageType) float64 {
// If we're going only to crop, we need only to scale down to DPR.
// Scaling up while cropping is not optimal on this stage, we'll do it later if needed.
if po.Resize == resizeCrop {
@ -173,7 +176,7 @@ func calcScale(width, height int, po *processingOptions) float64 {
scale = scale * po.Dpr
if !po.Enlarge && scale > 1 {
if !po.Enlarge && scale > 1 && imgtype != imageTypeSVG {
return 1
}
@ -274,22 +277,31 @@ func transformImage(ctx context.Context, img **C.struct__VipsImage, data []byte,
hasAlpha := vipsImageHasAlpha(*img)
if scale := calcScale(imgWidth, imgHeight, po); scale != 1 {
// Do some shrink-on-load
if scale < 1.0 && data != nil {
if shrink := calcShink(scale, imgtype); shrink != 1 {
scale = scale * float64(shrink)
if scale := calcScale(imgWidth, imgHeight, po, imgtype); scale != 1 {
if imgtype == imageTypeSVG && data != nil {
// Load SVG with desired scale
if tmp, err := vipsLoadImage(data, imgtype, 1, scale, false); err == nil {
C.swap_and_clear(img, tmp)
} else {
return err
}
} else {
// Do some shrink-on-load
if scale < 1.0 && data != nil {
if shrink := calcShink(scale, imgtype); shrink != 1 {
scale = scale * float64(shrink)
if tmp, err := vipsLoadImage(data, imgtype, shrink, false); err == nil {
C.swap_and_clear(img, tmp)
} else {
return err
if tmp, err := vipsLoadImage(data, imgtype, shrink, 1.0, false); err == nil {
C.swap_and_clear(img, tmp)
} else {
return err
}
}
}
}
if err = resizeImage(img, scale, hasAlpha); err != nil {
return err
if err = resizeImage(img, scale, hasAlpha); err != nil {
return err
}
}
// Update actual image size after resize
@ -506,7 +518,7 @@ func processImage(ctx context.Context) ([]byte, error) {
}
}
img, err := vipsLoadImage(data, imgtype, 1, po.Format == imageTypeGIF)
img, err := vipsLoadImage(data, imgtype, 1, 1.0, po.Format == imageTypeGIF)
if err != nil {
return nil, err
}
@ -546,7 +558,7 @@ func vipsPrepareWatermark() error {
return nil
}
watermark, err = vipsLoadImage(data, imgtype, 1, false)
watermark, err = vipsLoadImage(data, imgtype, 1, 1.0, false)
if err != nil {
return err
}
@ -593,7 +605,7 @@ func vipsPrepareWatermark() error {
return nil
}
func vipsLoadImage(data []byte, imgtype imageType, shrink int, allPages bool) (*C.struct__VipsImage, error) {
func vipsLoadImage(data []byte, imgtype imageType, shrink int, svgScale float64, allPages bool) (*C.struct__VipsImage, error) {
var img *C.struct__VipsImage
err := C.int(0)
@ -612,6 +624,8 @@ func vipsLoadImage(data []byte, imgtype imageType, shrink int, allPages bool) (*
err = C.vips_webpload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.int(shrink), &img)
case imageTypeGIF:
err = C.vips_gifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), pages, &img)
case imageTypeSVG:
err = C.vips_svgload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(svgScale), &img)
case imageTypeICO:
rawData, width, height, icoErr := icoData(data)
if icoErr != nil {

View File

@ -29,6 +29,7 @@ const (
imageTypeWEBP = imageType(C.WEBP)
imageTypeGIF = imageType(C.GIF)
imageTypeICO = imageType(C.ICO)
imageTypeSVG = imageType(C.SVG)
)
type processingHeaders struct {
@ -45,6 +46,7 @@ var imageTypes = map[string]imageType{
"webp": imageTypeWEBP,
"gif": imageTypeGIF,
"ico": imageTypeICO,
"svg": imageTypeSVG,
}
type gravityType int

22
svg.go Normal file
View File

@ -0,0 +1,22 @@
package main
import (
"image"
goColor "image/color"
"io"
)
func init() {
// Register fake svg decoder. Since we need this only for type detecting, we can
// return fake image sizes
image.RegisterFormat(
"svg",
"<?xml ",
func(io.Reader) (image.Image, error) {
return image.NewRGBA(image.Rect(0, 0, 1, 1)), nil
},
func(io.Reader) (image.Config, error) {
return image.Config{ColorModel: goColor.RGBAModel, Width: 1, Height: 1}, nil
},
)
}

16
vips.h
View File

@ -12,6 +12,9 @@
#define VIPS_SUPPORT_GIF \
(VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 3))
#define VIPS_SUPPORT_SVG \
(VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 3))
#define VIPS_SUPPORT_MAGICK \
(VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 7))
@ -52,6 +55,9 @@ vips_type_find_load_go(int imgtype) {
if (imgtype == GIF) {
return vips_type_find("VipsOperation", "gifload_buffer");
}
if (imgtype == SVG) {
return vips_type_find("VipsOperation", "svgload_buffer");
}
return 0;
}
@ -106,6 +112,16 @@ vips_gifload_go(void *buf, size_t len, int pages, VipsImage **out) {
#endif
}
int
vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out) {
#if VIPS_SUPPORT_SVG
return vips_svgload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, "scale", scale, NULL);
#else
vips_error("vips_svgload_go", "Loading SVG is not supported");
return 1;
#endif
}
int
vips_get_exif_orientation(VipsImage *image) {
const char *orientation;