From e44c482527f799d1d1786f4482ba1bc27ef42c9b Mon Sep 17 00:00:00 2001 From: sunshineplan Date: Thu, 23 Nov 2023 18:11:57 +0800 Subject: [PATCH] Format and TIFFCompression support flag.TextVar (#92) --- converter/main.go | 34 ++++++++------------------ format.go | 62 ++++++++++++++++++++++++++++++++++++++++++++--- format_test.go | 40 ++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 27 deletions(-) diff --git a/converter/main.go b/converter/main.go index 0d98fc0..e942e0a 100644 --- a/converter/main.go +++ b/converter/main.go @@ -10,7 +10,6 @@ import ( "log/slog" "os" "path/filepath" - "strings" "time" "github.com/sunshineplan/imgconv" @@ -26,11 +25,9 @@ var ( test = flag.Bool("test", false, "") force = flag.Bool("force", false, "") pdf = flag.Bool("pdf", false, "") - format = flag.String("format", "jpg", "") whiteBackground = flag.Bool("white-background", false, "") gray = flag.Bool("gray", false, "") quality = flag.Int("quality", 75, "") - compression = flag.String("compression", "deflate", "") autoOrientation = flag.Bool("auto-orientation", false, "") watermark = flag.String("watermark", "", "") opacity = flag.Uint("opacity", 128, "") @@ -42,6 +39,9 @@ var ( percent = flag.Float64("percent", 0, "") worker = flag.Int("worker", 5, "") debug = flag.Bool("debug", false, "") + + format imgconv.Format + compression imgconv.TIFFCompression ) func usage() { @@ -106,7 +106,10 @@ func main() { return } + flag.CommandLine.Init(os.Args[0], flag.PanicOnError) flag.Usage = usage + flag.TextVar(&format, "format", imgconv.JPEG, "") + flag.TextVar(&compression, "compression", imgconv.TIFFDeflate, "") flags.SetConfigFile(filepath.Join(filepath.Dir(self), "config.ini")) flags.Parse() @@ -150,34 +153,17 @@ func main() { task := imgconv.NewOptions() - outputFormat, err := imgconv.FormatFromExtension(*format) - if err != nil { - log.Error("Failed to parse image format", "format", *format, "error", err) - code = 1 - return - } var opts []imgconv.EncodeOption - if outputFormat == imgconv.JPEG || outputFormat == imgconv.PDF { + if format == imgconv.JPEG || format == imgconv.PDF { opts = append(opts, imgconv.Quality(*quality)) } - if outputFormat == imgconv.TIFF { - var ct imgconv.TIFFCompression - switch strings.ToLower(*compression) { - case "none": - ct = imgconv.TIFFUncompressed - case "deflate": - ct = imgconv.TIFFDeflate - default: - log.Error("Unknown tiff compression", "type", *compression) - code = 1 - return - } - opts = append(opts, imgconv.TIFFCompressionType(ct)) + if format == imgconv.TIFF { + opts = append(opts, imgconv.TIFFCompressionType(compression)) } if *whiteBackground { opts = append(opts, imgconv.BackgroundColor(color.White)) } - task.SetFormat(outputFormat, opts...) + task.SetFormat(format, opts...) if *gray { task.SetGray(true) diff --git a/format.go b/format.go index 3e04a52..c470aaa 100644 --- a/format.go +++ b/format.go @@ -1,6 +1,8 @@ package imgconv import ( + "encoding" + "fmt" "image" "image/color" "image/draw" @@ -17,6 +19,11 @@ import ( _ "golang.org/x/image/webp" // decode webp format ) +var ( + _ encoding.TextUnmarshaler = new(Format) + _ encoding.TextMarshaler = Format(0) +) + // Format is an image file format. type Format int @@ -39,7 +46,12 @@ var formatExts = [][]string{ {"pdf"}, } -func (f Format) String() string { +func (f Format) String() (format string) { + defer func() { + if err := recover(); err != nil { + format = "unknown" + } + }() return formatExts[f][0] } @@ -47,8 +59,8 @@ func (f Format) String() string { // "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff"), "bmp" and "pdf" are supported. func FormatFromExtension(ext string) (Format, error) { ext = strings.ToLower(ext) - for _, exts := range formatExts { - for index, i := range exts { + for index, exts := range formatExts { + for _, i := range exts { if ext == i { return Format(index), nil } @@ -58,6 +70,24 @@ func FormatFromExtension(ext string) (Format, error) { return -1, image.ErrFormat } +func (f *Format) UnmarshalText(text []byte) error { + format, err := FormatFromExtension(string(text)) + if err != nil { + return err + } + *f = format + return nil +} + +func (f Format) MarshalText() ([]byte, error) { + return []byte(f.String()), nil +} + +var ( + _ encoding.TextUnmarshaler = new(TIFFCompression) + _ encoding.TextMarshaler = TIFFCompression(0) +) + // TIFFCompression describes the type of compression used in Options. type TIFFCompression int @@ -67,6 +97,11 @@ const ( TIFFDeflate ) +var tiffCompression = []string{ + "none", + "deflate", +} + func (c TIFFCompression) value() tiff.CompressionType { switch c { case TIFFDeflate: @@ -75,6 +110,27 @@ func (c TIFFCompression) value() tiff.CompressionType { return tiff.Uncompressed } +func (c *TIFFCompression) UnmarshalText(text []byte) error { + t := strings.ToLower(string(text)) + for index, tt := range tiffCompression { + if t == tt { + *c = TIFFCompression(index) + return nil + } + } + return fmt.Errorf("tiff: unsupported compression: %s", t) +} + +func (c TIFFCompression) MarshalText() (b []byte, err error) { + defer func() { + if err := recover(); err != nil { + b = []byte("unknown") + } + }() + ct := tiffCompression[c] + return []byte(ct), nil +} + // FormatOption is format option type FormatOption struct { Format Format diff --git a/format_test.go b/format_test.go index c9b897b..0b68bcc 100644 --- a/format_test.go +++ b/format_test.go @@ -2,6 +2,7 @@ package imgconv import ( "bytes" + "flag" "image" "image/draw" "image/png" @@ -21,6 +22,45 @@ func TestFormatFromExtension(t *testing.T) { } } +func TestTextVar(t *testing.T) { + testCase1 := []struct { + argument string + format Format + }{ + {"Jpg", JPEG}, + {"TIFF", TIFF}, + {"txt", Format(-1)}, + } + for _, tc := range testCase1 { + f := flag.NewFlagSet("test", flag.ContinueOnError) + f.SetOutput(io.Discard) + var format Format + f.TextVar(&format, "f", Format(-1), "") + f.Parse(append([]string{"-f"}, tc.argument)) + if format != tc.format { + t.Errorf("expected %s format; got %s", tc.format, format) + } + } + testCase2 := []struct { + argument string + compression TIFFCompression + }{ + {"none", TIFFUncompressed}, + {"Deflate", TIFFDeflate}, + {"lzw", TIFFCompression(-1)}, + } + for _, tc := range testCase2 { + f := flag.NewFlagSet("test", flag.ContinueOnError) + f.SetOutput(io.Discard) + var compression TIFFCompression + f.TextVar(&compression, "c", TIFFCompression(-1), "") + f.Parse(append([]string{"-c"}, tc.argument)) + if compression != tc.compression { + t.Errorf("expected %d compression; got %d", tc.compression, compression) + } + } +} + func TestEncode(t *testing.T) { testCase := []FormatOption{ {Format: JPEG, EncodeOption: []EncodeOption{Quality(75)}},