MCPcopy Index your code
hub / github.com/docker/docker-agent / ResizeImage

Function ResizeImage

pkg/chat/image.go:73–178  ·  view source on GitHub ↗

ResizeImage takes raw image bytes and ensures they fit within provider limits (max 2000×2000 pixels, max 4.5 MB). If the image already fits, it is returned unchanged. Otherwise it is scaled down (preserving aspect ratio) and re-encoded. The function tries to produce the smallest output by comparing

(data []byte, mimeType string)

Source from the content-addressed store, hash-verified

71// The function tries to produce the smallest output by comparing PNG and JPEG
72// encoding, and progressively reducing JPEG quality and dimensions if needed.
73func ResizeImage(data []byte, mimeType string) (*ImageResizeResult, error) {
74 img, _, err := image.Decode(bytes.NewReader(data))
75 if err != nil {
76 return nil, fmt.Errorf("decode image: %w", err)
77 }
78
79 bounds := img.Bounds()
80 origW, origH := bounds.Dx(), bounds.Dy()
81
82 // Guard against decompression bombs: reject images whose decoded
83 // dimensions are absurdly large. A small compressed file can expand
84 // to hundreds of megabytes in memory (e.g. 20000×20000×4 ≈ 1.6 GB).
85 if origW > maxDecodedDimension || origH > maxDecodedDimension {
86 return nil, fmt.Errorf("image dimensions too large: %dx%d (max %d)", origW, origH, maxDecodedDimension)
87 }
88
89 // If the image already fits within all limits, return unchanged.
90 if origW <= MaxImageDimension && origH <= MaxImageDimension && len(data) <= MaxImageBytes {
91 return &ImageResizeResult{
92 Data: data,
93 MimeType: mimeType,
94 OriginalWidth: origW,
95 OriginalHeight: origH,
96 Width: origW,
97 Height: origH,
98 Resized: false,
99 }, nil
100 }
101
102 // Scale down to fit within MaxImageDimension, preserving aspect ratio.
103 newW, newH := fitDimensions(origW, origH, MaxImageDimension, MaxImageDimension)
104 resized := scaleImage(img, newW, newH)
105
106 // Try both PNG and JPEG at default quality, pick the smaller one.
107 best, bestMime, err := pickSmallestEncoding(resized)
108 if err != nil {
109 return nil, fmt.Errorf("picking smallest encoding: %w", err)
110 }
111
112 // If still over the byte limit, try JPEG with decreasing quality.
113 if len(best) > MaxImageBytes {
114 for _, q := range []int{70, 55, 40} {
115 encoded, err := encodeJPEG(resized, q)
116 if err != nil {
117 slog.Debug("JPEG encoding failed", "quality", q, "error", err)
118 continue
119 }
120
121 if len(encoded) < len(best) {
122 best = encoded
123 bestMime = "image/jpeg"
124 }
125 if len(best) <= MaxImageBytes {
126 break
127 }
128 }
129 }
130

Callers 7

readImageFileMethod · 0.92
inlineImageFromBase64Function · 0.92
transcodeImageWithMetaFunction · 0.85
ResizeImageBase64Function · 0.85
TestResizeImage_JPEGFunction · 0.85

Calls 5

fitDimensionsFunction · 0.85
scaleImageFunction · 0.85
pickSmallestEncodingFunction · 0.85
encodeJPEGFunction · 0.85
DebugMethod · 0.80

Tested by 3

TestResizeImage_JPEGFunction · 0.68