Files
mrktplaats/imageutil.go
T
Joren 25410749db Initial Marktplaats SDK scaffold
Clone the twdehands SDK into mrktplaats and retarget naming and defaults for app.marktplaats.nl while keeping the same request/response bodies and endpoint behavior.
2026-04-15 23:45:49 +02:00

80 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mrktplaats
import (
"bytes"
"image"
"image/jpeg"
_ "image/jpeg" // register JPEG decoder for image.Decode
"io"
)
// maxImageUploadBytes is the threshold above which we attempt to compress an
// image before sending it to the API. The marktplaats endpoints reject payloads
// that are too large (HTTP 413 / LIMIT_UNEXPECTED_FILE).
const maxImageUploadBytes = 900 * 1024 // 900 KB
// autoCompressImage reads all bytes from r and, if the result exceeds
// maxImageUploadBytes, decodes it as an image and re-encodes it as a JPEG at
// progressively smaller dimensions until it fits. If the data cannot be decoded
// as a recognised image format it is returned unchanged (the server will then
// return whatever error it normally would). The original data is also returned
// unchanged if it is already within the size limit.
func autoCompressImage(r io.Reader) ([]byte, error) {
data, err := io.ReadAll(r)
if err != nil {
return nil, err
}
if len(data) <= maxImageUploadBytes {
return data, nil
}
src, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
// Not a format we can handle — return as-is.
return data, nil
}
for maxDim := 1200; maxDim >= 300; maxDim = maxDim * 3 / 4 {
scaled := scaleImageNN(src, maxDim)
var buf bytes.Buffer
if err := jpeg.Encode(&buf, scaled, &jpeg.Options{Quality: 80}); err != nil {
return data, nil // encoding failed, return original
}
if buf.Len() <= maxImageUploadBytes {
return buf.Bytes(), nil
}
}
return data, nil // could not get small enough, let the server handle it
}
// scaleImageNN scales src down so that neither dimension exceeds maxDim,
// preserving the aspect ratio using nearest-neighbour sampling.
// Returns src unchanged if it already fits within maxDim×maxDim.
func scaleImageNN(src image.Image, maxDim int) image.Image {
bounds := src.Bounds()
w, h := bounds.Dx(), bounds.Dy()
dstW, dstH := w, h
if dstW > maxDim {
dstH = dstH * maxDim / dstW
dstW = maxDim
}
if dstH > maxDim {
dstW = dstW * maxDim / dstH
dstH = maxDim
}
if dstW == w && dstH == h {
return src
}
dst := image.NewRGBA(image.Rect(0, 0, dstW, dstH))
for y := 0; y < dstH; y++ {
srcY := bounds.Min.Y + y*h/dstH
for x := 0; x < dstW; x++ {
srcX := bounds.Min.X + x*w/dstW
dst.Set(x, y, src.At(srcX, srcY))
}
}
return dst
}