mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-25 00:02:37 +02:00
Compare commits
13 Commits
ab62692ce6
...
5e5a07c930
Author | SHA1 | Date | |
---|---|---|---|
5e5a07c930 | |||
897efdc1d1 | |||
7b304149fd | |||
cc7a97ad6f | |||
5968cbdd09 | |||
79e20ca622 | |||
8233d067ef | |||
f4501753c5 | |||
0dde6e02a4 | |||
c500755a4e | |||
9133493e60 | |||
c75c58dede | |||
ee466f2872 |
389
README.md
389
README.md
@ -44,7 +44,7 @@ $ go install github.com/celogeek/go-comic-converter/v2
|
|||||||
To force install a specific version:
|
To force install a specific version:
|
||||||
```
|
```
|
||||||
# specific version
|
# specific version
|
||||||
$ go install github.com/celogeek/go-comic-converter/v2@v2.4.0
|
$ go install github.com/celogeek/go-comic-converter/v2@v2.6.9
|
||||||
|
|
||||||
# main branch
|
# main branch
|
||||||
$ go install github.com/celogeek/go-comic-converter/v2@main
|
$ go install github.com/celogeek/go-comic-converter/v2@main
|
||||||
@ -65,12 +65,12 @@ You can check if a new version is available with:
|
|||||||
$ go-comic-converter -version
|
$ go-comic-converter -version
|
||||||
go-comic-converter
|
go-comic-converter
|
||||||
Path : github.com/celogeek/go-comic-converter/v2
|
Path : github.com/celogeek/go-comic-converter/v2
|
||||||
Sum : h1:4PRd8xrqnK6B1fNaKdUDdIR5CEhBmfUAl8IkUtNLz7s=
|
Sum : h1:tUFF2m/fGlOJOwC0/PlTopMfcBMprKvgr6TiQHQxEeo=
|
||||||
Version : v2.6.3
|
Version : v2.6.9
|
||||||
Available Version: v2.6.3
|
Available Version: v2.6.9
|
||||||
|
|
||||||
To install the latest version:
|
To install the latest version:
|
||||||
$ go install github.com/celogeek/go-comic-converter/v2@v2.6.3
|
$ go install github.com/celogeek/go-comic-converter/v2@v2.6.9
|
||||||
```
|
```
|
||||||
|
|
||||||
# Supported image files
|
# Supported image files
|
||||||
@ -137,35 +137,35 @@ $ go-comic-converter -input ~/Downloads/mymanga.cbr -profile SR -auto -manga -li
|
|||||||
Go Comic Converter
|
Go Comic Converter
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Input : ~/Downloads/mymanga.cbr
|
Input : ~/Downloads/mymanga.cbr
|
||||||
Output : ~/Downloads/mymanga.epub
|
Output : ~/Downloads/mymanga.epub
|
||||||
Author : GO Comic Converter
|
Author : GO Comic Converter
|
||||||
Title : mymanga
|
Title : mymanga
|
||||||
Workers : 8
|
Workers : 20
|
||||||
Profile : SR - Standard Resolution - 1200x1920
|
Profile : SR - Standard Resolution - 1200x1920
|
||||||
Format : jpeg
|
Format : jpeg
|
||||||
Quality : 90
|
Quality : 85
|
||||||
Grayscale : true
|
Grayscale : true
|
||||||
Grayscale Mode : normal
|
Grayscale mode : normal
|
||||||
Crop : true
|
Crop : true
|
||||||
CropRatio : 1 Left - 1 Up - 1 Right - 3 Bottom
|
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
|
||||||
AutoContrast : true
|
Auto contrast : true
|
||||||
AutoRotate : false
|
Auto rotate : true
|
||||||
AutoSplitDoublePage : false
|
Auto split double page : true
|
||||||
KeepDoublePageIfSplitted : true
|
Keep double page if split : true
|
||||||
NoBlankImage : true
|
No blank image : true
|
||||||
Manga : true
|
Manga : true
|
||||||
HasCover : true
|
Has cover : true
|
||||||
LimitMb : 200 Mb
|
Limit : 200 Mb
|
||||||
StripFirstDirectoryFromToc : true
|
Strip first directory from toc : false
|
||||||
SortPathMode : path=alphanum, file=alpha
|
Sort path mode : path=alphanumeric, file=alpha
|
||||||
Foreground Color : #000
|
Foreground color : #000
|
||||||
Background Color : #FFF
|
Background color : #FFF
|
||||||
Resize : true
|
Resize : true
|
||||||
Aspect Ratio : 1:1.60
|
Aspect ratio : auto
|
||||||
Portrait Only : false
|
Portrait only : false
|
||||||
Title Page : always
|
Title page : always
|
||||||
Apple Book Compatibility : false
|
Apple book compatibility : false
|
||||||
|
|
||||||
TOC:
|
TOC:
|
||||||
- mymanga
|
- mymanga
|
||||||
@ -185,35 +185,35 @@ $ go-comic-converter -input ~/Downloads/mymanga.cbr -profile SR -auto -manga -li
|
|||||||
Go Comic Converter
|
Go Comic Converter
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Input : ~/Downloads/mymanga.cbr
|
Input : ~/Downloads/mymanga.cbr
|
||||||
Output : ~/Downloads/mymanga.epub
|
Output : ~/Downloads/mymanga.epub
|
||||||
Author : GO Comic Converter
|
Author : GO Comic Converter
|
||||||
Title : mymanga
|
Title : mymanga
|
||||||
Workers : 8
|
Workers : 20
|
||||||
Profile : SR - Standard Resolution - 1200x1920
|
Profile : SR - Standard Resolution - 1200x1920
|
||||||
Format : jpeg
|
Format : jpeg
|
||||||
Quality : 90
|
Quality : 85
|
||||||
Grayscale : true
|
Grayscale : true
|
||||||
Grayscale Mode : normal
|
Grayscale mode : normal
|
||||||
Crop : true
|
Crop : true
|
||||||
CropRatio : 1 Left - 1 Up - 1 Right - 3 Bottom
|
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
|
||||||
AutoContrast : true
|
Auto contrast : true
|
||||||
AutoRotate : false
|
Auto rotate : true
|
||||||
AutoSplitDoublePage : false
|
Auto split double page : true
|
||||||
KeepDoublePageIfSplitted : true
|
Keep double page if split : true
|
||||||
NoBlankImage : true
|
No blank image : true
|
||||||
Manga : true
|
Manga : true
|
||||||
HasCover : true
|
Has cover : true
|
||||||
LimitMb : 200 Mb
|
Limit : 200 Mb
|
||||||
StripFirstDirectoryFromToc : true
|
Strip first directory from toc : false
|
||||||
SortPathMode : path=alphanum, file=alpha
|
Sort path mode : path=alphanumeric, file=alpha
|
||||||
Foreground Color : #000
|
Foreground color : #000
|
||||||
Background Color : #FFF
|
Background color : #FFF
|
||||||
Resize : true
|
Resize : true
|
||||||
Aspect Ratio : 1:1.60
|
Aspect ratio : auto
|
||||||
Portrait Only : false
|
Portrait only : false
|
||||||
Title Page : always
|
Title page : always
|
||||||
Apple Book Compatibility : false
|
Apple book compatibility : false
|
||||||
|
|
||||||
TOC:
|
TOC:
|
||||||
- mymanga
|
- mymanga
|
||||||
@ -248,29 +248,28 @@ $ go-comic-converter -show
|
|||||||
Go Comic Converter
|
Go Comic Converter
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Profile :
|
Profile : SR - Standard Resolution - 1200x1920
|
||||||
Format : jpeg
|
Format : jpeg
|
||||||
Quality : 85
|
Quality : 85
|
||||||
Grayscale : true
|
Grayscale : true
|
||||||
Grayscale Mode : normal
|
Grayscale mode : normal
|
||||||
Crop : true
|
Crop : true
|
||||||
CropRatio : 1 Left - 1 Up - 1 Right - 3 Bottom
|
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
|
||||||
AutoContrast : false
|
Auto contrast : false
|
||||||
AutoRotate : false
|
Auto rotate : false
|
||||||
AutoSplitDoublePage : false
|
Auto split double page : false
|
||||||
KeepDoublePageIfSplitted : true
|
No blank image : true
|
||||||
NoBlankImage : true
|
Manga : false
|
||||||
Manga : false
|
Has cover : true
|
||||||
HasCover : true
|
Strip first directory from toc : false
|
||||||
StripFirstDirectoryFromToc : false
|
Sort path mode : path=alphanumeric, file=alpha
|
||||||
SortPathMode : path=alphanum, file=alpha
|
Foreground color : #000
|
||||||
Foreground Color : #000
|
Background color : #FFF
|
||||||
Background Color : #FFF
|
Resize : true
|
||||||
Resize : true
|
Aspect ratio : auto
|
||||||
Aspect Ratio : auto
|
Portrait only : false
|
||||||
Portrait Only : false
|
Title page : always
|
||||||
Title Page : always
|
Apple book compatibility : false
|
||||||
Apple Book Compatibility : false
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Change default settings
|
### Change default settings
|
||||||
@ -280,30 +279,30 @@ $ go-comic-converter -manga -auto -profile SR -limitmb 200 -save
|
|||||||
Go Comic Converter
|
Go Comic Converter
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Profile : SR - Standard Resolution - 1200x1920
|
Profile : SR - Standard Resolution - 1200x1920
|
||||||
Format : jpeg
|
Format : jpeg
|
||||||
Quality : 85
|
Quality : 85
|
||||||
Grayscale : true
|
Grayscale : true
|
||||||
Grayscale Mode : normal
|
Grayscale mode : normal
|
||||||
Crop : true
|
Crop : true
|
||||||
CropRatio : 1 Left - 1 Up - 1 Right - 3 Bottom
|
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
|
||||||
AutoContrast : true
|
Auto contrast : true
|
||||||
AutoRotate : true
|
Auto rotate : true
|
||||||
AutoSplitDoublePage : true
|
Auto split double page : true
|
||||||
KeepDoublePageIfSplitted : true
|
Keep double page if split : true
|
||||||
NoBlankImage : true
|
No blank image : true
|
||||||
Manga : true
|
Manga : true
|
||||||
HasCover : true
|
Has cover : true
|
||||||
LimitMb : 200 Mb
|
Limit : 200 Mb
|
||||||
StripFirstDirectoryFromToc : false
|
Strip first directory from toc : false
|
||||||
SortPathMode : path=alphanum, file=alpha
|
Sort path mode : path=alphanumeric, file=alpha
|
||||||
Foreground Color : #000
|
Foreground color : #000
|
||||||
Background Color : #FFF
|
Background color : #FFF
|
||||||
Resize : true
|
Resize : true
|
||||||
Aspect Ratio : auto
|
Aspect ratio : auto
|
||||||
Portrait Only : false
|
Portrait only : false
|
||||||
Title Page : always
|
Title page : always
|
||||||
Apple Book Compatibility : false
|
Apple book compatibility : false
|
||||||
|
|
||||||
Saving to ~/.go-comic-converter.yaml
|
Saving to ~/.go-comic-converter.yaml
|
||||||
```
|
```
|
||||||
@ -313,35 +312,35 @@ If you want to change a setting, you can change only one of them
|
|||||||
$ go-comic-converter -manga=0 -save
|
$ go-comic-converter -manga=0 -save
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Profile : SR - Standard Resolution - 1200x1920
|
Profile : SR - Standard Resolution - 1200x1920
|
||||||
Format : jpeg
|
Format : jpeg
|
||||||
Quality : 85
|
Quality : 85
|
||||||
Grayscale : true
|
Grayscale : true
|
||||||
Grayscale Mode : normal
|
Grayscale mode : normal
|
||||||
Crop : true
|
Crop : true
|
||||||
CropRatio : 1 Left - 1 Up - 1 Right - 3 Bottom
|
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
|
||||||
AutoContrast : true
|
Auto contrast : true
|
||||||
AutoRotate : true
|
Auto rotate : true
|
||||||
AutoSplitDoublePage : true
|
Auto split double page : true
|
||||||
KeepDoublePageIfSplitted : true
|
Keep double page if split : true
|
||||||
NoBlankImage : true
|
No blank image : true
|
||||||
Manga : false
|
Manga : false
|
||||||
HasCover : true
|
Has cover : true
|
||||||
LimitMb : 200 Mb
|
Limit : 200 Mb
|
||||||
StripFirstDirectoryFromToc : false
|
Strip first directory from toc : false
|
||||||
SortPathMode : path=alphanum, file=alpha
|
Sort path mode : path=alphanumeric, file=alpha
|
||||||
Foreground Color : #000
|
Foreground color : #000
|
||||||
Background Color : #FFF
|
Background color : #FFF
|
||||||
Resize : true
|
Resize : true
|
||||||
Aspect Ratio : auto
|
Aspect ratio : auto
|
||||||
Portrait Only : false
|
Portrait only : false
|
||||||
Title Page : always
|
Title page : always
|
||||||
Apple Book Compatibility : false
|
Apple book compatibility : false
|
||||||
|
|
||||||
Saving to ~/.go-comic-converter.yaml
|
Saving to ~/.go-comic-converter.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
###Â Reset default
|
### Reset default
|
||||||
To reset all value to default:
|
To reset all value to default:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -349,29 +348,28 @@ $ go-comic-converter -reset
|
|||||||
Go Comic Converter
|
Go Comic Converter
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Profile :
|
Profile : SR - Standard Resolution - 1200x1920
|
||||||
Format : jpeg
|
Format : jpeg
|
||||||
Quality : 85
|
Quality : 85
|
||||||
Grayscale : true
|
Grayscale : true
|
||||||
Grayscale Mode : normal
|
Grayscale mode : normal
|
||||||
Crop : true
|
Crop : true
|
||||||
CropRatio : 1 Left - 1 Up - 1 Right - 3 Bottom
|
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
|
||||||
AutoContrast : false
|
Auto contrast : false
|
||||||
AutoRotate : false
|
Auto rotate : false
|
||||||
AutoSplitDoublePage : false
|
Auto split double page : false
|
||||||
KeepDoublePageIfSplitted : true
|
No blank image : true
|
||||||
NoBlankImage : true
|
Manga : false
|
||||||
Manga : false
|
Has cover : true
|
||||||
HasCover : true
|
Strip first directory from toc : false
|
||||||
StripFirstDirectoryFromToc : false
|
Sort path mode : path=alphanumeric, file=alpha
|
||||||
SortPathMode : path=alphanum, file=alpha
|
Foreground color : #000
|
||||||
Foreground Color : #000
|
Background color : #FFF
|
||||||
Background Color : #FFF
|
Resize : true
|
||||||
Resize : true
|
Aspect ratio : auto
|
||||||
Aspect Ratio : auto
|
Portrait only : false
|
||||||
Portrait Only : false
|
Title page : always
|
||||||
Title Page : always
|
Apple book compatibility : false
|
||||||
Apple Book Compatibility : false
|
|
||||||
|
|
||||||
Reset default to ~/.go-comic-converter.yaml
|
Reset default to ~/.go-comic-converter.yaml
|
||||||
```
|
```
|
||||||
@ -382,32 +380,31 @@ After playing around with the options, I have my perfect settings for all my dev
|
|||||||
|
|
||||||
```
|
```
|
||||||
$ go-comic-converter -reset
|
$ go-comic-converter -reset
|
||||||
$ go-comic-converter -profile SR -quality 90 -autocontrast -manga -strip -aspect-ratio 1.6 -save
|
$ go-comic-converter -profile SR -quality 90 -manga -aspect-ratio 1.6 -limitmb 200 -save
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Profile : SR - Standard Resolution - 1200x1920
|
Profile : SR - Standard Resolution - 1200x1920
|
||||||
Format : jpeg
|
Format : jpeg
|
||||||
Quality : 90
|
Quality : 90
|
||||||
Grayscale : true
|
Grayscale : true
|
||||||
Grayscale Mode : normal
|
Grayscale mode : normal
|
||||||
Crop : true
|
Crop : true
|
||||||
CropRatio : 1 Left - 1 Up - 1 Right - 3 Bottom
|
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
|
||||||
AutoContrast : true
|
Auto contrast : false
|
||||||
AutoRotate : false
|
Auto rotate : false
|
||||||
AutoSplitDoublePage : false
|
Auto split double page : false
|
||||||
KeepDoublePageIfSplitted : true
|
No blank image : true
|
||||||
NoBlankImage : true
|
Manga : true
|
||||||
Manga : true
|
Has cover : true
|
||||||
HasCover : true
|
Strip first directory from toc : false
|
||||||
StripFirstDirectoryFromToc : true
|
Sort path mode : path=alphanumeric, file=alpha
|
||||||
SortPathMode : path=alphanum, file=alpha
|
Foreground color : #000
|
||||||
Foreground Color : #000
|
Background color : #FFF
|
||||||
Background Color : #FFF
|
Resize : true
|
||||||
Resize : true
|
Aspect ratio : 1:1.60
|
||||||
Aspect Ratio : 1:1.60
|
Portrait only : false
|
||||||
Portrait Only : false
|
Title page : always
|
||||||
Title Page : always
|
Apple book compatibility : false
|
||||||
Apple Book Compatibility : false
|
|
||||||
|
|
||||||
Saving to ~/.go-comic-converter.yaml
|
Saving to ~/.go-comic-converter.yaml
|
||||||
```
|
```
|
||||||
@ -415,11 +412,9 @@ Saving to ~/.go-comic-converter.yaml
|
|||||||
Explanation:
|
Explanation:
|
||||||
- `-profile SR`: standard resolution (fast conversion from Amazon as images do not need to be resized)
|
- `-profile SR`: standard resolution (fast conversion from Amazon as images do not need to be resized)
|
||||||
- `-quality 90`: JPEG output quality of images
|
- `-quality 90`: JPEG output quality of images
|
||||||
- `-autocontrast`: automatically improve contrast
|
|
||||||
- `-manga`: manga mode, read right to left
|
- `-manga`: manga mode, read right to left
|
||||||
- `-limitmb 200`: size limit to 200MB allowing upload from SendToKindle website
|
- `-limitmb 200`: size limit to 200MB allowing upload from SendToKindle website
|
||||||
- `-strip`: remove first level if alone on TOC, as often comics include a main directory with the title
|
- `-aspect-ratio`: ensure aspect ratio is 1:1.6, best for kindle devices.
|
||||||
- `aspect-ratio`: ensure aspect ratio is 1:1.6, best for kindle devices.
|
|
||||||
# Help
|
# Help
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -439,7 +434,7 @@ Output:
|
|||||||
|
|
||||||
Config:
|
Config:
|
||||||
-profile string (default "SR")
|
-profile string (default "SR")
|
||||||
Profile to use:
|
Profile to use:
|
||||||
- HR ( 2400x3840 ) - High Resolution
|
- HR ( 2400x3840 ) - High Resolution
|
||||||
- SR ( 1200x1920 ) - Standard Resolution
|
- SR ( 1200x1920 ) - Standard Resolution
|
||||||
- K1 ( 600x670 ) - Kindle 1
|
- K1 ( 600x670 ) - Kindle 1
|
||||||
@ -487,18 +482,22 @@ Config:
|
|||||||
Crop ratio right: ratio of pixels allow to be non blank while cutting on the right.
|
Crop ratio right: ratio of pixels allow to be non blank while cutting on the right.
|
||||||
-crop-ratio-bottom int (default 3)
|
-crop-ratio-bottom int (default 3)
|
||||||
Crop ratio bottom: ratio of pixels allow to be non blank while cutting on the bottom.
|
Crop ratio bottom: ratio of pixels allow to be non blank while cutting on the bottom.
|
||||||
|
-crop-limit int (default 10)
|
||||||
|
Crop limit: maximum number of cropping in percentage allowed. 0 mean unlimited.
|
||||||
|
-crop-skip-if-limit-reached (default true)
|
||||||
|
Crop skip if limit reached.
|
||||||
-brightness int
|
-brightness int
|
||||||
Brightness readjustement: between -100 and 100, > 0 lighter, < 0 darker
|
Brightness readjustment: between -100 and 100, > 0 lighter, < 0 darker
|
||||||
-contrast int
|
-contrast int
|
||||||
Contrast readjustement: between -100 and 100, > 0 more contrast, < 0 less contrast
|
Contrast readjustment: between -100 and 100, > 0 more contrast, < 0 less contrast
|
||||||
-autocontrast
|
-autocontrast
|
||||||
Improve contrast automatically
|
Improve contrast automatically
|
||||||
-autorotate
|
-autorotate
|
||||||
Auto Rotate page when width > height
|
Auto Rotate page when width > height
|
||||||
-autosplitdoublepage
|
-autosplitdoublepage
|
||||||
Auto Split double page when width > height
|
Auto Split double page when width > height
|
||||||
-keepdoublepageifsplitted (default true)
|
-keepdoublepageifsplit (default true)
|
||||||
Keep the double page if splitted
|
Keep the double page if split
|
||||||
-noblankimage (default true)
|
-noblankimage (default true)
|
||||||
Remove blank image
|
Remove blank image
|
||||||
-manga
|
-manga
|
||||||
@ -512,12 +511,12 @@ Config:
|
|||||||
-sort int (default 1)
|
-sort int (default 1)
|
||||||
Sort path mode
|
Sort path mode
|
||||||
0 = alpha for path and file
|
0 = alpha for path and file
|
||||||
1 = alphanum for path and alpha for file
|
1 = alphanumeric for path and alpha for file
|
||||||
2 = alphanum for path and file
|
2 = alphanumeric for path and file
|
||||||
-foreground-color string (default "000")
|
-foreground-color string (default "000")
|
||||||
Foreground color in hexa format RGB. Black=000, White=FFF
|
Foreground color in hexadecimal format RGB. Black=000, White=FFF
|
||||||
-background-color string (default "FFF")
|
-background-color string (default "FFF")
|
||||||
Background color in hexa format RGB. Black=000, White=FFF, Light Gray=DDD, Dark Gray=777
|
Background color in hexadecimal format RGB. Black=000, White=FFF, Light Gray=DDD, Dark Gray=777
|
||||||
-noresize
|
-noresize
|
||||||
Do not reduce image size if exceed device size
|
Do not reduce image size if exceed device size
|
||||||
-format string (default "jpeg")
|
-format string (default "jpeg")
|
||||||
@ -533,7 +532,7 @@ Config:
|
|||||||
Title page
|
Title page
|
||||||
0 = never
|
0 = never
|
||||||
1 = always
|
1 = always
|
||||||
2 = only if epub is splitted
|
2 = only if epub is split
|
||||||
|
|
||||||
Default config:
|
Default config:
|
||||||
-show
|
-show
|
||||||
|
8
go.mod
8
go.mod
@ -22,8 +22,8 @@ require (
|
|||||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
golang.org/x/net v0.21.0 // indirect
|
golang.org/x/net v0.24.0 // indirect
|
||||||
golang.org/x/sys v0.17.0 // indirect
|
golang.org/x/sys v0.19.0 // indirect
|
||||||
golang.org/x/term v0.17.0 // indirect
|
golang.org/x/term v0.19.0 // indirect
|
||||||
)
|
)
|
||||||
|
14
go.sum
14
go.sum
@ -35,19 +35,21 @@ github.com/schollz/progressbar/v3 v3.14.2 h1:EducH6uNLIWsr560zSV1KrTeUb/wZGAHqyM
|
|||||||
github.com/schollz/progressbar/v3 v3.14.2/go.mod h1:aQAZQnhF4JGFtRJiw/eobaXpsqpVQAftEQ+hLGXaRc4=
|
github.com/schollz/progressbar/v3 v3.14.2/go.mod h1:aQAZQnhF4JGFtRJiw/eobaXpsqpVQAftEQ+hLGXaRc4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e h1:IWllFTiDjjLIf2oeKxpIUmtiDV5sn71VgeQgg6vcE7k=
|
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e h1:IWllFTiDjjLIf2oeKxpIUmtiDV5sn71VgeQgg6vcE7k=
|
||||||
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e/go.mod h1:d7u6HkTYKSv5m6MCKkOQlHwaShTMl3HjqSGW3XtVhXM=
|
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e/go.mod h1:d7u6HkTYKSv5m6MCKkOQlHwaShTMl3HjqSGW3XtVhXM=
|
||||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||||
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||||
|
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/celogeek/go-comic-converter/v2/internal/converter/options"
|
"github.com/celogeek/go-comic-converter/v2/internal/converter/options"
|
||||||
|
"github.com/celogeek/go-comic-converter/v2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Converter struct {
|
type Converter struct {
|
||||||
@ -44,17 +45,17 @@ func New() *Converter {
|
|||||||
var cmdOutput strings.Builder
|
var cmdOutput strings.Builder
|
||||||
cmd.SetOutput(&cmdOutput)
|
cmd.SetOutput(&cmdOutput)
|
||||||
cmd.Usage = func() {
|
cmd.Usage = func() {
|
||||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", filepath.Base(os.Args[0]))
|
utils.Printf("Usage of %s:\n", filepath.Base(os.Args[0]))
|
||||||
for _, o := range conv.order {
|
for _, o := range conv.order {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
case converterOrderSection:
|
case converterOrderSection:
|
||||||
fmt.Fprintf(os.Stderr, "\n%s:\n", o.Value())
|
utils.Printf("\n%s:\n", o.Value())
|
||||||
case converterOrderName:
|
case converterOrderName:
|
||||||
fmt.Fprintln(os.Stderr, conv.Usage(v.isString, cmd.Lookup(v.Value())))
|
utils.Println(conv.Usage(v.isString, cmd.Lookup(v.Value())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cmdOutput.Len() > 0 {
|
if cmdOutput.Len() > 0 {
|
||||||
fmt.Fprintf(os.Stderr, "\nError: %s", cmdOutput.String())
|
utils.Printf("\nError: %s", cmdOutput.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +114,8 @@ func (c *Converter) InitParse() {
|
|||||||
c.AddIntParam(&c.Options.CropRatioUp, "crop-ratio-up", c.Options.CropRatioUp, "Crop ratio up: ratio of pixels allow to be non blank while cutting on the top.")
|
c.AddIntParam(&c.Options.CropRatioUp, "crop-ratio-up", c.Options.CropRatioUp, "Crop ratio up: ratio of pixels allow to be non blank while cutting on the top.")
|
||||||
c.AddIntParam(&c.Options.CropRatioRight, "crop-ratio-right", c.Options.CropRatioRight, "Crop ratio right: ratio of pixels allow to be non blank while cutting on the right.")
|
c.AddIntParam(&c.Options.CropRatioRight, "crop-ratio-right", c.Options.CropRatioRight, "Crop ratio right: ratio of pixels allow to be non blank while cutting on the right.")
|
||||||
c.AddIntParam(&c.Options.CropRatioBottom, "crop-ratio-bottom", c.Options.CropRatioBottom, "Crop ratio bottom: ratio of pixels allow to be non blank while cutting on the bottom.")
|
c.AddIntParam(&c.Options.CropRatioBottom, "crop-ratio-bottom", c.Options.CropRatioBottom, "Crop ratio bottom: ratio of pixels allow to be non blank while cutting on the bottom.")
|
||||||
|
c.AddIntParam(&c.Options.CropLimit, "crop-limit", c.Options.CropLimit, "Crop limit: maximum number of cropping in percentage allowed. 0 mean unlimited.")
|
||||||
|
c.AddBoolParam(&c.Options.CropSkipIfLimitReached, "crop-skip-if-limit-reached", c.Options.CropSkipIfLimitReached, "Crop skip if limit reached.")
|
||||||
c.AddIntParam(&c.Options.Brightness, "brightness", c.Options.Brightness, "Brightness readjustment: between -100 and 100, > 0 lighter, < 0 darker")
|
c.AddIntParam(&c.Options.Brightness, "brightness", c.Options.Brightness, "Brightness readjustment: between -100 and 100, > 0 lighter, < 0 darker")
|
||||||
c.AddIntParam(&c.Options.Contrast, "contrast", c.Options.Contrast, "Contrast readjustment: between -100 and 100, > 0 more contrast, < 0 less contrast")
|
c.AddIntParam(&c.Options.Contrast, "contrast", c.Options.Contrast, "Contrast readjustment: between -100 and 100, > 0 more contrast, < 0 less contrast")
|
||||||
c.AddBoolParam(&c.Options.AutoContrast, "autocontrast", c.Options.AutoContrast, "Improve contrast automatically")
|
c.AddBoolParam(&c.Options.AutoContrast, "autocontrast", c.Options.AutoContrast, "Improve contrast automatically")
|
||||||
@ -162,7 +165,7 @@ func (c *Converter) InitParse() {
|
|||||||
// Usage Customize version of FlagSet.PrintDefaults
|
// Usage Customize version of FlagSet.PrintDefaults
|
||||||
func (c *Converter) Usage(isString bool, f *flag.Flag) string {
|
func (c *Converter) Usage(isString bool, f *flag.Flag) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
fmt.Fprintf(&b, " -%s", f.Name) // Two spaces before -; see next two comments.
|
b.WriteString(" -" + f.Name)
|
||||||
name, usage := flag.UnquoteUsage(f)
|
name, usage := flag.UnquoteUsage(f)
|
||||||
if len(name) > 0 {
|
if len(name) > 0 {
|
||||||
b.WriteString(" ")
|
b.WriteString(" ")
|
||||||
@ -174,9 +177,9 @@ func (c *Converter) Usage(isString bool, f *flag.Flag) string {
|
|||||||
c.isZeroValueErrs = append(c.isZeroValueErrs, err)
|
c.isZeroValueErrs = append(c.isZeroValueErrs, err)
|
||||||
} else if !isZero {
|
} else if !isZero {
|
||||||
if isString {
|
if isString {
|
||||||
fmt.Fprintf(&b, " (default %q)", f.DefValue)
|
b.WriteString(fmt.Sprintf(" (default %q)", f.DefValue))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&b, " (default %v)", f.DefValue)
|
b.WriteString(fmt.Sprintf(" (default %v)", f.DefValue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +228,7 @@ func (c *Converter) isZeroValue(f *flag.Flag, value string) (ok bool, err error)
|
|||||||
|
|
||||||
// Parse all parameters
|
// Parse all parameters
|
||||||
func (c *Converter) Parse() {
|
func (c *Converter) Parse() {
|
||||||
c.Cmd.Parse(os.Args[1:])
|
_ = c.Cmd.Parse(os.Args[1:])
|
||||||
if c.Options.Help {
|
if c.Options.Help {
|
||||||
c.Cmd.Usage()
|
c.Cmd.Usage()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
@ -388,13 +391,18 @@ func (c *Converter) Validate() error {
|
|||||||
return errors.New("grayscale mode should be 0, 1 or 2")
|
return errors.New("grayscale mode should be 0, 1 or 2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// crop
|
||||||
|
if c.Options.CropLimit < 0 || c.Options.CropLimit > 100 {
|
||||||
|
return errors.New("crop limit should be between 0 and 100")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal Helper to show usage, err and exit 1
|
// Fatal Helper to show usage, err and exit 1
|
||||||
func (c *Converter) Fatal(err error) {
|
func (c *Converter) Fatal(err error) {
|
||||||
c.Cmd.Usage()
|
c.Cmd.Usage()
|
||||||
fmt.Fprintf(os.Stderr, "\nError: %s\n", err)
|
utils.Printf("\nError: %s\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,7 +413,7 @@ func (c *Converter) Stats() {
|
|||||||
runtime.ReadMemStats(&mem)
|
runtime.ReadMemStats(&mem)
|
||||||
|
|
||||||
if c.Options.Json {
|
if c.Options.Json {
|
||||||
json.NewEncoder(os.Stdout).Encode(map[string]any{
|
_ = json.NewEncoder(os.Stdout).Encode(map[string]any{
|
||||||
"type": "stats",
|
"type": "stats",
|
||||||
"data": map[string]any{
|
"data": map[string]any{
|
||||||
"elapse_ms": elapse.Milliseconds(),
|
"elapse_ms": elapse.Milliseconds(),
|
||||||
@ -413,8 +421,7 @@ func (c *Converter) Stats() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(
|
utils.Printf(
|
||||||
os.Stderr,
|
|
||||||
"Completed in %s, Memory usage %d Mb\n",
|
"Completed in %s, Memory usage %d Mb\n",
|
||||||
elapse,
|
elapse,
|
||||||
mem.Sys/1024/1024,
|
mem.Sys/1024/1024,
|
||||||
|
@ -8,8 +8,9 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/celogeek/go-comic-converter/v2/internal/converter/profiles"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/celogeek/go-comic-converter/v2/internal/converter/profiles"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@ -29,6 +30,8 @@ type Options struct {
|
|||||||
CropRatioUp int `yaml:"crop_ratio_up"`
|
CropRatioUp int `yaml:"crop_ratio_up"`
|
||||||
CropRatioRight int `yaml:"crop_ratio_right"`
|
CropRatioRight int `yaml:"crop_ratio_right"`
|
||||||
CropRatioBottom int `yaml:"crop_ratio_bottom"`
|
CropRatioBottom int `yaml:"crop_ratio_bottom"`
|
||||||
|
CropLimit int `yaml:"crop_limit"`
|
||||||
|
CropSkipIfLimitReached bool `yaml:"crop_skip_if_limit_reached"`
|
||||||
Brightness int `yaml:"brightness"`
|
Brightness int `yaml:"brightness"`
|
||||||
Contrast int `yaml:"contrast"`
|
Contrast int `yaml:"contrast"`
|
||||||
AutoContrast bool `yaml:"auto_contrast"`
|
AutoContrast bool `yaml:"auto_contrast"`
|
||||||
@ -79,23 +82,25 @@ type Options struct {
|
|||||||
// New Initialize default options.
|
// New Initialize default options.
|
||||||
func New() *Options {
|
func New() *Options {
|
||||||
return &Options{
|
return &Options{
|
||||||
Profile: "SR",
|
Profile: "SR",
|
||||||
Quality: 85,
|
Quality: 85,
|
||||||
Grayscale: true,
|
Grayscale: true,
|
||||||
Crop: true,
|
Crop: true,
|
||||||
CropRatioLeft: 1,
|
CropRatioLeft: 1,
|
||||||
CropRatioUp: 1,
|
CropRatioUp: 1,
|
||||||
CropRatioRight: 1,
|
CropRatioRight: 1,
|
||||||
CropRatioBottom: 3,
|
CropRatioBottom: 3,
|
||||||
NoBlankImage: true,
|
CropLimit: 10,
|
||||||
HasCover: true,
|
CropSkipIfLimitReached: true,
|
||||||
KeepDoublePageIfSplit: true,
|
NoBlankImage: true,
|
||||||
SortPathMode: 1,
|
HasCover: true,
|
||||||
ForegroundColor: "000",
|
KeepDoublePageIfSplit: true,
|
||||||
BackgroundColor: "FFF",
|
SortPathMode: 1,
|
||||||
Format: "jpeg",
|
ForegroundColor: "000",
|
||||||
TitlePage: 1,
|
BackgroundColor: "FFF",
|
||||||
profiles: profiles.New(),
|
Format: "jpeg",
|
||||||
|
TitlePage: 1,
|
||||||
|
profiles: profiles.New(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +166,8 @@ func (o *Options) MarshalJSON() ([]byte, error) {
|
|||||||
"up": o.CropRatioUp,
|
"up": o.CropRatioUp,
|
||||||
"bottom": o.CropRatioBottom,
|
"bottom": o.CropRatioBottom,
|
||||||
}
|
}
|
||||||
|
out["crop_limit"] = o.CropLimit
|
||||||
|
out["crop_skip_if_limit_reached"] = o.CropSkipIfLimitReached
|
||||||
}
|
}
|
||||||
if o.Brightness != 0 {
|
if o.Brightness != 0 {
|
||||||
out["brightness"] = o.Brightness
|
out["brightness"] = o.Brightness
|
||||||
@ -195,7 +202,9 @@ func (o *Options) LoadConfig() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer func(f *os.File) {
|
||||||
|
_ = f.Close()
|
||||||
|
}(f)
|
||||||
err = yaml.NewDecoder(f).Decode(o)
|
err = yaml.NewDecoder(f).Decode(o)
|
||||||
if err != nil && err.Error() != "EOF" {
|
if err != nil && err.Error() != "EOF" {
|
||||||
return err
|
return err
|
||||||
@ -232,7 +241,11 @@ func (o *Options) ShowConfig() string {
|
|||||||
if o.AspectRatio > 0 {
|
if o.AspectRatio > 0 {
|
||||||
aspectRatio = fmt.Sprintf("1:%.02f", o.AspectRatio)
|
aspectRatio = fmt.Sprintf("1:%.02f", o.AspectRatio)
|
||||||
} else if o.AspectRatio < 0 {
|
} else if o.AspectRatio < 0 {
|
||||||
aspectRatio = fmt.Sprintf("1:%0.2f (device)", float64(profile.Height)/float64(profile.Width))
|
if profile != nil {
|
||||||
|
aspectRatio = fmt.Sprintf("1:%0.2f (device)", float64(profile.Height)/float64(profile.Width))
|
||||||
|
} else {
|
||||||
|
aspectRatio = "1:?? (device)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
titlePage := ""
|
titlePage := ""
|
||||||
@ -265,7 +278,7 @@ func (o *Options) ShowConfig() string {
|
|||||||
{"Grayscale", o.Grayscale, true},
|
{"Grayscale", o.Grayscale, true},
|
||||||
{"Grayscale mode", grayscaleMode, o.Grayscale},
|
{"Grayscale mode", grayscaleMode, o.Grayscale},
|
||||||
{"Crop", o.Crop, true},
|
{"Crop", o.Crop, true},
|
||||||
{"Crop ratio", fmt.Sprintf("%d Left - %d Up - %d Right - %d Bottom", o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom), o.Crop},
|
{"Crop ratio", fmt.Sprintf("%d Left - %d Up - %d Right - %d Bottom - Limit %d%% - Skip %v", o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom, o.CropLimit, o.CropSkipIfLimitReached), o.Crop},
|
||||||
{"Brightness", o.Brightness, o.Brightness != 0},
|
{"Brightness", o.Brightness, o.Brightness != 0},
|
||||||
{"Contrast", o.Contrast, o.Contrast != 0},
|
{"Contrast", o.Contrast, o.Contrast != 0},
|
||||||
{"Auto contrast", o.AutoContrast, true},
|
{"Auto contrast", o.AutoContrast, true},
|
||||||
@ -295,7 +308,9 @@ func (o *Options) ShowConfig() string {
|
|||||||
|
|
||||||
// ResetConfig reset all settings to default value
|
// ResetConfig reset all settings to default value
|
||||||
func (o *Options) ResetConfig() error {
|
func (o *Options) ResetConfig() error {
|
||||||
New().SaveConfig()
|
if err := New().SaveConfig(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return o.LoadConfig()
|
return o.LoadConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +320,9 @@ func (o *Options) SaveConfig() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer func(f *os.File) {
|
||||||
|
_ = f.Close()
|
||||||
|
}(f)
|
||||||
return yaml.NewEncoder(f).Encode(o)
|
return yaml.NewEncoder(f).Encode(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"archive/zip"
|
"archive/zip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
@ -13,6 +12,8 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofrs/uuid"
|
||||||
|
|
||||||
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
||||||
epubimageprocessor "github.com/celogeek/go-comic-converter/v2/internal/epub/imageprocessor"
|
epubimageprocessor "github.com/celogeek/go-comic-converter/v2/internal/epub/imageprocessor"
|
||||||
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
||||||
@ -20,7 +21,7 @@ import (
|
|||||||
epubtemplates "github.com/celogeek/go-comic-converter/v2/internal/epub/templates"
|
epubtemplates "github.com/celogeek/go-comic-converter/v2/internal/epub/templates"
|
||||||
epubtree "github.com/celogeek/go-comic-converter/v2/internal/epub/tree"
|
epubtree "github.com/celogeek/go-comic-converter/v2/internal/epub/tree"
|
||||||
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip"
|
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip"
|
||||||
"github.com/gofrs/uuid"
|
"github.com/celogeek/go-comic-converter/v2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EPub struct {
|
type EPub struct {
|
||||||
@ -338,7 +339,9 @@ func (e *EPub) writePart(path string, currentPart, totalParts int, part *epubPar
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer wz.Close()
|
defer func(wz *epubzip.EPUBZip) {
|
||||||
|
_ = wz.Close()
|
||||||
|
}(wz)
|
||||||
|
|
||||||
title := e.Title
|
title := e.Title
|
||||||
if totalParts > 1 {
|
if totalParts > 1 {
|
||||||
@ -418,18 +421,18 @@ func (e *EPub) Write() error {
|
|||||||
|
|
||||||
if e.Dry {
|
if e.Dry {
|
||||||
p := epubParts[0]
|
p := epubParts[0]
|
||||||
fmt.Fprintf(os.Stderr, "TOC:\n - %s\n%s\n", e.Title, e.getTree(p.Images, true))
|
utils.Printf("TOC:\n - %s\n%s\n", e.Title, e.getTree(p.Images, true))
|
||||||
if e.DryVerbose {
|
if e.DryVerbose {
|
||||||
if e.Image.HasCover {
|
if e.Image.HasCover {
|
||||||
fmt.Fprintf(os.Stderr, "Cover:\n%s\n", e.getTree([]*epubimage.Image{p.Cover}, false))
|
utils.Printf("Cover:\n%s\n", e.getTree([]*epubimage.Image{p.Cover}, false))
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "Files:\n%s\n", e.getTree(p.Images, false))
|
utils.Printf("Files:\n%s\n", e.getTree(p.Images, false))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
imgStorage.Close()
|
_ = imgStorage.Close()
|
||||||
imgStorage.Remove()
|
_ = imgStorage.Remove()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
totalParts := len(epubParts)
|
totalParts := len(epubParts)
|
||||||
@ -465,11 +468,11 @@ func (e *EPub) Write() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
bar.Add(1)
|
_ = bar.Add(1)
|
||||||
}
|
}
|
||||||
bar.Close()
|
_ = bar.Close()
|
||||||
if !e.Json {
|
if !e.Json {
|
||||||
fmt.Fprintln(os.Stderr)
|
utils.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
// display corrupted images
|
// display corrupted images
|
||||||
@ -477,17 +480,17 @@ func (e *EPub) Write() error {
|
|||||||
for pId, part := range epubParts {
|
for pId, part := range epubParts {
|
||||||
if pId == 0 && e.Image.HasCover && part.Cover.Error != nil {
|
if pId == 0 && e.Image.HasCover && part.Cover.Error != nil {
|
||||||
hasError = true
|
hasError = true
|
||||||
fmt.Fprintf(os.Stderr, "Error on image %s: %v\n", filepath.Join(part.Cover.Path, part.Cover.Name), part.Cover.Error)
|
utils.Printf("Error on image %s: %v\n", filepath.Join(part.Cover.Path, part.Cover.Name), part.Cover.Error)
|
||||||
}
|
}
|
||||||
for _, img := range part.Images {
|
for _, img := range part.Images {
|
||||||
if img.Part == 0 && img.Error != nil {
|
if img.Part == 0 && img.Error != nil {
|
||||||
hasError = true
|
hasError = true
|
||||||
fmt.Fprintf(os.Stderr, "Error on image %s: %v\n", filepath.Join(img.Path, img.Name), img.Error)
|
utils.Printf("Error on image %s: %v\n", filepath.Join(img.Path, img.Name), img.Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if hasError {
|
if hasError {
|
||||||
fmt.Fprintln(os.Stderr)
|
utils.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// AutoCrop Lookup for margin and crop
|
// AutoCrop Lookup for margin and crop
|
||||||
func AutoCrop(img image.Image, bounds image.Rectangle, cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom int) gift.Filter {
|
func AutoCrop(img image.Image, bounds image.Rectangle, cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom int, limit int, skipIfLimitReached bool) gift.Filter {
|
||||||
return gift.Crop(
|
return gift.Crop(
|
||||||
findMargin(img, bounds, cutRatioOptions{cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom}),
|
findMargin(img, bounds, cutRatioOptions{cutRatioLeft, cutRatioUp, cutRatioRight, cutRatioBottom}, limit, skipIfLimitReached),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,11 +25,13 @@ type cutRatioOptions struct {
|
|||||||
Left, Up, Right, Bottom int
|
Left, Up, Right, Bottom int
|
||||||
}
|
}
|
||||||
|
|
||||||
func findMargin(img image.Image, bounds image.Rectangle, cutRatio cutRatioOptions) image.Rectangle {
|
func findMargin(img image.Image, bounds image.Rectangle, cutRatio cutRatioOptions, limit int, skipIfLimitReached bool) image.Rectangle {
|
||||||
imgArea := bounds
|
imgArea := bounds
|
||||||
|
|
||||||
|
maxCropX, maxCropY := imgArea.Dx()*limit/100, imgArea.Dy()*limit/100
|
||||||
|
|
||||||
LEFT:
|
LEFT:
|
||||||
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
for x, maxCrop := imgArea.Min.X, maxCropX; x < imgArea.Max.X && (limit == 0 || maxCrop > 0); x, maxCrop = x+1, maxCrop-1 {
|
||||||
allowNonBlank := imgArea.Dy() * cutRatio.Left / 100
|
allowNonBlank := imgArea.Dy() * cutRatio.Left / 100
|
||||||
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
||||||
if !colorIsBlank(img.At(x, y)) {
|
if !colorIsBlank(img.At(x, y)) {
|
||||||
@ -40,10 +42,13 @@ LEFT:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
imgArea.Min.X++
|
imgArea.Min.X++
|
||||||
|
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
|
||||||
|
return bounds
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UP:
|
UP:
|
||||||
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
for y, maxCrop := imgArea.Min.Y, maxCropY; y < imgArea.Max.Y && (limit == 0 || maxCrop > 0); y, maxCrop = y+1, maxCrop-1 {
|
||||||
allowNonBlank := imgArea.Dx() * cutRatio.Up / 100
|
allowNonBlank := imgArea.Dx() * cutRatio.Up / 100
|
||||||
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
||||||
if !colorIsBlank(img.At(x, y)) {
|
if !colorIsBlank(img.At(x, y)) {
|
||||||
@ -54,10 +59,13 @@ UP:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
imgArea.Min.Y++
|
imgArea.Min.Y++
|
||||||
|
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
|
||||||
|
return bounds
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RIGHT:
|
RIGHT:
|
||||||
for x := imgArea.Max.X - 1; x >= imgArea.Min.X; x-- {
|
for x, maxCrop := imgArea.Max.X-1, maxCropX; x >= imgArea.Min.X && (limit == 0 || maxCrop > 0); x, maxCrop = x-1, maxCrop-1 {
|
||||||
allowNonBlank := imgArea.Dy() * cutRatio.Right / 100
|
allowNonBlank := imgArea.Dy() * cutRatio.Right / 100
|
||||||
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
|
||||||
if !colorIsBlank(img.At(x, y)) {
|
if !colorIsBlank(img.At(x, y)) {
|
||||||
@ -68,10 +76,13 @@ RIGHT:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
imgArea.Max.X--
|
imgArea.Max.X--
|
||||||
|
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
|
||||||
|
return bounds
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOTTOM:
|
BOTTOM:
|
||||||
for y := imgArea.Max.Y - 1; y >= imgArea.Min.Y; y-- {
|
for y, maxCrop := imgArea.Max.Y-1, maxCropY; y >= imgArea.Min.Y && (limit == 0 || maxCrop > 0); y, maxCrop = y-1, maxCrop-1 {
|
||||||
allowNonBlank := imgArea.Dx() * cutRatio.Bottom / 100
|
allowNonBlank := imgArea.Dx() * cutRatio.Bottom / 100
|
||||||
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
|
||||||
if !colorIsBlank(img.At(x, y)) {
|
if !colorIsBlank(img.At(x, y)) {
|
||||||
@ -82,6 +93,9 @@ BOTTOM:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
imgArea.Max.Y--
|
imgArea.Max.Y--
|
||||||
|
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
|
||||||
|
return bounds
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return imgArea
|
return imgArea
|
||||||
|
@ -94,5 +94,5 @@ func (p *coverTitle) Draw(dst draw.Image, src image.Image, _ *gift.Options) {
|
|||||||
textLeft = textArea.Min.X
|
textLeft = textArea.Min.X
|
||||||
}
|
}
|
||||||
textTop := textArea.Min.Y + textArea.Dy()/2 + textHeight/4
|
textTop := textArea.Min.Y + textArea.Dy()/2 + textHeight/4
|
||||||
c.DrawString(p.title, freetype.Pt(textLeft, textTop))
|
_, _ = c.DrawString(p.title, freetype.Pt(textLeft, textTop))
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/disintegration/gift"
|
||||||
|
|
||||||
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
||||||
epubimagefilters "github.com/celogeek/go-comic-converter/v2/internal/epub/imagefilters"
|
epubimagefilters "github.com/celogeek/go-comic-converter/v2/internal/epub/imagefilters"
|
||||||
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
||||||
epubprogress "github.com/celogeek/go-comic-converter/v2/internal/epub/progress"
|
epubprogress "github.com/celogeek/go-comic-converter/v2/internal/epub/progress"
|
||||||
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip"
|
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip"
|
||||||
"github.com/disintegration/gift"
|
"github.com/celogeek/go-comic-converter/v2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EPUBImageProcessor struct {
|
type EPUBImageProcessor struct {
|
||||||
@ -62,7 +64,7 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
|
|||||||
|
|
||||||
imgStorage, err := epubzip.NewStorageImageWriter(e.ImgStorage(), e.Image.Format)
|
imgStorage, err := epubzip.NewStorageImageWriter(e.ImgStorage(), e.Image.Format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bar.Close()
|
_ = bar.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +84,8 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
|
|||||||
if !(img.DoublePage && input.Id > 0 &&
|
if !(img.DoublePage && input.Id > 0 &&
|
||||||
e.Options.Image.AutoSplitDoublePage && !e.Options.Image.KeepDoublePageIfSplit) {
|
e.Options.Image.AutoSplitDoublePage && !e.Options.Image.KeepDoublePageIfSplit) {
|
||||||
if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil {
|
if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil {
|
||||||
bar.Close()
|
_ = bar.Close()
|
||||||
fmt.Fprintf(os.Stderr, "error with %s: %s", input.Name, err)
|
utils.Printf("error with %s: %s", input.Name, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
// do not keep raw image except for cover
|
// do not keep raw image except for cover
|
||||||
@ -103,8 +105,8 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
|
|||||||
for i, b := range []bool{e.Image.Manga, !e.Image.Manga} {
|
for i, b := range []bool{e.Image.Manga, !e.Image.Manga} {
|
||||||
img = e.transformImage(input, i+1, b)
|
img = e.transformImage(input, i+1, b)
|
||||||
if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil {
|
if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil {
|
||||||
bar.Close()
|
_ = bar.Close()
|
||||||
fmt.Fprintf(os.Stderr, "error with %s: %s", input.Name, err)
|
utils.Printf("error with %s: %s", input.Name, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
img.Raw = nil
|
img.Raw = nil
|
||||||
@ -116,20 +118,20 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
imgStorage.Close()
|
_ = imgStorage.Close()
|
||||||
close(imageOutput)
|
close(imageOutput)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for img := range imageOutput {
|
for img := range imageOutput {
|
||||||
if img.Part == 0 {
|
if img.Part == 0 {
|
||||||
bar.Add(1)
|
_ = bar.Add(1)
|
||||||
}
|
}
|
||||||
if e.Image.NoBlankImage && img.IsBlank {
|
if e.Image.NoBlankImage && img.IsBlank {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
images = append(images, img)
|
images = append(images, img)
|
||||||
}
|
}
|
||||||
bar.Close()
|
_ = bar.Close()
|
||||||
|
|
||||||
if len(images) == 0 {
|
if len(images) == 0 {
|
||||||
return nil, errNoImagesFound
|
return nil, errNoImagesFound
|
||||||
@ -189,6 +191,8 @@ func (e *EPUBImageProcessor) transformImage(input *task, part int, right bool) *
|
|||||||
e.Image.Crop.Up,
|
e.Image.Crop.Up,
|
||||||
e.Image.Crop.Right,
|
e.Image.Crop.Right,
|
||||||
e.Image.Crop.Bottom,
|
e.Image.Crop.Bottom,
|
||||||
|
e.Image.Crop.Limit,
|
||||||
|
e.Image.Crop.SkipIfLimitReached,
|
||||||
)
|
)
|
||||||
|
|
||||||
// detect if blank image
|
// detect if blank image
|
||||||
|
@ -20,12 +20,14 @@ import (
|
|||||||
"golang.org/x/image/font/gofont/gomonobold"
|
"golang.org/x/image/font/gofont/gomonobold"
|
||||||
_ "golang.org/x/image/webp"
|
_ "golang.org/x/image/webp"
|
||||||
|
|
||||||
"github.com/celogeek/go-comic-converter/v2/internal/sortpath"
|
|
||||||
"github.com/fogleman/gg"
|
"github.com/fogleman/gg"
|
||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
"github.com/nwaples/rardecode/v2"
|
"github.com/nwaples/rardecode/v2"
|
||||||
pdfimage "github.com/raff/pdfreader/image"
|
pdfimage "github.com/raff/pdfreader/image"
|
||||||
"github.com/raff/pdfreader/pdfread"
|
"github.com/raff/pdfreader/pdfread"
|
||||||
|
|
||||||
|
"github.com/celogeek/go-comic-converter/v2/internal/sortpath"
|
||||||
|
"github.com/celogeek/go-comic-converter/v2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type task struct {
|
type task struct {
|
||||||
@ -153,7 +155,7 @@ func (e *EPUBImageProcessor) loadDir() (totalImages int, output chan *task, err
|
|||||||
f, err = os.Open(job.Path)
|
f, err = os.Open(job.Path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
img, _, err = image.Decode(f)
|
img, _, err = image.Decode(f)
|
||||||
f.Close()
|
_ = f.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +205,7 @@ func (e *EPUBImageProcessor) loadCbz() (totalImages int, output chan *task, err
|
|||||||
totalImages = len(images)
|
totalImages = len(images)
|
||||||
|
|
||||||
if totalImages == 0 {
|
if totalImages == 0 {
|
||||||
r.Close()
|
_ = r.Close()
|
||||||
err = errNoImagesFound
|
err = errNoImagesFound
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -246,7 +248,7 @@ func (e *EPUBImageProcessor) loadCbz() (totalImages int, output chan *task, err
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
img, _, err = image.Decode(f)
|
img, _, err = image.Decode(f)
|
||||||
}
|
}
|
||||||
f.Close()
|
_ = f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
p, fn := filepath.Split(filepath.Clean(job.F.Name))
|
p, fn := filepath.Split(filepath.Clean(job.F.Name))
|
||||||
@ -267,7 +269,7 @@ func (e *EPUBImageProcessor) loadCbz() (totalImages int, output chan *task, err
|
|||||||
go func() {
|
go func() {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(output)
|
close(output)
|
||||||
r.Close()
|
_ = r.Close()
|
||||||
}()
|
}()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -315,24 +317,26 @@ func (e *EPUBImageProcessor) loadCbr() (totalImages int, output chan *task, err
|
|||||||
if isSolid && !e.Dry {
|
if isSolid && !e.Dry {
|
||||||
r, rerr := rardecode.OpenReader(e.Input)
|
r, rerr := rardecode.OpenReader(e.Input)
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
fmt.Fprintf(os.Stderr, "\nerror processing image %s: %s\n", e.Input, rerr)
|
utils.Printf("\nerror processing image %s: %s\n", e.Input, rerr)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer func(r *rardecode.ReadCloser) {
|
||||||
|
_ = r.Close()
|
||||||
|
}(r)
|
||||||
for {
|
for {
|
||||||
f, rerr := r.Next()
|
f, rerr := r.Next()
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
if rerr == io.EOF {
|
if rerr == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "\nerror processing image %s: %s\n", f.Name, rerr)
|
utils.Printf("\nerror processing image %s: %s\n", f.Name, rerr)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if i, ok := indexedNames[f.Name]; ok {
|
if i, ok := indexedNames[f.Name]; ok {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
_, rerr = io.Copy(&b, r)
|
_, rerr = io.Copy(&b, r)
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
fmt.Fprintf(os.Stderr, "\nerror processing image %s: %s\n", f.Name, rerr)
|
utils.Printf("\nerror processing image %s: %s\n", f.Name, rerr)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
jobs <- &job{i, f.Name, func() (io.ReadCloser, error) {
|
jobs <- &job{i, f.Name, func() (io.ReadCloser, error) {
|
||||||
@ -365,7 +369,7 @@ func (e *EPUBImageProcessor) loadCbr() (totalImages int, output chan *task, err
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
img, _, err = image.Decode(f)
|
img, _, err = image.Decode(f)
|
||||||
}
|
}
|
||||||
f.Close()
|
_ = f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
p, fn := filepath.Split(filepath.Clean(job.Name))
|
p, fn := filepath.Split(filepath.Clean(job.Name))
|
||||||
|
@ -6,6 +6,8 @@ import "fmt"
|
|||||||
type Crop struct {
|
type Crop struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Left, Up, Right, Bottom int
|
Left, Up, Right, Bottom int
|
||||||
|
Limit int
|
||||||
|
SkipIfLimitReached bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Color struct {
|
type Color struct {
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
|
|
||||||
|
"github.com/celogeek/go-comic-converter/v2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@ -38,7 +40,7 @@ func New(o Options) EpubProgress {
|
|||||||
progressbar.OptionSetWriter(os.Stderr),
|
progressbar.OptionSetWriter(os.Stderr),
|
||||||
progressbar.OptionThrottle(65*time.Millisecond),
|
progressbar.OptionThrottle(65*time.Millisecond),
|
||||||
progressbar.OptionOnCompletion(func() {
|
progressbar.OptionOnCompletion(func() {
|
||||||
fmt.Fprint(os.Stderr, "\n")
|
utils.Println()
|
||||||
}),
|
}),
|
||||||
progressbar.OptionSetDescription(fmt.Sprintf(fmtDesc, o.CurrentJob, o.TotalJob, o.Description)),
|
progressbar.OptionSetDescription(fmt.Sprintf(fmtDesc, o.CurrentJob, o.TotalJob, o.Description)),
|
||||||
progressbar.OptionSetWidth(60),
|
progressbar.OptionSetWidth(60),
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/beevik/etree"
|
"github.com/beevik/etree"
|
||||||
|
|
||||||
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
||||||
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/beevik/etree"
|
"github.com/beevik/etree"
|
||||||
|
|
||||||
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ func (e *EPUBZip) Close() error {
|
|||||||
// This will be valid with epubcheck tools.
|
// This will be valid with epubcheck tools.
|
||||||
func (e *EPUBZip) WriteMagic() error {
|
func (e *EPUBZip) WriteMagic() error {
|
||||||
t := time.Now().UTC()
|
t := time.Now().UTC()
|
||||||
|
//goland:noinspection GoDeprecation
|
||||||
fh := &zip.FileHeader{
|
fh := &zip.FileHeader{
|
||||||
Name: "mimetype",
|
Name: "mimetype",
|
||||||
Method: zip.Store,
|
Method: zip.Store,
|
||||||
|
@ -52,6 +52,7 @@ func CompressImage(filename string, format string, img image.Image, quality int)
|
|||||||
}
|
}
|
||||||
|
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
|
//goland:noinspection GoDeprecation
|
||||||
return &ZipImage{
|
return &ZipImage{
|
||||||
&zip.FileHeader{
|
&zip.FileHeader{
|
||||||
Name: filename,
|
Name: filename,
|
||||||
|
@ -25,7 +25,7 @@ func NewStorageImageWriter(filename string, format string) (*StorageImageWriter,
|
|||||||
|
|
||||||
func (e *StorageImageWriter) Close() error {
|
func (e *StorageImageWriter) Close() error {
|
||||||
if err := e.fz.Close(); err != nil {
|
if err := e.fz.Close(); err != nil {
|
||||||
e.fh.Close()
|
_ = e.fh.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.fh.Close()
|
return e.fh.Close()
|
||||||
|
14
internal/utils/utils.go
Normal file
14
internal/utils/utils.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Printf(format string, a ...interface{}) {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Println(a ...interface{}) {
|
||||||
|
_, _ = fmt.Fprintln(os.Stderr, a...)
|
||||||
|
}
|
74
main.go
74
main.go
@ -9,14 +9,15 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
|
"github.com/tcnksm/go-latest"
|
||||||
|
|
||||||
"github.com/celogeek/go-comic-converter/v2/internal/converter"
|
"github.com/celogeek/go-comic-converter/v2/internal/converter"
|
||||||
"github.com/celogeek/go-comic-converter/v2/internal/epub"
|
"github.com/celogeek/go-comic-converter/v2/internal/epub"
|
||||||
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options"
|
||||||
"github.com/tcnksm/go-latest"
|
"github.com/celogeek/go-comic-converter/v2/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -30,7 +31,7 @@ func main() {
|
|||||||
if cmd.Options.Version {
|
if cmd.Options.Version {
|
||||||
bi, ok := debug.ReadBuildInfo()
|
bi, ok := debug.ReadBuildInfo()
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Fprintln(os.Stderr, "failed to fetch current version")
|
utils.Println("failed to fetch current version")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,12 +41,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
v, err := githubTag.Fetch()
|
v, err := githubTag.Fetch()
|
||||||
if err != nil || len(v.Versions) < 1 {
|
if err != nil || len(v.Versions) < 1 {
|
||||||
fmt.Fprintln(os.Stderr, "failed to fetch the latest version")
|
utils.Println("failed to fetch the latest version")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
latestVersion := v.Versions[0]
|
latestVersion := v.Versions[0]
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, `go-comic-converter
|
utils.Printf(`go-comic-converter
|
||||||
Path : %s
|
Path : %s
|
||||||
Sum : %s
|
Sum : %s
|
||||||
Version : %s
|
Version : %s
|
||||||
@ -65,9 +66,10 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Options.Save {
|
if cmd.Options.Save {
|
||||||
cmd.Options.SaveConfig()
|
if err := cmd.Options.SaveConfig(); err != nil {
|
||||||
fmt.Fprintf(
|
cmd.Fatal(err)
|
||||||
os.Stderr,
|
}
|
||||||
|
utils.Printf(
|
||||||
"%s%s\n\nSaving to %s\n",
|
"%s%s\n\nSaving to %s\n",
|
||||||
cmd.Options.Header(),
|
cmd.Options.Header(),
|
||||||
cmd.Options.ShowConfig(),
|
cmd.Options.ShowConfig(),
|
||||||
@ -77,14 +79,15 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Options.Show {
|
if cmd.Options.Show {
|
||||||
fmt.Fprintln(os.Stderr, cmd.Options.Header(), cmd.Options.ShowConfig())
|
utils.Println(cmd.Options.Header(), cmd.Options.ShowConfig())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Options.Reset {
|
if cmd.Options.Reset {
|
||||||
cmd.Options.ResetConfig()
|
if err := cmd.Options.ResetConfig(); err != nil {
|
||||||
fmt.Fprintf(
|
cmd.Fatal(err)
|
||||||
os.Stderr,
|
}
|
||||||
|
utils.Printf(
|
||||||
"%s%s\n\nReset default to %s\n",
|
"%s%s\n\nReset default to %s\n",
|
||||||
cmd.Options.Header(),
|
cmd.Options.Header(),
|
||||||
cmd.Options.ShowConfig(),
|
cmd.Options.ShowConfig(),
|
||||||
@ -98,11 +101,11 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Options.Json {
|
if cmd.Options.Json {
|
||||||
json.NewEncoder(os.Stdout).Encode(map[string]any{
|
_ = json.NewEncoder(os.Stdout).Encode(map[string]any{
|
||||||
"type": "options", "data": cmd.Options,
|
"type": "options", "data": cmd.Options,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(os.Stderr, cmd.Options)
|
utils.Println(cmd.Options)
|
||||||
}
|
}
|
||||||
|
|
||||||
profile := cmd.Options.GetProfile()
|
profile := cmd.Options.GetProfile()
|
||||||
@ -122,18 +125,35 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
|||||||
Quiet: cmd.Options.Quiet,
|
Quiet: cmd.Options.Quiet,
|
||||||
Json: cmd.Options.Json,
|
Json: cmd.Options.Json,
|
||||||
Image: &epuboptions.Image{
|
Image: &epuboptions.Image{
|
||||||
Crop: &epuboptions.Crop{Enabled: cmd.Options.Crop, Left: cmd.Options.CropRatioLeft, Up: cmd.Options.CropRatioUp, Right: cmd.Options.CropRatioRight, Bottom: cmd.Options.CropRatioBottom},
|
Crop: &epuboptions.Crop{
|
||||||
Quality: cmd.Options.Quality,
|
Enabled: cmd.Options.Crop,
|
||||||
Brightness: cmd.Options.Brightness,
|
Left: cmd.Options.CropRatioLeft,
|
||||||
Contrast: cmd.Options.Contrast,
|
Up: cmd.Options.CropRatioUp,
|
||||||
AutoContrast: cmd.Options.AutoContrast,
|
Right: cmd.Options.CropRatioRight,
|
||||||
AutoRotate: cmd.Options.AutoRotate,
|
Bottom: cmd.Options.CropRatioBottom,
|
||||||
AutoSplitDoublePage: cmd.Options.AutoSplitDoublePage,
|
Limit: cmd.Options.CropLimit,
|
||||||
KeepDoublePageIfSplit: cmd.Options.KeepDoublePageIfSplit,
|
SkipIfLimitReached: cmd.Options.CropSkipIfLimitReached,
|
||||||
NoBlankImage: cmd.Options.NoBlankImage,
|
},
|
||||||
Manga: cmd.Options.Manga,
|
Quality: cmd.Options.Quality,
|
||||||
HasCover: cmd.Options.HasCover,
|
Brightness: cmd.Options.Brightness,
|
||||||
View: &epuboptions.View{Width: profile.Width, Height: profile.Height, AspectRatio: cmd.Options.AspectRatio, PortraitOnly: cmd.Options.PortraitOnly, Color: epuboptions.Color{Foreground: cmd.Options.ForegroundColor, Background: cmd.Options.BackgroundColor}},
|
Contrast: cmd.Options.Contrast,
|
||||||
|
AutoContrast: cmd.Options.AutoContrast,
|
||||||
|
AutoRotate: cmd.Options.AutoRotate,
|
||||||
|
AutoSplitDoublePage: cmd.Options.AutoSplitDoublePage,
|
||||||
|
KeepDoublePageIfSplit: cmd.Options.KeepDoublePageIfSplit,
|
||||||
|
NoBlankImage: cmd.Options.NoBlankImage,
|
||||||
|
Manga: cmd.Options.Manga,
|
||||||
|
HasCover: cmd.Options.HasCover,
|
||||||
|
View: &epuboptions.View{
|
||||||
|
Width: profile.Width,
|
||||||
|
Height: profile.Height,
|
||||||
|
AspectRatio: cmd.Options.AspectRatio,
|
||||||
|
PortraitOnly: cmd.Options.PortraitOnly,
|
||||||
|
Color: epuboptions.Color{
|
||||||
|
Foreground: cmd.Options.ForegroundColor,
|
||||||
|
Background: cmd.Options.BackgroundColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
GrayScale: cmd.Options.Grayscale,
|
GrayScale: cmd.Options.Grayscale,
|
||||||
GrayScaleMode: cmd.Options.GrayscaleMode,
|
GrayScaleMode: cmd.Options.GrayscaleMode,
|
||||||
Resize: !cmd.Options.NoResize,
|
Resize: !cmd.Options.NoResize,
|
||||||
@ -141,7 +161,7 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
|||||||
AppleBookCompatibility: cmd.Options.AppleBookCompatibility,
|
AppleBookCompatibility: cmd.Options.AppleBookCompatibility,
|
||||||
},
|
},
|
||||||
}).Write(); err != nil {
|
}).Write(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
utils.Printf("Error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if !cmd.Options.Dry {
|
if !cmd.Options.Dry {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user