1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2024-11-24 08:12:38 +02:00

TIFF support

This commit is contained in:
DarthSim 2019-09-27 17:49:52 +06:00
parent 7d8145360c
commit 5e18d59f80
7 changed files with 170 additions and 5 deletions

View File

@ -9,7 +9,7 @@ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/reposit
&& apk --no-cache upgrade \
&& apk add --no-cache curl git ca-certificates go gcc g++ make musl-dev fftw-dev glib-dev libtool expat-dev \
libjpeg-turbo-dev libpng-dev libwebp-dev giflib-dev librsvg-dev libexif-dev lcms2-dev libimagequant-dev \
libheif-dev
libheif-dev tiff-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 libltdl expat libjpeg-turbo libpng \
libwebp giflib librsvg libgsf libexif lcms2 libimagequant libheif \
libwebp giflib librsvg libgsf libexif lcms2 libimagequant libheif tiff\
&& rm -rf /var/cache/apk*
COPY --from=0 /usr/local/bin/imgproxy /usr/local/bin/

121
image_size/tiff.go Normal file
View File

@ -0,0 +1,121 @@
package imageSize
import (
"bufio"
"bytes"
"encoding/binary"
"io"
)
var (
tiffLeHeader = []byte("II\x2A\x00")
tiffBeHeader = []byte("MM\x00\x2A")
)
const (
tiffDtByte = 1
tiffDtShort = 3
tiffDtLong = 4
tiffImageWidth = 256
tiffImageLength = 257
)
type tiffReader interface {
io.Reader
Discard(n int) (discarded int, err error)
}
func asTiffReader(r io.Reader) tiffReader {
if rr, ok := r.(tiffReader); ok {
return rr
}
return bufio.NewReader(r)
}
type TiffFormatError string
func (e TiffFormatError) Error() string { return "invalid TIFF format: " + string(e) }
func DecodeTiffMeta(rr io.Reader) (*Meta, error) {
var (
tmp [12]byte
byteOrder binary.ByteOrder
)
r := asTiffReader(rr)
if _, err := io.ReadFull(r, tmp[:8]); err != nil {
return nil, err
}
switch {
case bytes.Equal(tiffLeHeader, tmp[0:4]):
byteOrder = binary.LittleEndian
case bytes.Equal(tiffBeHeader, tmp[0:4]):
byteOrder = binary.BigEndian
default:
return nil, TiffFormatError("malformed header")
}
ifdOffset := int(byteOrder.Uint32(tmp[4:8]))
if _, err := r.Discard(ifdOffset - 8); err != nil {
return nil, err
}
if _, err := io.ReadFull(r, tmp[0:2]); err != nil {
return nil, err
}
numItems := int(byteOrder.Uint16(tmp[0:2]))
var width, height int
for i := 0; i < numItems; i++ {
if _, err := io.ReadFull(r, tmp[:]); err != nil {
return nil, err
}
tag := byteOrder.Uint16(tmp[0:2])
if tag != tiffImageWidth && tag != tiffImageLength {
continue
}
datatype := byteOrder.Uint16(tmp[2:4])
var value int
switch datatype {
case tiffDtByte:
value = int(tmp[9])
case tiffDtShort:
value = int(byteOrder.Uint16(tmp[8:10]))
case tiffDtLong:
value = int(byteOrder.Uint32(tmp[8:12]))
default:
return nil, TiffFormatError("unsupported IFD entry datatype")
}
if tag == tiffImageWidth {
width = value
} else {
height = value
}
if width > 0 && height > 0 {
return &Meta{
Format: "tiff",
Width: width,
Height: height,
}, nil
}
}
return nil, TiffFormatError("image dimensions are not specified")
}
func init() {
RegisterFormat(string(tiffLeHeader), DecodeTiffMeta)
RegisterFormat(string(tiffBeHeader), DecodeTiffMeta)
}

View File

@ -24,6 +24,7 @@ const (
imageTypeICO = imageType(C.ICO)
imageTypeSVG = imageType(C.SVG)
imageTypeHEIC = imageType(C.HEIC)
imageTypeTIFF = imageType(C.TIFF)
contentDispositionFilenameFallback = "image"
)
@ -38,6 +39,7 @@ var (
"ico": imageTypeICO,
"svg": imageTypeSVG,
"heic": imageTypeHEIC,
"tiff": imageTypeTIFF,
}
mimes = map[imageType]string{
@ -47,6 +49,7 @@ var (
imageTypeGIF: "image/gif",
imageTypeICO: "image/x-icon",
imageTypeHEIC: "image/heif",
imageTypeTIFF: "image/tiff",
}
contentDispositionsFmt = map[imageType]string{
@ -56,6 +59,7 @@ var (
imageTypeGIF: "inline; filename=\"%s.gif\"",
imageTypeICO: "inline; filename=\"%s.ico\"",
imageTypeHEIC: "inline; filename=\"%s.heic\"",
imageTypeTIFF: "inline; filename=\"%s.tiff\"",
}
)

View File

@ -547,7 +547,7 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
switch {
case po.PreferWebP && vipsTypeSupportSave[imageTypeWEBP]:
po.Format = imageTypeWEBP
case vipsTypeSupportSave[imgdata.Type] && imgdata.Type != imageTypeHEIC:
case vipsTypeSupportSave[imgdata.Type] && imgdata.Type != imageTypeHEIC && imgdata.Type != imageTypeTIFF:
po.Format = imgdata.Type
default:
po.Format = imageTypeJPEG

29
vips.c
View File

@ -13,6 +13,9 @@
#define VIPS_SUPPORT_SVG \
(VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 3))
#define VIPS_SUPPORT_TIFF \
(VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 6))
#define VIPS_SUPPORT_MAGICK \
(VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 7))
@ -79,6 +82,8 @@ vips_type_find_load_go(int imgtype) {
return vips_type_find("VipsOperation", "svgload_buffer");
case (HEIC):
return vips_type_find("VipsOperation", "heifload_buffer");
case (TIFF):
return vips_type_find("VipsOperation", "tiffload_buffer");
}
return 0;
}
@ -99,6 +104,8 @@ vips_type_find_save_go(int imgtype) {
return vips_type_find("VipsOperation", "magicksave_buffer");
case (HEIC):
return vips_type_find("VipsOperation", "heifsave_buffer");
case (TIFF):
return vips_type_find("VipsOperation", "tiffsave_buffer");
}
return 0;
@ -164,6 +171,16 @@ vips_heifload_go(void *buf, size_t len, VipsImage **out) {
#endif
}
int
vips_tiffload_go(void *buf, size_t len, VipsImage **out) {
#if VIPS_SUPPORT_TIFF
return vips_tiffload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
#else
vips_error("vips_tiffload_go", "Loading TIFF is not supported (libvips 8.6+ reuired)");
return 1;
#endif
}
int
vips_get_orientation(VipsImage *image) {
#ifdef VIPS_META_ORIENTATION
@ -485,7 +502,17 @@ vips_heifsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
#if VIPS_SUPPORT_HEIF
return vips_heifsave_buffer(in, buf, len, "Q", quality, NULL);
#else
vips_error("vips_heifsave_go", "Saving HEIF is not supported");
vips_error("vips_heifsave_go", "Saving HEIF is not supported (libvips 8.8+ reuired)");
return 1;
#endif
}
int
vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
#if VIPS_SUPPORT_TIFF
return vips_tiffsave_buffer(in, buf, len, "Q", quality, NULL);
#else
vips_error("vips_tiffsave_go", "Saving TIFF is not supported (libvips 8.6+ reuired)");
return 1;
#endif
}

10
vips.go
View File

@ -91,6 +91,9 @@ func initVips() {
if int(C.vips_type_find_load_go(C.int(imageTypeHEIC))) != 0 {
vipsTypeSupportLoad[imageTypeHEIC] = true
}
if int(C.vips_type_find_load_go(C.int(imageTypeTIFF))) != 0 {
vipsTypeSupportLoad[imageTypeTIFF] = true
}
// we load ICO with github.com/mat/besticon/ico and send decoded data to vips
vipsTypeSupportLoad[imageTypeICO] = true
@ -113,6 +116,9 @@ func initVips() {
if int(C.vips_type_find_save_go(C.int(imageTypeHEIC))) != 0 {
vipsTypeSupportSave[imageTypeHEIC] = true
}
if int(C.vips_type_find_save_go(C.int(imageTypeTIFF))) != 0 {
vipsTypeSupportSave[imageTypeTIFF] = true
}
if conf.JpegProgressive {
vipsConf.JpegProgressive = C.int(1)
@ -199,6 +205,8 @@ func (img *vipsImage) Load(data []byte, imgtype imageType, shrink int, scale flo
tmp = C.vips_image_new_from_memory_copy(unsafe.Pointer(&rawData[0]), C.size_t(width*height*4), C.int(width), C.int(height), 4, C.VIPS_FORMAT_UCHAR)
case imageTypeHEIC:
err = C.vips_heifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
case imageTypeTIFF:
err = C.vips_tiffload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
}
if err != 0 {
return vipsError()
@ -233,6 +241,8 @@ func (img *vipsImage) Save(imgtype imageType, quality int) ([]byte, context.Canc
err = C.vips_icosave_go(img.VipsImage, &ptr, &imgsize)
case imageTypeHEIC:
err = C.vips_heifsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
case imageTypeTIFF:
err = C.vips_tiffsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
}
if err != 0 {
C.g_free_go(&ptr)

5
vips.h
View File

@ -12,7 +12,8 @@ enum ImgproxyImageTypes {
GIF,
ICO,
SVG,
HEIC
HEIC,
TIFF
};
int vips_initialize();
@ -31,6 +32,7 @@ int vips_webpload_go(void *buf, size_t len, double scale, int pages, VipsImage *
int vips_gifload_go(void *buf, size_t len, int pages, VipsImage **out);
int vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out);
int vips_heifload_go(void *buf, size_t len, VipsImage **out);
int vips_tiffload_go(void *buf, size_t len, VipsImage **out);
int vips_get_orientation(VipsImage *image);
void vips_strip_meta(VipsImage *image);
@ -83,5 +85,6 @@ int vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality);
int vips_gifsave_go(VipsImage *in, void **buf, size_t *len);
int vips_icosave_go(VipsImage *in, void **buf, size_t *len);
int vips_heifsave_go(VipsImage *in, void **buf, size_t *len, int quality);
int vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality);
void vips_cleanup();