Permalink
Browse files

Go 1.5.3 -> Go 1.6.2. VIPS 8.2.3 -> 8.3.0. Replace ImageMagick with G…

…iflib for loading GIFs. Pre-shrink WebP.
  • Loading branch information...
aaron42net committed Apr 28, 2016
1 parent 203b9fa commit 80d42ac6735b0ea41afcd0c16c7bb9dc8be1303f
Showing with 91 additions and 79 deletions.
  1. +1 −1 Dockerfile
  2. +1 −1 cmd/fotomat/version.go
  3. +5 −6 format/format.go
  4. +0 −17 format/metadata.go
  5. +10 −10 preinstall.sh
  6. +10 −5 thumbnail/thumbnail.go
  7. +1 −1 thumbnail/thumbnail_test.go
  8. +19 −8 thumbnail/utils.go
  9. +30 −16 vips/foreign.go
  10. +14 −14 vips/foreign.h
View
@@ -45,7 +45,7 @@ RUN \
# And remove almost everything else that we installed
apt-get remove -y git automake build-essential libglib2.0-dev libjpeg-dev libpng12-dev \
libwebp-dev libtiff5-dev libexif-dev libmagickwand-dev libfftw3-dev libffi-dev && \
libwebp-dev libtiff5-dev libexif-dev libgif-dev libfftw3-dev libffi-dev && \
apt-get autoremove -y && \
apt-get autoclean && \
apt-get clean && \
View
@@ -8,7 +8,7 @@ import (
const (
// FotomatVersion is updated by git-hooks/pre-commit
FotomatVersion = "2.4.175"
FotomatVersion = "2.4.176"
)
var (
View
@@ -25,13 +25,12 @@ var formatInfo = []struct {
mime string
loadFile func(filename string) (*vips.Image, error)
loadBytes func([]byte) (*vips.Image, error)
metadata func([]byte) (Metadata, error)
}{
{mime: "application/octet-stream", loadFile: nil, loadBytes: nil, metadata: nil},
{mime: "image/jpeg", loadFile: vips.Jpegload, loadBytes: vips.JpegloadBuffer, metadata: nil},
{mime: "image/png", loadFile: vips.Pngload, loadBytes: vips.PngloadBuffer, metadata: nil},
{mime: "image/gif", loadFile: vips.Magickload, loadBytes: vips.MagickloadBuffer, metadata: metadataGif},
{mime: "image/webp", loadFile: vips.Webpload, loadBytes: vips.WebploadBuffer, metadata: nil},
{mime: "application/octet-stream", loadFile: nil, loadBytes: nil},
{mime: "image/jpeg", loadFile: vips.Jpegload, loadBytes: vips.JpegloadBuffer},
{mime: "image/png", loadFile: vips.Pngload, loadBytes: vips.PngloadBuffer},
{mime: "image/gif", loadFile: vips.Gifload, loadBytes: vips.GifloadBuffer},
{mime: "image/webp", loadFile: vips.Webpload, loadBytes: vips.WebploadBuffer},
}
func DetectFormat(blob []byte) Format {
View
@@ -1,9 +1,7 @@
package format
import (
"bytes"
"github.com/die-net/fotomat/vips"
"image/gif"
)
type Metadata struct {
@@ -24,10 +22,6 @@ func MetadataBytes(blob []byte) (Metadata, error) {
}
func (format Format) MetadataBytes(blob []byte) (Metadata, error) {
if metadata := formatInfo[format].metadata; metadata != nil {
return metadata(blob)
}
image, err := format.LoadBytes(blob)
if err != nil {
return Metadata{}, ErrUnknownFormat
@@ -63,14 +57,3 @@ func MetadataImage(image *vips.Image) Metadata {
}
return Metadata{Width: w, Height: h, Orientation: o, HasAlpha: image.HasAlpha()}
}
// vips.MagickloadBuffer completely decodes the image, which is slow and
// unsafe, as we can't check the size before decode. Use Go's GIF reader
// to fetch metadata instead.
func metadataGif(blob []byte) (Metadata, error) {
c, err := gif.DecodeConfig(bytes.NewReader(blob))
if err != nil {
return Metadata{}, err
}
return Metadata{Width: c.Width, Height: c.Height, Orientation: Undefined, Format: Gif}, nil
}
View
@@ -7,8 +7,8 @@ set -euo pipefail
# Usage: sudo ./preinstall.sh
VIPS_VERSION=${VIPS_VERSION:-8.2.3}
GO_VERSION=${GO_VERSION:-1.5.3}
VIPS_VERSION=${VIPS_VERSION:-8.3.0}
GO_VERSION=${GO_VERSION:-1.6.2}
export PATH="/usr/local/bin:/usr/bin:/bin:${PATH:-}"
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
@@ -42,23 +42,23 @@ case "$release" in
debian-[89]|debian-unknown|ubuntu-1[456].*|mint-17.*)
# Debian 8-9 or sid, Ubuntu 14-16, Mint 17
apt-get -q update
apt-get install -y -q --no-install-recommends ca-certificates git curl tar automake build-essential libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libmagickwand-dev libfftw3-dev libffi-dev
apt-get install -y -q --no-install-recommends ca-certificates git curl tar automake build-essential libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libgif-dev libtiff5-dev libexif-dev libfftw3-dev libffi-dev
;;
centos-7*|rhel-7*)
# RHEL/CentOS/SL 7
yum -y install epel-release
yum -y update
yum install -y curl tar findutils git automake make gcc gcc-c++ glib2-devel ImageMagick-devel libexif-devel libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel libxml2-devel libffi-devel jbigkit-devel
yum install -y curl tar findutils git automake make gcc gcc-c++ glib2-devel libexif-devel libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel giflib-devel libxml2-devel libffi-devel jbigkit-devel
;;
fedora-2[1-3])
# Fedora 21-23
yum install -y curl tar findutils git automake make gcc gcc-c++ glib2-devel ImageMagick-devel libexif-devel libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel libxml2-devel libffi-devel jbigkit-devel fftw3-devel fontconfig-devel libtool-ltdl-devel
yum install -y curl tar findutils git automake make gcc gcc-c++ glib2-devel libexif-devel libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel giflib-devel libxml2-devel libffi-devel jbigkit-devel fftw3-devel fontconfig-devel libtool-ltdl-devel
;;
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
# RHEL/CentOS/SL 6
yum -y install epel-release
yum -y update
yum install -y curl tar findutils git automake make gcc gcc-c++ glib2-devel ImageMagick-devel libexif-devel libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel libxml2-devel
yum install -y curl tar findutils git automake make gcc gcc-c++ glib2-devel libexif-devel libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel giflib-devel libxml2-devel
;;
*)
echo "Sorry, I don't yet know how to install on $release ($(uname -a))."
@@ -81,10 +81,10 @@ else
curl -sS http://www.vips.ecs.soton.ac.uk/supported/${VIPS_VERSION%.*}/vips-${VIPS_VERSION}.tar.gz | \
tar --strip-components=1 -C vips-$VIPS_VERSION -xzf -
cd vips-$VIPS_VERSION
./configure --disable-debug --disable-dependency-tracking --disable-static --without-orc \
--with-OpenEXR --with-jpeg --with-lcms --with-libexif --with-magick \
./configure --disable-debug --disable-dependency-tracking --disable-static --without-orc --without-magick \
--with-OpenEXR --with-jpeg --with-lcms --with-libexif --with-giflib \
--with-tiff --with-libwebp --with-png ${VIPS_OPTIONS:-}
make
make -j $( getconf _NPROCESSORS_ONLN 2> /dev/null || echo 1 )
make install
cd ..
rm -rf vips-$VIPS_VERSION
@@ -106,7 +106,7 @@ else
mkdir -p /usr/local/go && \
curl -sS https://storage.googleapis.com/golang/go${GO_VERSION}.${arch}.tar.gz | \
tar --strip-components=1 -C /usr/local/go -xzf -
ln -s ../go/bin/go /usr/local/bin
ln -sf ../go/bin/go /usr/local/bin
echo "Installed $(go version)"
fi
View
@@ -42,9 +42,9 @@ func Thumbnail(blob []byte, o Options) ([]byte, error) {
// Are we shrinking by more than 2.5%?
shrinking := iw < m.Width-m.Width/40 && ih < m.Height-m.Height/40
// Figure out the jpeg shrink factor and load image.
// Figure out the jpeg/webp shrink factor and load image.
// Jpeg shrink rounds up the number of pixels.
psf := preShrinkFactor(m.Width, m.Height, iw, ih, trustWidth, o.FastResize)
psf := preShrinkFactor(m.Width, m.Height, iw, ih, trustWidth, o.FastResize, m.Format == format.Jpeg)
image, err := load(blob, m.Format, psf)
if err != nil {
return nil, err
@@ -89,8 +89,12 @@ func Thumbnail(blob []byte, o Options) ([]byte, error) {
}
func load(blob []byte, f format.Format, shrink int) (*vips.Image, error) {
if f == format.Jpeg && shrink > 1 {
return vips.JpegloadBufferShrink(blob, shrink)
if shrink > 1 {
if f == format.Jpeg {
return vips.JpegloadBufferShrink(blob, shrink)
} else if f == format.Webp {
return vips.WebploadBufferShrink(blob, shrink)
}
}
return f.LoadBytes(blob)
@@ -146,7 +150,8 @@ func resize(image *vips.Image, iw, ih int, fastResize bool, blurSigma float64, s
// If necessary, do a high-quality resize to scale to final size.
if iw < m.Width || ih < m.Height {
if err := image.Resize(float64(iw)/float64(m.Width), float64(ih)/float64(m.Height)); err != nil {
// Vips 8.3 sometimes produces 1px smaller images than desired without the rounding help here.
if err := image.Resize((float64(iw)+0.5)/float64(m.Width), (float64(ih)+0.5)/float64(m.Height)); err != nil {
return err
}
}
@@ -114,7 +114,7 @@ func TestBlurSharpen(t *testing.T) {
assert.Nil(t, err)
l := len(thumb)
thumb, err = Thumbnail(img, Options{Width: 300, Height: 400, BlurSigma: 0.5})
thumb, err = Thumbnail(img, Options{Width: 300, Height: 400, BlurSigma: 0.8})
if assert.Nil(t, err) {
assert.True(t, len(thumb) < l) // Blurry photos will be smaller
}
View
@@ -31,11 +31,11 @@ func scaleAspect(ow, oh, rw, rh int, within bool) (int, int, bool) {
return rw, rh, trustWidth
}
func preShrinkFactor(mw, mh, iw, ih int, trustWidth, fastResize bool) int {
func preShrinkFactor(mw, mh, iw, ih int, trustWidth, fastResize, jpeg bool) int {
// Jpeg shrink rounds up the number of pixels, so calculate
// pre-shrink based on side that matters more.
// pre-shrink based on side that matters more. Webp rounds down.
var shrink float64
if trustWidth {
if trustWidth == jpeg {
shrink = float64(mw) / float64(iw)
} else {
shrink = float64(mh) / float64(ih)
@@ -48,13 +48,24 @@ func preShrinkFactor(mw, mh, iw, ih int, trustWidth, fastResize bool) int {
}
// Jpeg loader can quickly shrink by 2, 4, or 8.
if jpeg {
switch {
case shrink >= 8:
return 8
case shrink >= 4:
return 4
case shrink >= 2:
return 2
default:
return 1
}
}
switch {
case shrink >= 8:
return 8
case shrink >= 4:
return 4
case shrink >= 1024:
return 1024
case shrink >= 2:
return 2
return int(shrink)
default:
return 1
}
View
@@ -10,6 +10,20 @@ import (
"unsafe"
)
func Gifload(filename string) (*Image, error) {
var out *C.struct__VipsImage
cf := C.CString(filename)
e := C.cgo_vips_gifload(cf, &out)
C.free(unsafe.Pointer(cf))
return loadError(out, e)
}
func GifloadBuffer(buf []byte) (*Image, error) {
var out *C.struct__VipsImage
e := C.cgo_vips_gifload_buffer(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), &out)
return loadError(out, e)
}
func Jpegload(filename string) (*Image, error) {
var out *C.struct__VipsImage
cf := C.CString(filename)
@@ -47,20 +61,6 @@ func (in *Image) JpegsaveBuffer(strip bool, q int, optimizeCoding, interlace boo
return saveError(ptr, length, e)
}
func Magickload(filename string) (*Image, error) {
var out *C.struct__VipsImage
cf := C.CString(filename)
e := C.cgo_vips_magickload(cf, &out)
C.free(unsafe.Pointer(cf))
return loadError(out, e)
}
func MagickloadBuffer(buf []byte) (*Image, error) {
var out *C.struct__VipsImage
e := C.cgo_vips_magickload_buffer(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), &out)
return loadError(out, e)
}
func Pngload(filename string) (*Image, error) {
var out *C.struct__VipsImage
cf := C.CString(filename)
@@ -87,14 +87,28 @@ func (in *Image) PngsaveBuffer(compression int, interlace bool) ([]byte, error)
func Webpload(filename string) (*Image, error) {
var out *C.struct__VipsImage
cf := C.CString(filename)
e := C.cgo_vips_webpload(cf, &out)
e := C.cgo_vips_webpload(cf, &out, 1)
C.free(unsafe.Pointer(cf))
return loadError(out, e)
}
func WebploadShrink(filename string, shrink int) (*Image, error) {
var out *C.struct__VipsImage
cf := C.CString(filename)
e := C.cgo_vips_webpload(cf, &out, C.int(shrink))
C.free(unsafe.Pointer(cf))
return loadError(out, e)
}
func WebploadBuffer(buf []byte) (*Image, error) {
var out *C.struct__VipsImage
e := C.cgo_vips_webpload_buffer(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), &out)
e := C.cgo_vips_webpload_buffer(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), &out, 1)
return loadError(out, e)
}
func WebploadBufferShrink(buf []byte, shrink int) (*Image, error) {
var out *C.struct__VipsImage
e := C.cgo_vips_webpload_buffer(unsafe.Pointer(&buf[0]), C.size_t(len(buf)), &out, C.int(shrink))
return loadError(out, e)
}
View
@@ -3,28 +3,28 @@
#include <vips/vips7compat.h>
int
cgo_vips_jpegload(const char *filename, VipsImage **out, int shrink) {
return vips_jpegload(filename, out, "access", VIPS_ACCESS_SEQUENTIAL, "shrink", shrink, NULL);
cgo_vips_gifload(const char *filename, VipsImage **out) {
return vips_gifload(filename, out, NULL);
}
int
cgo_vips_jpegload_buffer(void *buf, size_t len, VipsImage **out, int shrink) {
return vips_jpegload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, "shrink", shrink, NULL);
cgo_vips_gifload_buffer(void *buf, size_t len, VipsImage **out) {
return vips_gifload_buffer(buf, len, out, NULL);
}
int
cgo_vips_jpegsave_buffer(VipsImage *in, void **buf, size_t *len, int strip, int q, int optimize_coding, int interlace) {
return vips_jpegsave_buffer(in, buf, len, "strip", strip, "Q", q, "optimize_coding", optimize_coding, "interlace", interlace, NULL);
cgo_vips_jpegload(const char *filename, VipsImage **out, int shrink) {
return vips_jpegload(filename, out, "access", VIPS_ACCESS_SEQUENTIAL, "shrink", shrink, NULL);
}
int
cgo_vips_magickload(const char *filename, VipsImage **out) {
return vips_magickload(filename, out, NULL);
cgo_vips_jpegload_buffer(void *buf, size_t len, VipsImage **out, int shrink) {
return vips_jpegload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, "shrink", shrink, NULL);
}
int
cgo_vips_magickload_buffer(void *buf, size_t len, VipsImage **out) {
return vips_magickload_buffer(buf, len, out, NULL);
cgo_vips_jpegsave_buffer(VipsImage *in, void **buf, size_t *len, int strip, int q, int optimize_coding, int interlace) {
return vips_jpegsave_buffer(in, buf, len, "strip", strip, "Q", q, "optimize_coding", optimize_coding, "interlace", interlace, NULL);
}
int
@@ -43,13 +43,13 @@ cgo_vips_pngsave_buffer(VipsImage *in, void **buf, size_t *len, int compression,
}
int
cgo_vips_webpload(const char *filename, VipsImage **out) {
return vips_webpload(filename, out, NULL);
cgo_vips_webpload(const char *filename, VipsImage **out, int shrink) {
return vips_webpload(filename, out, "shrink", shrink, NULL);
}
int
cgo_vips_webpload_buffer(void *buf, size_t len, VipsImage **out) {
return vips_webpload_buffer(buf, len, out, NULL);
cgo_vips_webpload_buffer(void *buf, size_t len, VipsImage **out, int shrink) {
return vips_webpload_buffer(buf, len, out, "shrink", shrink, NULL);
}
int

0 comments on commit 80d42ac

Please sign in to comment.