From 7dadd7b7f70a759b7ffb915a42860c7536cadbf2 Mon Sep 17 00:00:00 2001 From: heyarne Date: Tue, 8 Feb 2022 00:38:12 +0100 Subject: [PATCH] Implement image resizing and grayscale conversion --- cmd/convert.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/root.go | 14 ++++---- go.mod | 5 ++- go.sum | 1 + 4 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 cmd/convert.go diff --git a/cmd/convert.go b/cmd/convert.go new file mode 100644 index 0000000..cac9198 --- /dev/null +++ b/cmd/convert.go @@ -0,0 +1,97 @@ +/* +Copyright © 2022 NAME HERE + +*/ +package cmd + +import ( + "fmt" + "image" + "image/jpeg" + "image/png" + "log" + "os" + + "github.com/spf13/cobra" + "golang.org/x/image/draw" +) + +// convertCmd represents the convert command +var convertCmd = &cobra.Command{ + Use: "convert", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + Run: func(cmd *cobra.Command, args []string) { + width, _ := cmd.Flags().GetInt("width") + height, _ := cmd.Flags().GetInt("height") + + convertImage(width, height) + }, +} + +func init() { + rootCmd.AddCommand(convertCmd) + + convertCmd.Flags().Int("width", 540, "Target width") + convertCmd.Flags().Int("height", 960, "Target height") +} + +// Returns a new Rectangle that is resized and centered in `dst` +func fitRectInto(src *image.Rectangle, dst *image.Rectangle) image.Rectangle { + var targetWidth int + var targetHeight int + var scale float64 + + srcRatio := float64(src.Max.X) / float64(src.Max.Y) + dstRatio := float64(dst.Max.X) / float64(dst.Max.Y) + + if srcRatio < dstRatio { + // center horizontally, scale vertically + scale = float64(dst.Max.Y) / float64(src.Max.Y) + } else { + // center vertically, scale horizontally + scale = float64(dst.Max.X) / float64(src.Max.X) + } + + targetWidth = int(float64(src.Max.X) * scale) + targetHeight = int(float64(src.Max.Y) * scale) + + targetX := (dst.Max.X - targetWidth) / 2 + targetY := (dst.Max.Y - targetHeight) / 2 + + return image.Rect(targetX, targetY, targetWidth + targetX, targetHeight + targetY) +} + +func convertImage(width int, height int) { + // for now, we're reading a predefined input file + input, err := os.Open("cat.jpg") + if err != nil { + log.Fatalf("Error opening file: %v", err) + } + defer input.Close() + + // … and writing to a predefined output file + output, err := os.OpenFile("cat_resized.png", os.O_RDWR|os.O_CREATE, 0644) + if err != nil { + log.Fatalf("Error writing output file: %v", err) + } + defer output.Close() + + src, _ := jpeg.Decode(input) + dst := image.NewGray16(image.Rect(0, 0, width, height)) + + srcBounds := src.Bounds() + targetRect := fitRectInto(&srcBounds, &dst.Rect) + + fmt.Printf("targetRect: %v", targetRect) + + draw.CatmullRom.Scale(dst, targetRect, src, src.Bounds(), draw.Over, nil) + + // we're taking care of a more efficient output encoding later + png.Encode(output, dst) +} diff --git a/cmd/root.go b/cmd/root.go index 1e4fd20..4495dc4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -27,13 +27,11 @@ import ( // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "inkpot-cli", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, + Short: "Convert images for e-ink displays", + Long: `A command-line-tool that can be used to prepare images by +resizing them, rotating them and converting them to 16-color +grayscale so they can be comfortably displayed on e-ink +displays powered by the epdiy driver.`, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { }, @@ -57,7 +55,7 @@ func init() { // Cobra also supports local flags, which will only run // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/go.mod b/go.mod index d16412d..e196342 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/saunaclub/inkpot-cli go 1.16 -require github.com/spf13/cobra v1.3.0 // indirect +require ( + github.com/spf13/cobra v1.3.0 + golang.org/x/image v0.0.0-20190802002840-cff245a6509b +) diff --git a/go.sum b/go.sum index 73a92e4..15426dc 100644 --- a/go.sum +++ b/go.sum @@ -358,6 +358,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=