mirror of
https://github.com/coalaura/ffwebp.git
synced 2025-07-17 22:04:35 +00:00
logging and improvements
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
bin
|
||||
example.*
|
||||
test.*
|
||||
*.exe
|
@ -1,6 +0,0 @@
|
||||
@echo off
|
||||
|
||||
echo Building...
|
||||
go build -o %USERPROFILE%/.bin/ffwebp.exe
|
||||
|
||||
echo Done
|
36
cmd/ffwebp/banner.go
Normal file
36
cmd/ffwebp/banner.go
Normal file
@ -0,0 +1,36 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/coalaura/ffwebp/internal/codec"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
func banner() {
|
||||
codecs := codec.All()
|
||||
|
||||
names := make([]string, len(codecs))
|
||||
|
||||
for i, c := range codecs {
|
||||
names[i] = c.String()
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
|
||||
build := strings.Join(names, ",")
|
||||
|
||||
logx.Printf("ffwebp version %s\n", Version)
|
||||
logx.Printf(
|
||||
" built with %s %s %s\n",
|
||||
runtime.Compiler,
|
||||
runtime.Version(),
|
||||
runtime.GOARCH,
|
||||
)
|
||||
logx.Printf(
|
||||
" configuration: -tags %s\n",
|
||||
build,
|
||||
)
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/gif"
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/jpeg"
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/png"
|
||||
)
|
@ -3,10 +3,13 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
_ "github.com/coalaura/ffwebp/internal/builtins"
|
||||
"github.com/coalaura/ffwebp/internal/codec"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
"github.com/coalaura/ffwebp/internal/opts"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
@ -14,8 +17,6 @@ import (
|
||||
var Version = "dev"
|
||||
|
||||
func main() {
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
flags := codec.Flags([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "input",
|
||||
@ -45,10 +46,17 @@ func main() {
|
||||
Aliases: []string{"l"},
|
||||
Usage: "force lossless mode (overrides --quality)",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "resize",
|
||||
Aliases: []string{"r"},
|
||||
Usage: "WxH, Wx or xH (keep aspect)",
|
||||
&cli.BoolFlag{
|
||||
Name: "silent",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "hides all output",
|
||||
Action: func(_ context.Context, _ *cli.Command, silent bool) error {
|
||||
if silent {
|
||||
logx.SetSilent()
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@ -66,11 +74,14 @@ func main() {
|
||||
}
|
||||
|
||||
if err := app.Run(context.Background(), os.Args); err != nil {
|
||||
log.Fatal(err)
|
||||
logx.Errorf("fatal: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(_ context.Context, cmd *cli.Command) error {
|
||||
banner()
|
||||
|
||||
var (
|
||||
input string
|
||||
output string
|
||||
@ -78,10 +89,12 @@ func run(_ context.Context, cmd *cli.Command) error {
|
||||
common opts.Common
|
||||
|
||||
reader io.Reader = os.Stdin
|
||||
writer io.Writer = os.Stdout
|
||||
writer *countWriter = &countWriter{w: os.Stdout}
|
||||
)
|
||||
|
||||
if input = cmd.String("input"); input != "-" {
|
||||
logx.Printf("opening input file %q\n", filepath.ToSlash(input))
|
||||
|
||||
file, err := os.OpenFile(input, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -90,9 +103,13 @@ func run(_ context.Context, cmd *cli.Command) error {
|
||||
defer file.Close()
|
||||
|
||||
reader = file
|
||||
} else {
|
||||
logx.Printf("reading input from <stdin>\n")
|
||||
}
|
||||
|
||||
if output = cmd.String("output"); output != "-" {
|
||||
logx.Printf("opening output file %q\n", filepath.ToSlash(output))
|
||||
|
||||
file, err := os.OpenFile(output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -100,31 +117,47 @@ func run(_ context.Context, cmd *cli.Command) error {
|
||||
|
||||
defer file.Close()
|
||||
|
||||
writer = file
|
||||
writer = &countWriter{w: file}
|
||||
} else {
|
||||
logx.Printf("writing output to <stdout>\n")
|
||||
}
|
||||
|
||||
common.Quality = cmd.Int("quality")
|
||||
common.Lossless = cmd.Bool("lossless")
|
||||
|
||||
common.FillDefaults()
|
||||
|
||||
sniffed, reader, err := codec.Sniff(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logx.Printf("sniffed codec: %s (%q)\n", sniffed.Codec, sniffed)
|
||||
|
||||
oCodec, err := codec.Detect(output, cmd.String("codec"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iCodec, reader, err := codec.Sniff(reader)
|
||||
logx.Printf("output codec: %s (forced=%v)\n", oCodec, cmd.IsSet("codec"))
|
||||
|
||||
t0 := time.Now()
|
||||
|
||||
img, err := sniffed.Codec.Decode(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
img, err := iCodec.Decode(reader)
|
||||
logx.Printf("decoded image: %dx%d %s in %s\n", img.Bounds().Dx(), img.Bounds().Dy(), colorModel(img), time.Since(t0).Truncate(time.Millisecond))
|
||||
|
||||
t1 := time.Now()
|
||||
|
||||
err = oCodec.Encode(writer, img, common)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resized, err := resize(img, cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logx.Printf("encoded %d KiB in %s\n", (writer.n+1023)/1024, time.Since(t1).Truncate(time.Millisecond))
|
||||
|
||||
return oCodec.Encode(writer, resized, common)
|
||||
return nil
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func resize(img image.Image, cmd *cli.Command) (image.Image, error) {
|
||||
options := strings.ToLower(cmd.String("resize"))
|
||||
|
||||
index := strings.Index(options, "x")
|
||||
if index == -1 {
|
||||
return img, nil
|
||||
}
|
||||
|
||||
var (
|
||||
width int
|
||||
height int
|
||||
)
|
||||
|
||||
wRaw := options[:index]
|
||||
if wRaw != "" {
|
||||
w64, err := strconv.ParseInt(wRaw, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
width = int(max(0, w64))
|
||||
}
|
||||
|
||||
hRaw := options[index:]
|
||||
if hRaw != "" {
|
||||
h64, err := strconv.ParseInt(hRaw, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
height = int(max(0, h64))
|
||||
}
|
||||
|
||||
if width == 0 && height == 0 {
|
||||
return nil, errors.New("at least one size needs to be specified for resizing")
|
||||
}
|
||||
|
||||
resized := imaging.Resize(img, width, height, imaging.Lanczos)
|
||||
|
||||
return resized, nil
|
||||
}
|
32
cmd/ffwebp/utils.go
Normal file
32
cmd/ffwebp/utils.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
func colorModel(img image.Image) string {
|
||||
model := img.ColorModel()
|
||||
|
||||
switch model {
|
||||
case color.RGBAModel:
|
||||
return "RGBA"
|
||||
case color.RGBA64Model:
|
||||
return "RGBA64"
|
||||
case color.NRGBAModel:
|
||||
return "NRGBA"
|
||||
case color.NRGBA64Model:
|
||||
return "NRGBA64"
|
||||
case color.AlphaModel:
|
||||
return "Alpha"
|
||||
case color.Alpha16Model:
|
||||
return "Alpha16"
|
||||
case color.GrayModel:
|
||||
return "Gray"
|
||||
case color.Gray16Model:
|
||||
return "Gray16"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%T", model)
|
||||
}
|
16
cmd/ffwebp/writer.go
Normal file
16
cmd/ffwebp/writer.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import "io"
|
||||
|
||||
type countWriter struct {
|
||||
w io.Writer
|
||||
n int64
|
||||
}
|
||||
|
||||
func (cw *countWriter) Write(p []byte) (int, error) {
|
||||
m, err := cw.w.Write(p)
|
||||
|
||||
cw.n += int64(m)
|
||||
|
||||
return m, err
|
||||
}
|
5
go.mod
5
go.mod
@ -2,9 +2,6 @@ module github.com/coalaura/ffwebp
|
||||
|
||||
go 1.24.2
|
||||
|
||||
require (
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/urfave/cli/v3 v3.3.8
|
||||
)
|
||||
require github.com/urfave/cli/v3 v3.3.8
|
||||
|
||||
require golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
|
||||
|
2
go.sum
2
go.sum
@ -1,7 +1,5 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
|
@ -1,7 +1,7 @@
|
||||
//go:build bmp
|
||||
// +build bmp
|
||||
//go:build bmp || full
|
||||
// +build bmp full
|
||||
|
||||
package main
|
||||
package builtins
|
||||
|
||||
import (
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/bmp"
|
3
internal/builtins/builtins.go
Normal file
3
internal/builtins/builtins.go
Normal file
@ -0,0 +1,3 @@
|
||||
package builtins
|
||||
|
||||
// does nothing :)
|
8
internal/builtins/gif.go
Normal file
8
internal/builtins/gif.go
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build gif || core || full
|
||||
// +build gif core full
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/gif"
|
||||
)
|
8
internal/builtins/jpeg.go
Normal file
8
internal/builtins/jpeg.go
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build jpeg || core || full
|
||||
// +build jpeg core full
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/jpeg"
|
||||
)
|
8
internal/builtins/png.go
Normal file
8
internal/builtins/png.go
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build png || core || full
|
||||
// +build png core full
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/png"
|
||||
)
|
@ -1,7 +1,7 @@
|
||||
//go:build tiff
|
||||
// +build tiff
|
||||
//go:build tiff || full
|
||||
// +build tiff full
|
||||
|
||||
package main
|
||||
package builtins
|
||||
|
||||
import (
|
||||
_ "github.com/coalaura/ffwebp/internal/codec/tiff"
|
@ -18,7 +18,7 @@ func init() {
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func (impl) Name() string {
|
||||
func (impl) String() string {
|
||||
return "bmp"
|
||||
}
|
||||
|
||||
@ -30,20 +30,20 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
return flags
|
||||
}
|
||||
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, error) {
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, []byte, error) {
|
||||
magic := []byte{0x42, 0x4D}
|
||||
|
||||
buf := make([]byte, 2)
|
||||
|
||||
if _, err := reader.ReadAt(buf, 0); err != nil {
|
||||
return 0, err
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if bytes.Equal(buf, magic) {
|
||||
return 100, nil
|
||||
return 100, magic, nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
|
@ -9,12 +9,12 @@ import (
|
||||
)
|
||||
|
||||
type Codec interface {
|
||||
Name() string
|
||||
String() string
|
||||
|
||||
Flags([]cli.Flag) []cli.Flag
|
||||
Extensions() []string
|
||||
|
||||
Sniff(io.ReaderAt) (int, error)
|
||||
Sniff(io.ReaderAt) (int, []byte, error)
|
||||
Decode(io.Reader) (image.Image, error)
|
||||
Encode(io.Writer, image.Image, opts.Common) error
|
||||
}
|
||||
@ -22,7 +22,7 @@ type Codec interface {
|
||||
var codecs = map[string]Codec{}
|
||||
|
||||
func Register(c Codec) {
|
||||
codecs[c.Name()] = c
|
||||
codecs[c.String()] = c
|
||||
}
|
||||
|
||||
func Flags(flags []cli.Flag) []cli.Flag {
|
||||
|
@ -9,7 +9,27 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Sniff(reader io.Reader) (Codec, io.Reader, error) {
|
||||
type Sniffed struct {
|
||||
Header []byte
|
||||
Confidence int
|
||||
Codec Codec
|
||||
}
|
||||
|
||||
func (s *Sniffed) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
for _, b := range s.Header {
|
||||
if b >= 32 && b <= 126 {
|
||||
builder.WriteByte(b)
|
||||
} else {
|
||||
builder.WriteRune('.')
|
||||
}
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func Sniff(reader io.Reader) (*Sniffed, io.Reader, error) {
|
||||
buf, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -18,18 +38,20 @@ func Sniff(reader io.Reader) (Codec, io.Reader, error) {
|
||||
ra := bytes.NewReader(buf)
|
||||
|
||||
var (
|
||||
guess Codec
|
||||
best int
|
||||
magic []byte
|
||||
guess Codec
|
||||
)
|
||||
|
||||
for _, codec := range codecs {
|
||||
confidence, err := codec.Sniff(ra)
|
||||
confidence, header, err := codec.Sniff(ra)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if confidence > best {
|
||||
best = confidence
|
||||
magic = header
|
||||
guess = codec
|
||||
}
|
||||
}
|
||||
@ -38,7 +60,11 @@ func Sniff(reader io.Reader) (Codec, io.Reader, error) {
|
||||
return nil, nil, errors.New("unknown format")
|
||||
}
|
||||
|
||||
return guess, bytes.NewReader(buf), nil
|
||||
return &Sniffed{
|
||||
Header: magic,
|
||||
Confidence: best,
|
||||
Codec: guess,
|
||||
}, bytes.NewReader(buf), nil
|
||||
}
|
||||
|
||||
func Detect(output, override string) (Codec, error) {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/coalaura/ffwebp/internal/codec"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
"github.com/coalaura/ffwebp/internal/opts"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
@ -20,7 +21,7 @@ func init() {
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func (impl) Name() string {
|
||||
func (impl) String() string {
|
||||
return "gif"
|
||||
}
|
||||
|
||||
@ -44,21 +45,25 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
})
|
||||
}
|
||||
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, error) {
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, []byte, error) {
|
||||
magic7a := []byte("GIF87a")
|
||||
magic9a := []byte("GIF89a")
|
||||
|
||||
buf := make([]byte, 6)
|
||||
|
||||
if _, err := reader.ReadAt(buf, 0); err != nil {
|
||||
return 0, err
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if bytes.Equal(buf, magic7a) || bytes.Equal(buf, magic9a) {
|
||||
return 100, nil
|
||||
if bytes.Equal(buf, magic7a) {
|
||||
return 100, magic7a, nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
if bytes.Equal(buf, magic9a) {
|
||||
return 100, magic9a, nil
|
||||
}
|
||||
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
@ -66,6 +71,8 @@ func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
}
|
||||
|
||||
func (impl) Encode(writer io.Writer, img image.Image, options opts.Common) error {
|
||||
logx.Printf("gif: colors=%d\n", numColors)
|
||||
|
||||
return gif.Encode(writer, img, &gif.Options{
|
||||
NumColors: numColors,
|
||||
})
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/coalaura/ffwebp/internal/codec"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
"github.com/coalaura/ffwebp/internal/opts"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
@ -17,7 +18,7 @@ func init() {
|
||||
codec.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) Name() string {
|
||||
func (impl) String() string {
|
||||
return "jpeg"
|
||||
}
|
||||
|
||||
@ -29,20 +30,20 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
return flags
|
||||
}
|
||||
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, error) {
|
||||
marker := []byte{0xFF, 0xD8, 0xFF}
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, []byte, error) {
|
||||
magic := []byte{0xFF, 0xD8, 0xFF}
|
||||
|
||||
buf := make([]byte, 3)
|
||||
|
||||
if _, err := reader.ReadAt(buf, 0); err != nil {
|
||||
return 0, err
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if bytes.Equal(buf, marker) {
|
||||
return 100, nil
|
||||
if bytes.Equal(buf, magic) {
|
||||
return 100, magic, nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
@ -50,6 +51,8 @@ func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
}
|
||||
|
||||
func (impl) Encode(writer io.Writer, img image.Image, options opts.Common) error {
|
||||
logx.Printf("jpeg: quality=%d\n", options.Quality)
|
||||
|
||||
return jpeg.Encode(writer, img, &jpeg.Options{
|
||||
Quality: options.Quality,
|
||||
})
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/coalaura/ffwebp/internal/codec"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
"github.com/coalaura/ffwebp/internal/opts"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
@ -22,7 +23,7 @@ func init() {
|
||||
codec.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) Name() string {
|
||||
func (impl) String() string {
|
||||
return "png"
|
||||
}
|
||||
|
||||
@ -46,20 +47,20 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
})
|
||||
}
|
||||
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, error) {
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, []byte, error) {
|
||||
magic := []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}
|
||||
|
||||
buf := make([]byte, len(magic))
|
||||
|
||||
if _, err := reader.ReadAt(buf, 0); err != nil {
|
||||
return 0, err
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if bytes.Equal(buf, magic) {
|
||||
return 100, nil
|
||||
return 100, magic, nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
@ -67,6 +68,8 @@ func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
}
|
||||
|
||||
func (impl) Encode(writer io.Writer, img image.Image, _ opts.Common) error {
|
||||
logx.Printf("png: compression=%d\n", compression)
|
||||
|
||||
encoder := png.Encoder{
|
||||
CompressionLevel: compressionLevel(compression),
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"golang.org/x/image/tiff"
|
||||
|
||||
"github.com/coalaura/ffwebp/internal/codec"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
"github.com/coalaura/ffwebp/internal/opts"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
@ -24,7 +25,7 @@ func init() {
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func (impl) Name() string {
|
||||
func (impl) String() string {
|
||||
return "tiff"
|
||||
}
|
||||
|
||||
@ -56,21 +57,25 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
)
|
||||
}
|
||||
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, error) {
|
||||
func (impl) Sniff(reader io.ReaderAt) (int, []byte, error) {
|
||||
magicLE := []byte{0x49, 0x49, 0x2A, 0x00}
|
||||
magicBE := []byte{0x4D, 0x4D, 0x00, 0x2A}
|
||||
|
||||
buf := make([]byte, 4)
|
||||
|
||||
if _, err := reader.ReadAt(buf, 0); err != nil {
|
||||
return 0, err
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if bytes.Equal(buf, magicLE) || bytes.Equal(buf, magicBE) {
|
||||
return 100, nil
|
||||
if bytes.Equal(buf, magicLE) {
|
||||
return 100, magicLE, nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
if bytes.Equal(buf, magicBE) {
|
||||
return 100, magicBE, nil
|
||||
}
|
||||
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
@ -78,6 +83,8 @@ func (impl) Decode(reader io.Reader) (image.Image, error) {
|
||||
}
|
||||
|
||||
func (impl) Encode(writer io.Writer, img image.Image, options opts.Common) error {
|
||||
logx.Printf("tiff: compression=%d predictor=%t\n", compression, predictor)
|
||||
|
||||
return tiff.Encode(writer, img, &tiff.Options{
|
||||
Compression: compressionType(compression),
|
||||
Predictor: predictor,
|
||||
|
54
internal/logx/logx.go
Normal file
54
internal/logx/logx.go
Normal file
@ -0,0 +1,54 @@
|
||||
package logx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
var enabled atomic.Bool
|
||||
|
||||
func init() {
|
||||
enabled.Store(true)
|
||||
}
|
||||
|
||||
func SetSilent() {
|
||||
enabled.Store(false)
|
||||
}
|
||||
|
||||
func Printf(format string, a ...any) {
|
||||
if !enabled.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
for i, v := range a {
|
||||
switch r := v.(type) {
|
||||
case time.Time:
|
||||
a[i] = time.Since(r)
|
||||
case image.Image:
|
||||
b := r.Bounds()
|
||||
|
||||
a[i] = fmt.Sprintf("%dx%dx", b.Dx(), b.Dy())
|
||||
default:
|
||||
a[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, format, a...)
|
||||
}
|
||||
|
||||
func PrintKV(codec, key string, val any) {
|
||||
if !enabled.Load() {
|
||||
return
|
||||
}
|
||||
|
||||
Printf("%s: %s=%v\n", codec, key, val)
|
||||
}
|
||||
|
||||
func Errorf(f string, a ...any) {
|
||||
fmt.Fprintf(os.Stderr, f, a...)
|
||||
|
||||
os.Exit(1)
|
||||
}
|
Reference in New Issue
Block a user