Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/include.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
uses: fortio/workflows/.github/workflows/releaser.yml@main
with:
description: "Support for high dynamic range synthetic PNG image in go"
binary_name: "demo"
main_path: "./demo"
binary_name: "hdr_demo"
main_path: "./hdr_demo"
dockerfile: "./Dockerfile"
secrets:
GH_PAT: ${{ secrets.GH_PAT }}
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM scratch
COPY demo /usr/bin/demo
COPY hdr_demo /usr/bin/hdr_demo
ENV HOME=/home/user
ENTRYPOINT ["/usr/bin/demo"]
WORKDIR /home/user
ENTRYPOINT ["/usr/bin/hdr_demo"]
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ coverage:
go test -race -coverprofile=coverage.out -covermode=atomic ./...

demo:
go run ./demo
go run ./hdr_demo

.PHONY: lint coverage test demo all
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,48 @@ HDR:
![Mandelbrot HDR](mandelbrot_hdr.png)

## Install
You can get the binary from [releases](https://github.com/fortio/hdr/releases)
Use in your own code importing "fortio.org/hdr" and Encode() away.

You can get the demo binary from [releases](https://github.com/fortio/hdr/releases)

Or just run
```
CGO_ENABLED=0 go install fortio.org/hdr/demo@latest # to install (in ~/go/bin typically) or just
CGO_ENABLED=0 go run fortio.org/hdr@latest # to run without install
CGO_ENABLED=0 go install fortio.org/hdr/hdr_demo@latest # to install (in ~/go/bin typically) or just
CGO_ENABLED=0 go run fortio.org/hdr/hdr_demo@latest # to run without install
```

or
```
brew install fortio/tap/hdr
brew install fortio/tap/hdr_demo
```

or
```
docker run -ti fortio/hdr
docker run -ti -v `pwd`:/home/user fortio/hdr_demo
```


## Usage

```
hdr help

$ hdr_demo help
hdr_demo v1.0.0 usage:
hdr_demo [flags]
or 1 of the special arguments
hdr_demo {help|envhelp|version|buildinfo}
flags:
-chroma float
chroma (saturation) for coloring (default 80)
-hue-freq float
hue frequency multiplier for coloring (higher means more color cycles) (default 0.35)
-light-angle float
light angle in degrees for shading (azimuth) (default 45)
-light-height float
light height for shading (elevation, higher means more light from above) (default 1.5)
-profile-cpu file
write cpu profile to file
-profile-mem file
write memory profile to file
-shading float
range for shading lightness (0 = no shading, 100 = full range from black to white) (default 70)
```
20 changes: 11 additions & 9 deletions hdr.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"compress/zlib"
"encoding/binary"
"fmt"
"hash/crc32"
"image"
"io"
Expand Down Expand Up @@ -180,21 +181,22 @@ func sumAbs(data []byte) int64 {
return s
}

// Encode writes img as a PNG (truecolor 16-bit per channel with alpha) to w.
// Adaptive row filtering (None/Sub/Up/Average/Paeth) is used to minimize file size.
//
// Encode writes img as an HDR PNG 3.0 (truecolor 16-bit per channel with alpha) to the provided writer.
// The white parameter controls HDR output (PNG 3.0 with cICP chunk):
// - white == 0 : standard sRGB PNG (no HDR metadata).
// - white in (0,1] : HDR PQ PNG. Input pixels at this sRGB intensity
// map to SDR reference white (203 nits); brighter pixels extend into
// the HDR range. For example white=0.5 means anything above 50 %
// input brightness will appear brighter than SDR white on HDR displays.
func Encode(w io.Writer, img *image.NRGBA64, white float64) error {
func Encode(writer io.Writer, img *image.NRGBA64, white float64) error {
bounds := img.Bounds()
width := bounds.Dx()
height := bounds.Dy()
if white < 0 || white > 1 {
return fmt.Errorf("white parameter must be in [0,1], got %f", white)
}
// PNG signature
if _, err := w.Write(pngSignature[:]); err != nil {
if _, err := writer.Write(pngSignature[:]); err != nil {
return err
}
// IHDR
Expand All @@ -203,7 +205,7 @@ func Encode(w io.Writer, img *image.NRGBA64, white float64) error {
binary.BigEndian.PutUint32(ihdr[4:8], safecast.MustConv[uint32](height))
ihdr[8] = 16 // bit depth: 16 bits per channel
ihdr[9] = 6 // color type: truecolor with alpha (RGBA)
if err := writeChunk(w, "IHDR", ihdr[:]); err != nil {
if err := writeChunk(writer, "IHDR", ihdr[:]); err != nil {
return err
}
// HDR mode: add cICP chunk (PNG 3.0) signaling BT.2020 + PQ.
Expand All @@ -216,7 +218,7 @@ func Encode(w io.Writer, img *image.NRGBA64, white float64) error {
0, // Matrix coefficients: Identity
1, // Video full range flag
}
if err := writeChunk(w, "cICP", cicp[:]); err != nil {
if err := writeChunk(writer, "cICP", cicp[:]); err != nil {
return err
}
// scaleFactor maps srgbToLinear(white) → SDR reference white in PQ's
Expand Down Expand Up @@ -272,9 +274,9 @@ func Encode(w io.Writer, img *image.NRGBA64, white float64) error {
if err := zw.Close(); err != nil {
return err
}
if err := writeChunk(w, "IDAT", buf.Bytes()); err != nil {
if err := writeChunk(writer, "IDAT", buf.Bytes()); err != nil {
return err
}
// IEND
return writeChunk(w, "IEND", nil)
return writeChunk(writer, "IEND", nil)
}
File renamed without changes.
Loading