add automatic image resizing
This commit is contained in:
211
cmd/cli/cli.go
211
cmd/cli/cli.go
@ -5,7 +5,11 @@ import (
|
||||
b64 "encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/urfave/cli/v2"
|
||||
"image/draw"
|
||||
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
@ -15,12 +19,15 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
commands := []*cli.Command{
|
||||
//startCmd(),
|
||||
getJobResultCmd(),
|
||||
resizeCmd(),
|
||||
}
|
||||
|
||||
app := &cli.App{
|
||||
@ -38,6 +45,12 @@ func main() {
|
||||
"o",
|
||||
},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "format",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "The format to resize the image to wide, tall, or square",
|
||||
Value: "wide",
|
||||
},
|
||||
},
|
||||
Authors: []*cli.Author{
|
||||
{
|
||||
@ -48,27 +61,25 @@ func main() {
|
||||
Copyright: "2023 Masonite Studios LLC",
|
||||
UseShortOptionHandling: true,
|
||||
Action: func(c *cli.Context) error {
|
||||
var needsCleanup bool
|
||||
// use the first argument as the file name
|
||||
fileLocation := c.Args().Get(0)
|
||||
// if no argument is provided, use stdin
|
||||
if fileLocation == "" {
|
||||
fmt.Println("No file provided, using stdin.")
|
||||
// read from stdin
|
||||
var err error
|
||||
fileLocationBytes, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading from stdin | %w", err)
|
||||
}
|
||||
fileLocation = string(fileLocationBytes)
|
||||
fileLocation, err := getFileLocation(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting file location | %w", err)
|
||||
}
|
||||
|
||||
// TODO: preprocess the image to make sure it is the right size
|
||||
// preprocess the image to make sure it is the right size
|
||||
/*
|
||||
Supported Dimensions:
|
||||
1024x576
|
||||
576x1024
|
||||
768x768
|
||||
*/
|
||||
// get the format
|
||||
format := c.String("format")
|
||||
if format != "wide" && format != "tall" && format != "square" {
|
||||
return fmt.Errorf("invalid format %s", format)
|
||||
}
|
||||
|
||||
// make sure the image is either jpeg or png
|
||||
fileMimeType := mime.TypeByExtension(path.Ext(fileLocation))
|
||||
@ -76,8 +87,27 @@ func main() {
|
||||
return fmt.Errorf("unsupported file type | %v", fileMimeType)
|
||||
}
|
||||
|
||||
// resize the image
|
||||
tempLocation, err := resizeImage(fileLocation, format)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error resizing image | %w", err)
|
||||
}
|
||||
|
||||
if tempLocation != fileLocation {
|
||||
fmt.Printf("Resized image to %s\n", tempLocation)
|
||||
needsCleanup = true
|
||||
fileLocation = tempLocation // use the resized image
|
||||
}
|
||||
|
||||
id, err := initiateGeneratingAnimation(fileLocation)
|
||||
if err != nil {
|
||||
if needsCleanup {
|
||||
// remove the temp file
|
||||
err = cleanUpTempFile(tempLocation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error removing temp file | %w", err)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("error making request | %w", err)
|
||||
}
|
||||
|
||||
@ -87,6 +117,13 @@ func main() {
|
||||
// wait for the job to finish
|
||||
err = job(id, c.String("output"))
|
||||
if err != nil {
|
||||
if needsCleanup {
|
||||
// remove the temp file
|
||||
err = cleanUpTempFile(tempLocation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error removing temp file | %w", err)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("error getting job result | %w", err)
|
||||
}
|
||||
|
||||
@ -101,6 +138,152 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func cleanUpTempFile(fileLocation string) error {
|
||||
// remove the temp file
|
||||
err := os.Remove(fileLocation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error removing temp file | %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resizeImage(fileLocation string, format string) (string, error) {
|
||||
// load the image
|
||||
file, err := os.Open(fileLocation)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error opening file | %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var img image.Image
|
||||
fileMimeType := mime.TypeByExtension(path.Ext(fileLocation))
|
||||
if fileMimeType == "image/jpeg" {
|
||||
// decode the image
|
||||
img, err = jpeg.Decode(file)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error decoding jpeg image | %w", err)
|
||||
}
|
||||
} else if fileMimeType == "image/png" {
|
||||
// decode the image
|
||||
img, err = png.Decode(file)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error decoding png image | %w", err)
|
||||
}
|
||||
} else {
|
||||
return "", fmt.Errorf("unsupported file type | %v", fileMimeType)
|
||||
}
|
||||
|
||||
// check if the image is already the correct size
|
||||
rect := img.Bounds()
|
||||
width := rect.Max.X - rect.Min.X
|
||||
height := rect.Max.Y - rect.Min.Y
|
||||
x1 := 1024
|
||||
y1 := 576
|
||||
if format == "wide" {
|
||||
if width == 1024 && height == 576 {
|
||||
fmt.Println("Image is already the correct size.")
|
||||
return fileLocation, nil
|
||||
}
|
||||
}
|
||||
if format == "tall" {
|
||||
if width == 576 && height == 1024 {
|
||||
fmt.Println("Image is already the correct size.")
|
||||
return fileLocation, nil
|
||||
}
|
||||
x1 = 576
|
||||
y1 = 1024
|
||||
}
|
||||
if format == "square" {
|
||||
if width == 768 && height == 768 {
|
||||
fmt.Println("Image is already the correct size.")
|
||||
return fileLocation, nil
|
||||
}
|
||||
x1 = 768
|
||||
y1 = 768
|
||||
}
|
||||
|
||||
inFormat := "wide"
|
||||
if width < height {
|
||||
inFormat = "tall"
|
||||
}
|
||||
if width == height {
|
||||
inFormat = "square"
|
||||
}
|
||||
|
||||
// if not, resize the image
|
||||
// scale the original image to the new size
|
||||
var resizedImage image.Image
|
||||
if format == "wide" {
|
||||
resizedImage = resize.Resize(uint(x1), 0, img, resize.Lanczos3)
|
||||
}
|
||||
if format == "tall" {
|
||||
resizedImage = resize.Resize(0, uint(y1), img, resize.Lanczos3)
|
||||
}
|
||||
if format == "square" {
|
||||
if inFormat == "wide" {
|
||||
resizedImage = resize.Resize(0, uint(y1), img, resize.Lanczos3)
|
||||
}
|
||||
if inFormat == "tall" {
|
||||
resizedImage = resize.Resize(uint(x1), 0, img, resize.Lanczos3)
|
||||
}
|
||||
if inFormat == "square" {
|
||||
resizedImage = resize.Resize(uint(x1), uint(y1), img, resize.Lanczos3)
|
||||
}
|
||||
}
|
||||
|
||||
// crop the image to the final correct size
|
||||
|
||||
// start by getting the center of the image
|
||||
tempBounds := resizedImage.Bounds()
|
||||
x0 := tempBounds.Max.X/2 - x1/2
|
||||
y0 := tempBounds.Max.Y/2 - y1/2
|
||||
xMax := x0 + x1
|
||||
yMax := y0 + y1
|
||||
|
||||
croppedImageRect := image.Rect(x0, y0, xMax, yMax)
|
||||
rgba := convertToRGBA(resizedImage)
|
||||
croppedImage := rgba.SubImage(croppedImageRect)
|
||||
|
||||
// save the image to a temp file
|
||||
tempFile, err := os.CreateTemp("", "i2v*"+path.Ext(fileLocation))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error creating temp file | %w", err)
|
||||
}
|
||||
defer tempFile.Close()
|
||||
|
||||
// encode the image to the temp file
|
||||
err = jpeg.Encode(tempFile, croppedImage, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error encoding resized image | %w", err)
|
||||
}
|
||||
|
||||
// return the temp file location
|
||||
return tempFile.Name(), nil
|
||||
}
|
||||
|
||||
func convertToRGBA(img image.Image) *image.RGBA {
|
||||
bounds := img.Bounds()
|
||||
rgba := image.NewRGBA(bounds)
|
||||
draw.Draw(rgba, bounds, img, bounds.Min, draw.Src)
|
||||
return rgba
|
||||
}
|
||||
|
||||
func getFileLocation(c *cli.Context) (string, error) {
|
||||
fileLocation := c.Args().Get(0)
|
||||
// if no argument is provided, use stdin
|
||||
if fileLocation == "" {
|
||||
fmt.Println("No file provided, using stdin.")
|
||||
// read from stdin
|
||||
var err error
|
||||
fileLocationBytes, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error reading from stdin | %w", err)
|
||||
}
|
||||
fileLocation = string(fileLocationBytes)
|
||||
}
|
||||
return fileLocation, nil
|
||||
}
|
||||
|
||||
func initiateGeneratingAnimation(fileLocation string) (string, error) {
|
||||
// get base filename from file location
|
||||
filename := path.Base(fileLocation)
|
||||
|
Reference in New Issue
Block a user