Example #1
0
func TestCrop(t *testing.T) {
	img := image("watermelon.jpg")

	m, err := format.MetadataBytes(img)
	assert.Nil(t, err)
	assert.Equal(t, m.Width, 398)
	assert.Equal(t, m.Height, 536)

	// Verify cropping to fit.
	thumb, err := Thumbnail(img, Options{Width: 300, Height: 400, Crop: true})
	if assert.Nil(t, err) {
		assert.Nil(t, isSize(thumb, format.Jpeg, 300, 400, false))
	}

	// Verify cropping to fit, too big.
	thumb, err = Thumbnail(img, Options{Width: 2000, Height: 1500, Crop: true})
	if assert.Nil(t, err) {
		assert.Nil(t, isSize(thumb, format.Jpeg, 398, 299, false))
	}

	// Verify cropping to fit, same result size.
	thumb, err = Thumbnail(img, Options{Width: 796, Height: 1072, Crop: true})
	if assert.Nil(t, err) {
		assert.Nil(t, isSize(thumb, format.Jpeg, 398, 536, false))
	}
}
Example #2
0
func TestThumbnail(t *testing.T) {
	img := image("watermelon.jpg")

	m, err := format.MetadataBytes(img)
	if !assert.Nil(t, err) {
		return
	}
	assert.Equal(t, m.Width, 398)
	assert.Equal(t, m.Height, 536)

	// Verify scaling down to fit completely into box.
	thumb, err := Thumbnail(img, Options{Width: 200, Height: 300})
	if assert.Nil(t, err) {
		assert.Nil(t, isSize(thumb, format.Jpeg, 200, 270, false))
	}

	// Verify scaling down to have width fit.
	thumb, err = Thumbnail(img, Options{Width: 200})
	if assert.Nil(t, err) {
		assert.Nil(t, isSize(thumb, format.Jpeg, 200, 270, false))
	}

	// Verify scaling down to have height fit.
	thumb, err = Thumbnail(img, Options{Height: 300})
	if assert.Nil(t, err) {
		assert.Nil(t, isSize(thumb, format.Jpeg, 223, 300, false))
	}

	// Verify that we don't scale up.
	thumb, err = Thumbnail(img, Options{Width: 2048, Height: 2048})
	if assert.Nil(t, err) {
		assert.Nil(t, isSize(thumb, format.Jpeg, 398, 536, false))
	}
}
Example #3
0
func TestConversion(t *testing.T) {
	var formatTest = []struct {
		filename    string
		in          format.Format
		outLossless format.Format
	}{
		{"2px.gif", format.Gif, format.Png},
		{"2px.png", format.Png, format.Png},
		{"2px.jpg", format.Jpeg, format.Jpeg},
		{"2px.webp", format.Webp, format.Png},
	}
	for _, f := range formatTest {
		img := image(f.filename)

		m, err := format.MetadataBytes(img)
		if assert.Nil(t, err, "format: %s", f.in) {
			assert.Equal(t, m.Format, f.in, "format: %s", f.in)
			assert.Equal(t, m.Width, 2, "format: %s", f.in)
			assert.Equal(t, m.Height, 3, "format: %s", f.in)

			for _, of := range []format.Format{format.Png, format.Jpeg, format.Webp} {
				// If we ask for a specific format, it should return that.
				thumb, err := Thumbnail(img, Options{Width: 1024, Height: 1024, Save: format.SaveOptions{Format: of}})
				if assert.Nil(t, err, "formats: %s -> %s", f.in, of) {
					assert.Nil(t, isSize(thumb, of, 2, 3, false), "formats: %s -> %s", f.in, of)
				}
			}
		}

	}
}
Example #4
0
func isSize(image []byte, f format.Format, width, height int, alpha bool) error {
	m, err := format.MetadataBytes(image)
	if err != nil {
		return err
	}
	if m.Width != width || m.Height != height {
		return fmt.Errorf("Got %dx%d != want %dx%d", m.Width, m.Height, width, height)
	}
	if m.Format != f {
		return fmt.Errorf("Format %s!=%s", m.Format, f)
	}
	if m.HasAlpha != alpha {
		return fmt.Errorf("HasAlpha %t!=%t", m.HasAlpha, alpha)
	}
	return nil
}
Example #5
0
func isSize(filename string, f format.Format, width, height int) error {
	image, code := fetch(filename)
	if code != 200 {
		return fmt.Errorf("HTTP error %d", code)
	}

	m, err := format.MetadataBytes(image)
	if err != nil {
		return err
	}
	if m.Width != width || m.Height != height {
		return fmt.Errorf("Width %d!=%d or Height %d!=%d", m.Width, width, m.Height, height)
	}
	if m.Format != f {
		return fmt.Errorf("Format %s!=%s", m.Format, f)
	}
	return nil
}
Example #6
0
func TestRotation(t *testing.T) {
	for i := 0; i <= 8; i++ {
		// Verify that New() correctly translates dimensions.
		img := image("orient" + strconv.Itoa(i) + ".jpg")

		m, err := format.MetadataBytes(img)
		if !assert.Nil(t, err) {
			continue
		}
		assert.Equal(t, m.Width, 48)
		assert.Equal(t, m.Height, 80)

		// Verify that img.Thumbnail() maintains orientation.
		thumb, err := Thumbnail(img, Options{Width: 40, Height: 40})
		if assert.Nil(t, err) {
			assert.Nil(t, isSize(thumb, format.Jpeg, 24, 40, false))
		}

		// TODO: Figure out how to test crop.
	}
}
Example #7
0
// Thumbnail scales or crops a compressed image blob according to the
// Options specified in o and returns a compressed image.
// Should be called from a thread pool with runtime.LockOSThread() locked.
func Thumbnail(blob []byte, o Options) ([]byte, error) {
	if o.MaxProcessingDuration > 0 {
		timer := time.AfterFunc(o.MaxProcessingDuration, func() {
			panic(fmt.Sprintf("Thumbnail took longer than %v", o.MaxProcessingDuration))
		})
		defer timer.Stop()
	}

	// Free some thread-local caches. Safe to call unnecessarily.
	defer vips.ThreadShutdown()

	m, err := format.MetadataBytes(blob)
	if err != nil {
		return nil, err
	}

	o, err = o.Check(m)
	if err != nil {
		return nil, err
	}

	// If source image is lossy, disable lossless.
	if m.Format == format.Jpeg {
		o.Save.Lossless = false
	}

	// Figure out size to scale image down to.  For crop, this is the
	// intermediate size the original image would have to be scaled to
	// be cropped to requested size.
	iw, ih, trustWidth := scaleAspect(m.Width, m.Height, o.Width, o.Height, !o.Crop)

	// 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/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, m.Format == format.Jpeg)
	image, err := load(blob, m.Format, psf)
	if err != nil {
		return nil, err
	}
	defer image.Close()

	if err := srgb(image); err != nil {
		return nil, err
	}

	if err := resize(image, iw, ih, o.FastResize, o.BlurSigma, o.Sharpen && shrinking); err != nil {
		return nil, err
	}

	// Make sure we generate images with 8 bits per channel.  Do this before the
	// rotate to reduce the amount of data that needs to be copied.
	if image.ImageGetBandFormat() != vips.BandFormatUchar {
		if err := image.Cast(vips.BandFormatUchar); err != nil {
			return nil, err
		}
	}

	if o.Crop {
		if err = crop(image, o.Width, o.Height); err != nil {
			return nil, err
		}
	}

	if image.HasAlpha() {
		if min, err := minTransparency(image); err == nil && min >= 0.9 {
			if err := image.Flatten(); err != nil {
				return nil, err
			}
		}
	}

	if err := m.Orientation.Apply(image); err != nil {
		return nil, err
	}

	return format.Save(image, o.Save)
}