func TestMain(m *testing.M) { vips.Initialize() vips.LeakSet(true) r := m.Run() vips.ThreadShutdown() vips.Shutdown() os.Exit(r) }
func (p *Pool) worker() { runtime.LockOSThread() for { q := <-p.RequestCh if q == nil { break } s := &Response{} if hasAborted(q.Aborted) { s.Error = ErrAborted } else { s.Blob, s.Error = Thumbnail(q.Blob, q.Options) } q.ResponseCh <- s } vips.ThreadShutdown() runtime.UnlockOSThread() p.wg.Done() }
// 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) }