-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c216fc2
commit 59c2b65
Showing
12 changed files
with
335 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: goreleaser | ||
|
||
on: | ||
pull_request: | ||
push: | ||
tags: | ||
- '*' | ||
|
||
jobs: | ||
goreleaser: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- | ||
name: Checkout | ||
uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
- | ||
name: Set up Go | ||
uses: actions/setup-go@v3 | ||
- | ||
name: Run GoReleaser | ||
uses: goreleaser/goreleaser-action@v3 | ||
with: | ||
distribution: goreleaser | ||
version: latest | ||
args: release --rm-dist | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
watermark-to-image* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
builds: | ||
- | ||
goos: | ||
- darwin | ||
- linux | ||
- windows | ||
goarch: | ||
- amd64 | ||
- arm64 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,38 @@ | ||
# watermark-to-image | ||
This application inserts a watermark in the lower right corner into the specified images folder. | ||
This application inserts a watermark in the lower right corner into all images of an specified images folder. | ||
|
||
# Examples | ||
Check out examples/original_images and examples/watermarked_images to get an idea what the application is doing. | ||
|
||
## Usage | ||
1. Build or download prebuild executeable | ||
2. Execute following command: | ||
``` | ||
./watermark-to-image -sourceDirectory ./examples/original_images -targetDirectory ./examples/watermarked_images -watermarkImageFile ./examples/watermark.png | ||
``` | ||
|
||
### Available command line parameter | ||
``` | ||
./watermark-to-image --help | ||
-sourceDirectory string | ||
Source directory of original images | ||
-targetDirectory string | ||
Target directory for watermarked images | ||
-watermarkImageFile string | ||
Path and name of the watermark png image file | ||
-watermarkIncreasement float | ||
Scale factor of the watermark image file (default 100) | ||
-watermarkMarginBottom int | ||
Margin to the bottom edge for the watermark (default 20) | ||
-watermarkMarginRight int | ||
Margin to the right edge for the watermark (default 20) | ||
-watermarkOpacity float | ||
Opacity/Transparency of the watermark image file (default 0.5) | ||
``` | ||
|
||
## Clone and build the project | ||
``` | ||
$ git clone https://github.com/danielchristianschroeter/watermark-to-image | ||
$ cd watermark-to-image | ||
$ go build . | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module watermark-to-image | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/disintegration/imaging v1.6.2 | ||
github.com/gabriel-vasile/mimetype v1.4.1 | ||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd | ||
golang.org/x/image v0.2.0 | ||
) | ||
|
||
require golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
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/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q= | ||
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M= | ||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= | ||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= | ||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | ||
golang.org/x/image v0.2.0 h1:/DcQ0w3VHKCC5p0/P2B0JpAZ9Z++V2KOo2fyU89CXBQ= | ||
golang.org/x/image v0.2.0/go.mod h1:la7oBXb9w3YFjBqaAwtynVioc1ZvOnNteUNrifGNmAI= | ||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= | ||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"image" | ||
"image/color" | ||
"image/jpeg" | ||
_ "image/png" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/disintegration/imaging" | ||
"github.com/gabriel-vasile/mimetype" | ||
"github.com/rwcarlsen/goexif/exif" | ||
"golang.org/x/image/draw" | ||
) | ||
|
||
// Used for build version information | ||
var version = "development" | ||
|
||
// Global variables used for command line flags | ||
var ( | ||
sourceDirectory string | ||
targetDirectory string | ||
watermarkImageFile string | ||
watermarkIncreasement float64 | ||
watermarkOpacity float64 | ||
watermarkMarginRight int | ||
watermarkMarginBottom int | ||
) | ||
|
||
func init() { | ||
// Initialize command line flags | ||
flag.StringVar(&sourceDirectory, "sourceDirectory", "", "Source directory of original images") | ||
flag.StringVar(&targetDirectory, "targetDirectory", "", "Target directory for watermarked images") | ||
flag.StringVar(&watermarkImageFile, "watermarkImageFile", "", "Path and name of the watermark png image file") | ||
flag.Float64Var(&watermarkIncreasement, "watermarkIncreasement", 100, "Scale factor of the watermark image file") | ||
flag.Float64Var(&watermarkOpacity, "watermarkOpacity", 0.5, "Opacity/Transparency of the watermark image file") | ||
flag.IntVar(&watermarkMarginRight, "watermarkMarginRight", 20, "Margin to the right edge for the watermark") | ||
flag.IntVar(&watermarkMarginBottom, "watermarkMarginBottom", 20, "Margin to the bottom edge for the watermark") | ||
} | ||
|
||
func processImage(file *os.File, targetDirectory string, watermarkImageFile string, watermarkIncreasement float64, watermarkMarginRight int, watermarkMarginBottom int, watermarkOpacity float64) error { | ||
|
||
// Load the watermark png image file using image.Decode | ||
watermarkFile, err := os.Open(watermarkImageFile) | ||
if err != nil { | ||
log.Fatalf("Failed to os.Open of file %+v Error: %+v", watermarkImageFile, err) | ||
} | ||
defer watermarkFile.Close() | ||
watermark, _, err := image.Decode(watermarkFile) | ||
if err != nil { | ||
log.Fatalf("Failed to image.Decode of file %+v Error: %+v", watermarkImageFile, err) | ||
} | ||
|
||
// Read EXIF-Metadata of image | ||
exifData, err := exif.Decode(file) | ||
if err != nil { | ||
log.Fatalf("Failed to exif.Decode of file %+v Error: %+v", file.Name(), err) | ||
} | ||
|
||
// Read Orientation-Tag from EXIF-Metadata | ||
orientation, err := exifData.Get(exif.Orientation) | ||
if err != nil { | ||
log.Fatalf("Failed to exifData.Get of file %+v Error: %+v", file.Name(), err) | ||
} | ||
|
||
// Convert Orientation-Tag to integer value | ||
orientationInt, err := orientation.Int(0) | ||
if err != nil { | ||
log.Fatalf("Failed to convert orientation-tag of file %+v Error: %+v", file.Name(), err) | ||
} | ||
|
||
// Seek to the beginning of the file before calling image.Decode | ||
_, err = file.Seek(0, 0) | ||
if err != nil { | ||
log.Fatalf("Failed to file.Seek of file %+v Error: %+v", file.Name(), err) | ||
} | ||
|
||
// Decode the image from the buffer | ||
img, _, err := image.Decode(file) | ||
if err != nil { | ||
log.Fatalf("Failed to image.Decode of file %+v Error: %+v", file.Name(), err) | ||
} | ||
// Rotate and/or flip image based on Orientation-Tag from EXIF-Metadata | ||
switch orientationInt { | ||
case 1: | ||
// no adjustment needed | ||
case 2: | ||
img = imaging.FlipH(img) | ||
case 3: | ||
img = imaging.Rotate(img, 180, color.Transparent) | ||
case 4: | ||
img = imaging.FlipH(imaging.Rotate(img, 180, color.Transparent)) | ||
case 5: | ||
img = imaging.FlipV(imaging.Rotate(img, 90, color.Transparent)) | ||
case 6: | ||
img = imaging.Rotate(img, 270, color.Transparent) | ||
case 7: | ||
img = imaging.FlipV(imaging.Rotate(img, 270, color.Transparent)) | ||
case 8: | ||
img = imaging.Rotate(img, 90, color.Transparent) | ||
} | ||
|
||
// Set the the margins (pixels). | ||
//marginSide := 15 | ||
//marginBottom := 15 | ||
|
||
// Get the width and the height of our image. | ||
photoWidth := img.Bounds().Dx() | ||
photoHeight := img.Bounds().Dy() | ||
|
||
// Get the width and the height of our watermark. | ||
watermarkWidth := watermark.Bounds().Dx() | ||
watermarkHeight := watermark.Bounds().Dy() | ||
|
||
// Increase the dimensions of the watermark by a given percentage. | ||
//percentage := 250 // increase dimensions | ||
resizedWidth := int(float64(watermarkWidth) * (float64(watermarkIncreasement) / 100.0)) | ||
resizedHeight := int(float64(watermarkHeight) * (float64(watermarkIncreasement) / 100.0)) | ||
resizedWatermark := image.NewRGBA(image.Rect(0, 0, resizedWidth, resizedHeight)) | ||
draw.NearestNeighbor.Scale(resizedWatermark, resizedWatermark.Bounds(), watermark, watermark.Bounds(), draw.Over, nil) | ||
|
||
// Figure out the dstX value. | ||
dstX := photoWidth - resizedWidth - watermarkMarginRight | ||
|
||
// Figure out the dstY value. | ||
dstY := photoHeight - resizedHeight - watermarkMarginBottom | ||
|
||
// Overlay the watermark onto the photo image with a specified opacity/transparency | ||
dst := imaging.Overlay(img, resizedWatermark, image.Pt(dstX, dstY), watermarkOpacity) | ||
|
||
// Save the new image | ||
outFile, err := os.Create(targetDirectory + filepath.Base(file.Name())) | ||
if err != nil { | ||
// handle error | ||
log.Fatalf("Failed to os.Create of file %+v Error: %+v", targetDirectory+filepath.Base(file.Name()), err) | ||
} | ||
defer outFile.Close() | ||
jpeg.Encode(outFile, dst, nil) | ||
|
||
log.Println("Saved watermarked image to " + targetDirectory + filepath.Base(file.Name())) | ||
|
||
return nil | ||
} | ||
|
||
func main() { | ||
log.SetFlags(0) | ||
flag.Usage = func() { | ||
log.Println("watermark-to-image. Version: " + version) | ||
flag.PrintDefaults() | ||
} | ||
flag.Parse() | ||
|
||
if len(sourceDirectory) == 0 || len(targetDirectory) == 0 || len(watermarkImageFile) == 0 { | ||
log.Fatal("Usage: -sourceDirectory <sourceDirectory> -targetDirectory <targetDirectory> -watermarkImageFile <watermarkImageFile>") | ||
} | ||
|
||
// Add slash to source directory, if not exists | ||
if !strings.HasSuffix(sourceDirectory, "/") { | ||
sourceDirectory += "/" | ||
} | ||
|
||
// Add slash to target directory, if not exists | ||
if !strings.HasSuffix(targetDirectory, "/") { | ||
targetDirectory += "/" | ||
} | ||
|
||
log.Println("Processing imges from directory " + sourceDirectory + "...") | ||
// Open the source directory | ||
dir, err := os.Open(sourceDirectory) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer dir.Close() | ||
|
||
// Get a list of all the files in the source directory | ||
files, err := dir.Readdir(-1) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
// Loop through the images in the source directory | ||
for _, file := range files { | ||
// Open the image | ||
f, err := os.Open(sourceDirectory + file.Name()) | ||
if err != nil { | ||
log.Printf("Failed to os.Open of file %+v Error: %v", sourceDirectory+file.Name(), err) | ||
continue | ||
} | ||
defer f.Close() | ||
|
||
// Skip image/heic | ||
mimeType, err := mimetype.DetectFile(sourceDirectory + file.Name()) | ||
if err != nil { | ||
log.Printf("Failed to mimetype.DetectFile of file %+v Error: %v", sourceDirectory+file.Name(), err) | ||
} | ||
switch mimeType.String() { | ||
case "image/heic": | ||
log.Printf("Skipping %v Reason: heic not supported", sourceDirectory+file.Name()) | ||
continue | ||
} | ||
|
||
// Process the image | ||
if err := processImage(f, targetDirectory, watermarkImageFile, watermarkIncreasement, watermarkMarginRight, watermarkMarginBottom, watermarkOpacity); err != nil { | ||
log.Printf("Failed to processImage of file %+v Error: %v", sourceDirectory+file.Name(), err) | ||
continue | ||
} | ||
} | ||
} |