saveImageToFitBytes tries to save the image to fit into the specified max bytes by lowering the quality. It returns the image data that fits the requirement or the best effort data if it was not possible to fit into the limit.
( ctx context.Context, img *vips.Image, format imagetype.Type, startQuality int, target int, o *options.Options, )
| 16 | // by lowering the quality. It returns the image data that fits the requirement |
| 17 | // or the best effort data if it was not possible to fit into the limit. |
| 18 | func saveImageToFitBytes( |
| 19 | ctx context.Context, |
| 20 | img *vips.Image, |
| 21 | format imagetype.Type, |
| 22 | startQuality int, |
| 23 | target int, |
| 24 | o *options.Options, |
| 25 | ) (imagedata.ImageData, error) { |
| 26 | var newQuality int |
| 27 | |
| 28 | // Start with the specified quality and go down from there. |
| 29 | quality := startQuality |
| 30 | |
| 31 | // We will probably save the image multiple times, so we need to process its pixels |
| 32 | // to ensure that it is in random access mode. |
| 33 | if err := img.CopyMemory(); err != nil { |
| 34 | return nil, err |
| 35 | } |
| 36 | |
| 37 | for { |
| 38 | // Check for timeout or cancellation before each attempt as we might spend too much |
| 39 | // time processing the image or making previous attempts. |
| 40 | if err := server.CheckTimeout(ctx); err != nil { |
| 41 | return nil, err |
| 42 | } |
| 43 | |
| 44 | o.Set(keys.Quality, quality) |
| 45 | |
| 46 | imgdata, err := img.Save(format, quality, o) |
| 47 | if err != nil { |
| 48 | return nil, err |
| 49 | } |
| 50 | |
| 51 | size, err := imgdata.Size() |
| 52 | if err != nil { |
| 53 | imgdata.Close() |
| 54 | return nil, err |
| 55 | } |
| 56 | |
| 57 | // If we fit the limit or quality is too low, return the result. |
| 58 | if size <= target || quality <= 10 { |
| 59 | return imgdata, err |
| 60 | } |
| 61 | |
| 62 | // We don't need the image data anymore, close it to free resources. |
| 63 | imgdata.Close() |
| 64 | |
| 65 | // Tune quality for the next attempt based on how much we exceed the limit. |
| 66 | delta := float64(size) / float64(target) |
| 67 | switch { |
| 68 | case delta > 3: |
| 69 | newQuality = imath.Scale(quality, 0.25) |
| 70 | case delta > 1.5: |
| 71 | newQuality = imath.Scale(quality, 0.5) |
| 72 | default: |
| 73 | newQuality = imath.Scale(quality, 0.75) |
| 74 | } |
| 75 |
no test coverage detected