@ -0,0 +1,26 @@ | |||
/* | |||
* Copyright © 2020 Gytis Repečka (gytis@repecka.com) | |||
* | |||
* This file is part of webimg. | |||
* | |||
* webimg is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, included | |||
* in the LICENSE file in this source code package. | |||
*/ | |||
package webimg | |||
import ( | |||
"fmt" | |||
) | |||
// FormatVersion constructs the version string for the application | |||
func FormatVersion() string { | |||
// return serverSoftware + " " + softwareVer | |||
return "gowebimg 0.0.1" | |||
} | |||
// OutputVersion prints out the version of the application. | |||
func OutputVersion() { | |||
fmt.Println(FormatVersion()) | |||
} |
@ -0,0 +1,4 @@ | |||
webimg | |||
webimg.exe | |||
webimg.log | |||
@ -0,0 +1,99 @@ | |||
/* | |||
* Copyright © 2020 Gytis Repečka (gytis@repecka.com) | |||
* | |||
* This file is part of webimg. | |||
* | |||
* webimg is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, included | |||
* in the LICENSE file in this source code package. | |||
*/ | |||
package main | |||
import ( | |||
"code.gyt.is/webimg" | |||
"flag" | |||
"fmt" | |||
"log" | |||
"os" | |||
"time" | |||
) | |||
func main() { | |||
// webimg.PrintHello() | |||
// Set some parameters | |||
timestampLayout := "2006-01-02 15:04:05.000 (MST Z07:00)" | |||
currentTime := time.Now() | |||
// Logging | |||
logFile, err := os.OpenFile("webimg.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) | |||
if err != nil { | |||
log.Fatal(err) | |||
} | |||
defer logFile.Close() | |||
log.SetOutput(logFile) | |||
// Log beginning of program | |||
log.Printf("Started webimg: %s.\n", currentTime.Format(timestampLayout)) | |||
cmdLineArgs := os.Args | |||
/* | |||
Subcommands | |||
Args[0] - executable path; | |||
Args[1] - subcommand. | |||
*/ | |||
// Main subcommands | |||
watermarkCommand := flag.NewFlagSet("watermark", flag.ExitOnError) | |||
// Subcommand "watermark" flag pointers | |||
watermarkImagePtr := watermarkCommand.String("image", "", "Path to image (JPG) file to watermark.") | |||
// General options usable with other commands | |||
outputVersion := flag.Bool("v", false, "Output the current version") | |||
outputHelp := flag.Bool("h", false, "Show help information") | |||
flag.Parse() | |||
if *outputVersion { | |||
webimg.OutputVersion() | |||
os.Exit(0) | |||
} else if *outputHelp { | |||
fmt.Println("General commands:") | |||
flag.PrintDefaults() | |||
fmt.Println("Watermark commands:") | |||
watermarkCommand.PrintDefaults() | |||
// Check if subcommand (watermark) was provided | |||
} else if len(cmdLineArgs) >= 2 { | |||
// Switch based on subcommand | |||
switch cmdLineArgs[1] { | |||
case "watermark": | |||
watermarkCommand.Parse(cmdLineArgs[2:]) | |||
if *watermarkImagePtr != "" { | |||
imageToWatermark := fmt.Sprintf("%s", *watermarkImagePtr) | |||
fmt.Printf("Image to watermark: %s\n", imageToWatermark) | |||
// Input image, watermark image, result image, bottom-right offset X, bottom-right offset Y, watermark alpha | |||
doWatermark := webimg.Watermark(imageToWatermark, "watermark_inretio-logo.png", "result_img.jpg", 30, 30, 70) | |||
if doWatermark != nil { | |||
fmt.Println("There was an error watermarking image...") | |||
} | |||
} else { | |||
fmt.Println("No image given to watermark!") | |||
} | |||
default: | |||
fmt.Println("Wrong subcommand provided!") | |||
} | |||
} else { | |||
fmt.Println("No work given. Holiday time!") | |||
} | |||
// Log end of program | |||
// time.Sleep(2 * time.Second) | |||
currentTime = time.Now() | |||
log.Printf("Finished webimg: %s.\n", currentTime.Format(timestampLayout)) | |||
log.Println("--------------------") | |||
} |
@ -0,0 +1,96 @@ | |||
/* | |||
* Copyright © 2020 Gytis Repečka (gytis@repecka.com) | |||
* | |||
* This file is part of webimg. | |||
* | |||
* webimg is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License, included | |||
* in the LICENSE file in this source code package. | |||
*/ | |||
package webimg | |||
import ( | |||
"fmt" | |||
"image" | |||
"image/color" | |||
"image/draw" | |||
"image/jpeg" | |||
"image/png" | |||
"log" | |||
"os" | |||
) | |||
func PrintHello() { | |||
fmt.Println("Hello there!") | |||
} | |||
func Watermark(imagePath, watermarkPath, resultPath string, offsetX, offsetY int, watermarkAlpha uint8) (err error) { | |||
// Input image | |||
// To-do: need to sanitize image paths! | |||
image1, err := os.Open(imagePath) | |||
if err != nil { | |||
log.Fatalf("failed to open: %s", err) | |||
} | |||
first, err := jpeg.Decode(image1) | |||
if err != nil { | |||
log.Fatalf("failed to decode: %s", err) | |||
} | |||
defer image1.Close() | |||
// Watermark image | |||
image2, err := os.Open(watermarkPath) | |||
if err != nil { | |||
log.Fatalf("failed to open: %s", err) | |||
} | |||
second, err := png.Decode(image2) | |||
if err != nil { | |||
log.Fatalf("failed to decode: %s", err) | |||
} | |||
defer image2.Close() | |||
// x, y from top-left corner | |||
// offset := image.Pt(100, 50) | |||
// log.Printf("Point: %V (%T)\n", offset, offset) | |||
// Bounds of input image | |||
inBounds := first.Bounds() | |||
// Bounds of watermark image | |||
watermarkBounds := second.Bounds() | |||
// To-do: offset should be configurable! | |||
watermarkCoordX1 := inBounds.Max.X - offsetX - watermarkBounds.Max.X // Input image x2 - offset x - watermark x2 | |||
watermarkCoordY1 := inBounds.Max.Y - offsetY - watermarkBounds.Max.Y // Input image y2 - offset y - watermark y2 | |||
offset := image.Pt(watermarkCoordX1, watermarkCoordY1) | |||
outBoundsOff := watermarkBounds.Add(offset) | |||
// outBoundsOff := inBounds.Sub(offset) | |||
/* | |||
log.Printf("Bounds (input): %V (%T)\n", inBounds, inBounds) | |||
log.Printf("Bounds (watermark): %V (%T)\n", watermarkBounds, watermarkBounds) | |||
log.Printf("Bounds (watermark with offset): %V (%T)\n", outBoundsOff, outBoundsOff) | |||
*/ | |||
log.Printf("Watermark x1: %d, y1: %d, x2: %d, y2: %d.", outBoundsOff.Min.X, outBoundsOff.Min.Y, outBoundsOff.Max.X, outBoundsOff.Max.Y) | |||
// Create new (output) image with size (bounds) of input image | |||
image3 := image.NewRGBA(inBounds) | |||
// Transparency | |||
// 0 - 255 | |||
mask := image.NewUniform(color.Alpha{watermarkAlpha}) | |||
draw.Draw(image3, inBounds, first, image.ZP, draw.Src) | |||
draw.DrawMask(image3, outBoundsOff, second, image.ZP, mask, image.ZP, draw.Over) | |||
third, err := os.Create(resultPath) | |||
if err != nil { | |||
log.Fatalf("failed to create: %s", err) | |||
} | |||
// jpeg.Encode(third, image3, &jpeg.Options{jpeg.DefaultQuality}) | |||
jpeg.Encode(third, image3, &jpeg.Options{85}) | |||
defer third.Close() | |||
return err | |||
} |