mirror of
https://github.com/imgproxy/imgproxy.git
synced 2024-11-24 08:12:38 +02:00
TIFF support
This commit is contained in:
parent
7d8145360c
commit
5e18d59f80
@ -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
121
image_size/tiff.go
Normal 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)
|
||||
}
|
@ -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\"",
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -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
29
vips.c
@ -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
10
vips.go
@ -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
5
vips.h
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user