diff --git a/docker/dockerfile-api b/docker/dockerfile-api index 2c16fd63..f8e170cd 100644 --- a/docker/dockerfile-api +++ b/docker/dockerfile-api @@ -29,6 +29,7 @@ ARG STORAGE_DIR=storage ARG LOGS_DIR=logs ARG MEDIA_DIR=media ARG FIXTURES_DIR=fixture +ARG TZ=Asia/Singapore # ---------------------------------------------------------------------------------------------------------------------- # BUILDER STAGE @@ -41,10 +42,17 @@ ARG BINARY_NAME ARG APP_VERSION ARG BUILD_TAGS +# Install system dependencies required to build with CGO and libwebp support. +RUN apk add --no-cache \ + build-base=0.5-r3 \ + pkgconf=2.4.3-r0 \ + libwebp-dev=1.5.0-r0 + # Configure Go build cache and module cache under our APP_DIR. ENV GOPATH=${APP_DIR}/.gopath ENV GOMODCACHE=${APP_DIR}/.gopath/pkg/mod ENV GOCACHE=${APP_DIR}/.gocache +ENV CGO_ENABLED=1 # Create the Go module & build cache directories. RUN mkdir -p ${GOMODCACHE} ${GOCACHE} @@ -59,14 +67,13 @@ RUN go mod download # Copy remaining source code into the builder. COPY . . -# Compile a statically-linked binary. +# Compile the application binary with CGO enabled so WebP encoding is available. # -# * CGO_ENABLED=0: disable CGO for static builds. # * -tags: apply build tags. # * -o: output binaries path/name. # * -ldflags: strip symbols and inject version. # -RUN CGO_ENABLED=0 go build \ +RUN go build \ -tags "${BUILD_TAGS}" \ -o ${APP_DIR}/${BINARY_NAME} \ -ldflags="-s -w -X main.Version=${APP_VERSION}" \ @@ -89,9 +96,12 @@ ARG MEDIA_DIR ARG FIXTURES_DIR ARG APP_HOST_PORT -# Install timezone data so Go’s time.* functions work correctly. -RUN apk add --no-cache tzdata -ENV TZ=Asia/Singapore +# Timezone configuration (default to Asia/Singapore). +ARG TZ=Asia/Singapore + +# Install timezone data and runtime dependencies for the CGO-enabled binary. +RUN apk add --no-cache tzdata=2025b-r0 libwebp=1.5.0-r0 +ENV TZ=${TZ} # Create the system group for our non-root user. RUN addgroup -S ${APP_GROUP} diff --git a/pkg/images/image.go b/pkg/images/image.go index c7da413a..b84a639b 100644 --- a/pkg/images/image.go +++ b/pkg/images/image.go @@ -26,7 +26,6 @@ import ( _ "golang.org/x/image/webp" "github.com/andybalholm/brotli" - "github.com/chai2010/webp" "github.com/gen2brain/avif" "github.com/klauspost/compress/zstd" ) @@ -533,8 +532,7 @@ func Save(path string, img stdimage.Image, ext string, quality int) error { encoder := &png.Encoder{CompressionLevel: png.DefaultCompression} return encoder.Encode(fh, img) case ".webp": - options := &webp.Options{Lossless: false, Quality: float32(quality)} - return webp.Encode(fh, img, options) + return encodeWebp(fh, img, quality) default: options := &jpeg.Options{Quality: quality} return jpeg.Encode(fh, img, options) diff --git a/pkg/images/image_test.go b/pkg/images/image_test.go index 417f6ce0..53bedd7c 100644 --- a/pkg/images/image_test.go +++ b/pkg/images/image_test.go @@ -867,6 +867,10 @@ func TestSaveJPEG(t *testing.T) { func TestSaveWebP(t *testing.T) { t.Parallel() + if !webpEncodeSupported() { + t.Skip("webp encoding requires cgo") + } + dir := t.TempDir() path := filepath.Join(dir, "photo.webp") diff --git a/pkg/images/webp_encode_cgo.go b/pkg/images/webp_encode_cgo.go new file mode 100644 index 00000000..7fe24062 --- /dev/null +++ b/pkg/images/webp_encode_cgo.go @@ -0,0 +1,19 @@ +//go:build cgo + +package images + +import ( + stdimage "image" + "io" + + "github.com/chai2010/webp" +) + +func encodeWebp(w io.Writer, img stdimage.Image, quality int) error { + options := &webp.Options{Lossless: false, Quality: float32(quality)} + return webp.Encode(w, img, options) +} + +func webpEncodeSupported() bool { + return true +} diff --git a/pkg/images/webp_encode_stub.go b/pkg/images/webp_encode_stub.go new file mode 100644 index 00000000..098d5157 --- /dev/null +++ b/pkg/images/webp_encode_stub.go @@ -0,0 +1,17 @@ +//go:build !cgo + +package images + +import ( + "errors" + stdimage "image" + "io" +) + +func encodeWebp(_ io.Writer, _ stdimage.Image, _ int) error { + return errors.New("webp encoding requires cgo support") +} + +func webpEncodeSupported() bool { + return false +}