added bundle generation
This commit is contained in:
parent
ca06a91dc6
commit
f89883e745
8 changed files with 536 additions and 0 deletions
82
pipeline/05_bundle_gen/convert.go
Normal file
82
pipeline/05_bundle_gen/convert.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
|
||||
_ "github.com/biessek/golang-ico"
|
||||
_ "golang.org/x/image/webp"
|
||||
)
|
||||
|
||||
// convertIconToBase64PNG downloads an icon from S3, converts it to PNG, and returns base64-encoded data.
|
||||
func convertIconToBase64PNG(ctx context.Context, s3Key string, iconsBucket string) (encoded string, width, height int, err error) {
|
||||
data, err := s3Download(ctx, iconsBucket, s3Key)
|
||||
if err != nil {
|
||||
return "", 0, 0, fmt.Errorf("s3 download: %w", err)
|
||||
}
|
||||
|
||||
// Check for SVG (can't decode to raster without external deps)
|
||||
if isSVG(data) {
|
||||
return "", 0, 0, fmt.Errorf("svg not supported")
|
||||
}
|
||||
|
||||
// image.Decode handles PNG, GIF, JPEG, WebP, BMP, and ICO (via registered decoders)
|
||||
img, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return "", 0, 0, fmt.Errorf("decode: %w", err)
|
||||
}
|
||||
|
||||
// Downscale icons >128px to 32x32 to keep bundle sizes reasonable
|
||||
bounds := img.Bounds()
|
||||
w, h := bounds.Dx(), bounds.Dy()
|
||||
if w > 128 || h > 128 {
|
||||
img = resizeNearestNeighbor(img, 32, 32)
|
||||
w, h = 32, 32
|
||||
}
|
||||
|
||||
// Re-encode as PNG
|
||||
var pngBuf bytes.Buffer
|
||||
if err := png.Encode(&pngBuf, img); err != nil {
|
||||
return "", 0, 0, fmt.Errorf("png encode: %w", err)
|
||||
}
|
||||
|
||||
encoded = base64.StdEncoding.EncodeToString(pngBuf.Bytes())
|
||||
return encoded, w, h, nil
|
||||
}
|
||||
|
||||
// resizeNearestNeighbor does a simple nearest-neighbor resize.
|
||||
func resizeNearestNeighbor(src image.Image, dstW, dstH int) image.Image {
|
||||
srcBounds := src.Bounds()
|
||||
srcW := srcBounds.Dx()
|
||||
srcH := srcBounds.Dy()
|
||||
dst := image.NewRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
for y := 0; y < dstH; y++ {
|
||||
srcY := srcBounds.Min.Y + y*srcH/dstH
|
||||
for x := 0; x < dstW; x++ {
|
||||
srcX := srcBounds.Min.X + x*srcW/dstW
|
||||
dst.Set(x, y, src.At(srcX, srcY))
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func isSVG(data []byte) bool {
|
||||
if len(data) < 5 {
|
||||
return false
|
||||
}
|
||||
header := data[:min(256, len(data))]
|
||||
return bytes.Contains(header, []byte("<svg")) || bytes.Contains(header, []byte("<?xml"))
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue