DarthSim 5 éve
szülő
commit
5e18d59f80
7 módosított fájl, 170 hozzáadás és 5 törlés
  1. 2 2
      docker/Dockerfile
  2. 121 0
      image_size/tiff.go
  3. 4 0
      image_type.go
  4. 1 1
      process.go
  5. 28 1
      vips.c
  6. 10 0
      vips.go
  7. 4 1
      vips.h

+ 2 - 2
docker/Dockerfile

@@ -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 - 0
image_size/tiff.go

@@ -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)
+}

+ 4 - 0
image_type.go

@@ -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\"",
 	}
 )
 

+ 1 - 1
process.go

@@ -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

+ 28 - 1
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 - 0
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)

+ 4 - 1
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();