Support creating thumbnails using the avif command

This commit is contained in:
Trevor Slocum 2021-05-12 14:49:21 -07:00
parent 442e948cec
commit 6b88f0cd4d
8 changed files with 53 additions and 19 deletions

View File

@ -1,4 +1,4 @@
# Should contain src/github.com/Kagami/go-avif # Should contain src/github.com/kagami/go-avif
export GOPATH = $(PWD)/../../../.. export GOPATH = $(PWD)/../../../..
all: build all: build

View File

@ -1,8 +1,8 @@
# go-avif [![Build Status](https://travis-ci.org/Kagami/go-avif.svg?branch=master)](https://travis-ci.org/Kagami/go-avif) [![GoDoc](https://godoc.org/github.com/Kagami/go-avif?status.svg)](https://godoc.org/github.com/Kagami/go-avif) # go-avif [![Build Status](https://travis-ci.org/kagami/go-avif.svg?branch=master)](https://travis-ci.org/kagami/go-avif) [![GoDoc](https://godoc.org/github.com/kagami/go-avif?status.svg)](https://godoc.org/github.com/kagami/go-avif)
go-avif implements go-avif implements
AVIF ([AV1 Still Image File Format](https://aomediacodec.github.io/av1-avif/)) AVIF ([AV1 Still Image File Format](https://aomediacodec.github.io/av1-avif/))
encoder for Go using libaom, the [high quality](https://github.com/Kagami/av1-bench) encoder for Go using libaom, the [high quality](https://github.com/kagami/av1-bench)
AV1 codec. AV1 codec.
## Requirements ## Requirements
@ -18,16 +18,16 @@ sudo apt-get install libaom-dev
To use go-avif in your Go code: To use go-avif in your Go code:
```go ```go
import "github.com/Kagami/go-avif" import "github.com/kagami/go-avif"
``` ```
To install go-avif in your $GOPATH: To install go-avif in your $GOPATH:
```bash ```bash
go get github.com/Kagami/go-avif go get github.com/kagami/go-avif
``` ```
For further details see [GoDoc documentation](https://godoc.org/github.com/Kagami/go-avif). For further details see [GoDoc documentation](https://godoc.org/github.com/kagami/go-avif).
## Example ## Example
@ -40,7 +40,7 @@ import (
"log" "log"
"os" "os"
"github.com/Kagami/go-avif" "github.com/kagami/go-avif"
) )
func main() { func main() {
@ -81,7 +81,7 @@ PNG files to AVIF:
```bash ```bash
# Compile and put avif binary to $GOPATH/bin # Compile and put avif binary to $GOPATH/bin
go get github.com/Kagami/go-avif/... go get github.com/kagami/go-avif/...
# Encode JPEG to AVIF with default settings # Encode JPEG to AVIF with default settings
avif -e cat.jpg -o kitty.avif avif -e cat.jpg -o kitty.avif
@ -92,12 +92,15 @@ avif -e dog.png -o doggy.avif --best -q 15
# Lossless encoding # Lossless encoding
avif -e pig.png -o piggy.avif --lossless avif -e pig.png -o piggy.avif --lossless
# Create thumbnail
avif -e horse.png -o horsey.avif --thumb=640:480
# Show help # Show help
avif -h avif -h
``` ```
Static 64-bit builds for Windows, macOS and Linux are available at Static 64-bit builds for Windows, macOS and Linux are available at
[releases page](https://github.com/Kagami/go-avif/releases). They include [releases page](https://github.com/kagami/go-avif/releases). They include
latest libaom from git at the moment of build. latest libaom from git at the moment of build.
## Display ## Display

View File

@ -55,6 +55,7 @@ func (e OptionsError) Error() string {
// An EncoderError reports that the encoder error has occured. // An EncoderError reports that the encoder error has occured.
type EncoderError int type EncoderError int
// ToString returns the string representation of an EncoderError.
func (e EncoderError) ToString() string { func (e EncoderError) ToString() string {
switch e { switch e {
case C.AVIF_ERROR_GENERAL: case C.AVIF_ERROR_GENERAL:

View File

@ -1,19 +1,23 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"image" "image"
_ "image/jpeg" _ "image/jpeg"
_ "image/png" _ "image/png"
"io" "io"
"os" "os"
"strconv"
"strings"
"github.com/Kagami/go-avif"
"github.com/docopt/docopt-go" "github.com/docopt/docopt-go"
"github.com/kagami/go-avif"
"github.com/nfnt/resize"
) )
const VERSION = "0.0.0" const version = "0.0.0"
const USAGE = ` const usage = `
Usage: avif [options] -e src_filename -o dst_filename Usage: avif [options] -e src_filename -o dst_filename
AVIF encoder AVIF encoder
@ -23,6 +27,7 @@ Options:
-V, --version Display version number -V, --version Display version number
-e <src>, --encode=<src> Source filename -e <src>, --encode=<src> Source filename
-o <dst>, --output=<dst> Destination filename -o <dst>, --output=<dst> Destination filename
-b <w:h>, --thumb=<w:h> Maximum image dimensions
-q <qp>, --quality=<qp> Compression level (0..63), [default: 25] -q <qp>, --quality=<qp> Compression level (0..63), [default: 25]
-s <spd>, --speed=<spd> Compression speed (0..8), [default: 4] -s <spd>, --speed=<spd> Compression speed (0..8), [default: 4]
-t <td>, --threads=<td> Number of threads (0..64, 0 for all available cores), [default: 0] -t <td>, --threads=<td> Number of threads (0..64, 0 for all available cores), [default: 0]
@ -34,6 +39,7 @@ Options:
type config struct { type config struct {
Encode string Encode string
Output string Output string
Thumb string
Quality int Quality int
Speed int Speed int
Threads int Threads int
@ -58,7 +64,7 @@ func check(cond bool, errStr string) {
func main() { func main() {
var conf config var conf config
opts, err := docopt.ParseArgs(USAGE, nil, VERSION) opts, err := docopt.ParseArgs(usage, nil, version)
checkErr(err) checkErr(err)
err = opts.Bind(&conf) err = opts.Bind(&conf)
checkErr(err) checkErr(err)
@ -103,6 +109,19 @@ func main() {
img, _, err := image.Decode(src) img, _, err := image.Decode(src)
checkErr(err) checkErr(err)
if conf.Thumb != "" {
split := strings.Split(conf.Thumb, ":")
if len(split) != 2 {
checkErr(errors.New("failed to create thumbnail: invalid dimensions, must be in w:h format"))
}
w, err := strconv.Atoi(split[0])
checkErr(err)
h, err := strconv.Atoi(split[1])
checkErr(err)
img = resize.Thumbnail(uint(w), uint(h), img, resize.Lanczos3)
}
err = avif.Encode(dst, img, &avifOpts) err = avif.Encode(dst, img, &avifOpts)
checkErr(err) checkErr(err)
} }

View File

@ -6,7 +6,7 @@ import (
"log" "log"
"os" "os"
"github.com/Kagami/go-avif" "github.com/kagami/go-avif"
) )
const usageHelp = "Usage: %s src.jpg dst.avif" const usageHelp = "Usage: %s src.jpg dst.avif"

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module github.com/kagami/go-avif
go 1.16
require (
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
)

4
go.sum Normal file
View File

@ -0,0 +1,4 @@
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=

9
mp4.go
View File

@ -41,9 +41,8 @@ func ulen(s string) uint32 {
func bflag(b bool, pos uint8) uint8 { func bflag(b bool, pos uint8) uint8 {
if b { if b {
return 1 << (pos - 1) return 1 << (pos - 1)
} else {
return 0
} }
return 0
} }
func writeAll(w io.Writer, writers ...io.WriterTo) (err error) { func writeAll(w io.Writer, writers ...io.WriterTo) (err error) {
@ -744,7 +743,7 @@ func muxFrame(w io.Writer, m image.Image, subsampling image.YCbCrSubsampleRatio,
lengthSize: 4, lengthSize: 4,
baseOffsetSize: 4, baseOffsetSize: 4,
items: []boxILOCItem{ items: []boxILOCItem{
boxILOCItem{ {
itemID: 1, itemID: 1,
extents: []boxILOCItemExtent{{}}, extents: []boxILOCItemExtent{{}},
}, },
@ -752,7 +751,7 @@ func muxFrame(w io.Writer, m image.Image, subsampling image.YCbCrSubsampleRatio,
}, },
itemInfos: boxIINF{ itemInfos: boxIINF{
itemInfos: []boxINFEv2{ itemInfos: []boxINFEv2{
boxINFEv2{ {
itemID: 1, itemID: 1,
itemType: itemTypeAV01, itemType: itemTypeAV01,
itemName: "Image", itemName: "Image",
@ -776,7 +775,7 @@ func muxFrame(w io.Writer, m image.Image, subsampling image.YCbCrSubsampleRatio,
}, },
association: boxIPMA{ association: boxIPMA{
entries: []boxIPMAAssociation{ entries: []boxIPMAAssociation{
boxIPMAAssociation{ {
itemID: 1, itemID: 1,
props: []boxIPMAAssociationProperty{ props: []boxIPMAAssociationProperty{
{false, 1}, // non-essential width/height {false, 1}, // non-essential width/height