Compare commits

..

No commits in common. "2ce29d62ecacc6c49085c59a7af054205de7b9ef" and "2c372594cc179580678d4c4f444dd66ed635db3a" have entirely different histories.

7 changed files with 81 additions and 123 deletions

View File

@ -148,7 +148,7 @@ Options:
Grayscale : true Grayscale : true
Grayscale mode : normal Grayscale mode : normal
Crop : true Crop : true
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
Auto contrast : true Auto contrast : true
Auto rotate : true Auto rotate : true
Auto split double page : true Auto split double page : true
@ -196,7 +196,7 @@ Options:
Grayscale : true Grayscale : true
Grayscale mode : normal Grayscale mode : normal
Crop : true Crop : true
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
Auto contrast : true Auto contrast : true
Auto rotate : true Auto rotate : true
Auto split double page : true Auto split double page : true
@ -254,7 +254,7 @@ Options:
Grayscale : true Grayscale : true
Grayscale mode : normal Grayscale mode : normal
Crop : true Crop : true
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
Auto contrast : false Auto contrast : false
Auto rotate : false Auto rotate : false
Auto split double page : false Auto split double page : false
@ -285,12 +285,11 @@ Options:
Grayscale : true Grayscale : true
Grayscale mode : normal Grayscale mode : normal
Crop : true Crop : true
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
Auto contrast : true Auto contrast : true
Auto rotate : true Auto rotate : true
Auto split double page : true Auto split double page : true
Keep double page if split : true Keep double page if split : true
Keep split double page aspect : true
No blank image : true No blank image : true
Manga : true Manga : true
Has cover : true Has cover : true
@ -319,13 +318,15 @@ Options:
Grayscale : true Grayscale : true
Grayscale mode : normal Grayscale mode : normal
Crop : true Crop : true
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
Auto contrast : false Auto contrast : true
Auto rotate : false Auto rotate : true
Auto split double page : false Auto split double page : true
Keep double page if split : true
No blank image : true No blank image : true
Manga : false Manga : false
Has cover : true Has cover : true
Limit : 200 Mb
Strip first directory from toc : false Strip first directory from toc : false
Sort path mode : path=alphanumeric, file=alpha Sort path mode : path=alphanumeric, file=alpha
Foreground color : #000 Foreground color : #000
@ -353,7 +354,7 @@ Options:
Grayscale : true Grayscale : true
Grayscale mode : normal Grayscale mode : normal
Crop : true Crop : true
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
Auto contrast : false Auto contrast : false
Auto rotate : false Auto rotate : false
Auto split double page : false Auto split double page : false
@ -388,14 +389,13 @@ Options:
Grayscale : true Grayscale : true
Grayscale mode : normal Grayscale mode : normal
Crop : true Crop : true
Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 10% - Skip true
Auto contrast : false Auto contrast : false
Auto rotate : false Auto rotate : false
Auto split double page : false Auto split double page : false
No blank image : true No blank image : true
Manga : true Manga : true
Has cover : true Has cover : true
Limit : 200 Mb
Strip first directory from toc : false Strip first directory from toc : false
Sort path mode : path=alphanumeric, file=alpha Sort path mode : path=alphanumeric, file=alpha
Foreground color : #000 Foreground color : #000
@ -482,9 +482,9 @@ 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 -crop-limit int (default 10)
Crop limit: maximum number of cropping in percentage allowed. 0 mean unlimited. Crop limit: maximum number of cropping in percentage allowed. 0 mean unlimited.
-crop-skip-if-limit-reached -crop-skip-if-limit-reached (default true)
Crop skip if limit reached. Crop skip if limit reached.
-brightness int -brightness int
Brightness readjustment: between -100 and 100, > 0 lighter, < 0 darker Brightness readjustment: between -100 and 100, > 0 lighter, < 0 darker
@ -498,8 +498,6 @@ Config:
Auto Split double page when width > height Auto Split double page when width > height
-keepdoublepageifsplit (default true) -keepdoublepageifsplit (default true)
Keep the double page if split Keep the double page if split
-keepsplitdoublepageaspect (default true)
Keep aspect of split part of a double page (best for landscape rendering)
-noblankimage (default true) -noblankimage (default true)
Remove blank image Remove blank image
-manga -manga

View File

@ -122,7 +122,6 @@ func (c *Converter) InitParse() {
c.AddBoolParam(&c.Options.AutoRotate, "autorotate", c.Options.AutoRotate, "Auto Rotate page when width > height") c.AddBoolParam(&c.Options.AutoRotate, "autorotate", c.Options.AutoRotate, "Auto Rotate page when width > height")
c.AddBoolParam(&c.Options.AutoSplitDoublePage, "autosplitdoublepage", c.Options.AutoSplitDoublePage, "Auto Split double page when width > height") c.AddBoolParam(&c.Options.AutoSplitDoublePage, "autosplitdoublepage", c.Options.AutoSplitDoublePage, "Auto Split double page when width > height")
c.AddBoolParam(&c.Options.KeepDoublePageIfSplit, "keepdoublepageifsplit", c.Options.KeepDoublePageIfSplit, "Keep the double page if split") c.AddBoolParam(&c.Options.KeepDoublePageIfSplit, "keepdoublepageifsplit", c.Options.KeepDoublePageIfSplit, "Keep the double page if split")
c.AddBoolParam(&c.Options.KeepSplitDoublePageAspect, "keepsplitdoublepageaspect", c.Options.KeepSplitDoublePageAspect, "Keep aspect of split part of a double page (best for landscape rendering)")
c.AddBoolParam(&c.Options.NoBlankImage, "noblankimage", c.Options.NoBlankImage, "Remove blank image") c.AddBoolParam(&c.Options.NoBlankImage, "noblankimage", c.Options.NoBlankImage, "Remove blank image")
c.AddBoolParam(&c.Options.Manga, "manga", c.Options.Manga, "Manga mode (right to left)") c.AddBoolParam(&c.Options.Manga, "manga", c.Options.Manga, "Manga mode (right to left)")
c.AddBoolParam(&c.Options.HasCover, "hascover", c.Options.HasCover, "Has cover. Indicate if your comic have a cover. The first page will be used as a cover and include after the title.") c.AddBoolParam(&c.Options.HasCover, "hascover", c.Options.HasCover, "Has cover. Indicate if your comic have a cover. The first page will be used as a cover and include after the title.")
@ -275,11 +274,6 @@ func (c *Converter) Parse() {
if c.Options.AppleBookCompatibility { if c.Options.AppleBookCompatibility {
c.Options.AutoSplitDoublePage = true c.Options.AutoSplitDoublePage = true
c.Options.KeepDoublePageIfSplit = false c.Options.KeepDoublePageIfSplit = false
c.Options.KeepSplitDoublePageAspect = true
}
if c.Options.PortraitOnly {
c.Options.KeepSplitDoublePageAspect = false
} }
} }

View File

@ -38,7 +38,6 @@ type Options struct {
AutoRotate bool `yaml:"auto_rotate"` AutoRotate bool `yaml:"auto_rotate"`
AutoSplitDoublePage bool `yaml:"auto_split_double_page"` AutoSplitDoublePage bool `yaml:"auto_split_double_page"`
KeepDoublePageIfSplit bool `yaml:"keep_double_page_if_split"` KeepDoublePageIfSplit bool `yaml:"keep_double_page_if_split"`
KeepSplitDoublePageAspect bool `yaml:"keep_split_double_page_aspect"`
NoBlankImage bool `yaml:"no_blank_image"` NoBlankImage bool `yaml:"no_blank_image"`
Manga bool `yaml:"manga"` Manga bool `yaml:"manga"`
HasCover bool `yaml:"has_cover"` HasCover bool `yaml:"has_cover"`
@ -83,24 +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,
KeepSplitDoublePageAspect: true, HasCover: true,
SortPathMode: 1, KeepDoublePageIfSplit: true,
ForegroundColor: "000", SortPathMode: 1,
BackgroundColor: "FFF", ForegroundColor: "000",
Format: "jpeg", BackgroundColor: "FFF",
TitlePage: 1, Format: "jpeg",
profiles: profiles.New(), TitlePage: 1,
profiles: profiles.New(),
} }
} }
@ -179,7 +179,6 @@ func (o *Options) MarshalJSON() ([]byte, error) {
out["autosplitdoublepage"] = o.AutoSplitDoublePage out["autosplitdoublepage"] = o.AutoSplitDoublePage
if o.AutoSplitDoublePage { if o.AutoSplitDoublePage {
out["keepdoublepageifsplit"] = o.KeepDoublePageIfSplit out["keepdoublepageifsplit"] = o.KeepDoublePageIfSplit
out["keepsplitdoublepageaspect"] = o.KeepSplitDoublePageAspect
} }
} }
if o.LimitMb != 0 { if o.LimitMb != 0 {
@ -286,7 +285,6 @@ func (o *Options) ShowConfig() string {
{"Auto rotate", o.AutoRotate, true}, {"Auto rotate", o.AutoRotate, true},
{"Auto split double page", o.AutoSplitDoublePage, o.PortraitOnly || !o.AppleBookCompatibility}, {"Auto split double page", o.AutoSplitDoublePage, o.PortraitOnly || !o.AppleBookCompatibility},
{"Keep double page if split", o.KeepDoublePageIfSplit, (o.PortraitOnly || !o.AppleBookCompatibility) && o.AutoSplitDoublePage}, {"Keep double page if split", o.KeepDoublePageIfSplit, (o.PortraitOnly || !o.AppleBookCompatibility) && o.AutoSplitDoublePage},
{"Keep split double page aspect", o.KeepSplitDoublePageAspect, (o.PortraitOnly || !o.AppleBookCompatibility) && o.AutoSplitDoublePage},
{"No blank image", o.NoBlankImage, true}, {"No blank image", o.NoBlankImage, true},
{"Manga", o.Manga, true}, {"Manga", o.Manga, true},
{"Has cover", o.HasCover, true}, {"Has cover", o.HasCover, true},

View File

@ -28,8 +28,10 @@ type cutRatioOptions struct {
func findMargin(img image.Image, bounds image.Rectangle, cutRatio cutRatioOptions, limit int, skipIfLimitReached bool) 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,42 +93,10 @@ BOTTOM:
} }
} }
imgArea.Max.Y-- imgArea.Max.Y--
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
// no limit or blankImage
if limit == 0 || imgArea.Dx() == 0 || imgArea.Dy() == 0 {
return imgArea
}
exceedX, exceedY := limitExceed(bounds, imgArea, limit)
if skipIfLimitReached && (exceedX > 0 || exceedY > 0) {
return bounds
}
imgArea.Min.X, imgArea.Max.X = correctLine(imgArea.Min.X, imgArea.Max.X, bounds.Min.X, bounds.Max.X, exceedX)
imgArea.Min.Y, imgArea.Max.Y = correctLine(imgArea.Min.Y, imgArea.Max.Y, bounds.Min.Y, bounds.Max.Y, exceedY)
return imgArea return imgArea
} }
func limitExceed(bounds, newBounds image.Rectangle, limit int) (int, int) {
return bounds.Dx() - newBounds.Dx() - bounds.Dx()*limit/100, bounds.Dy() - newBounds.Dy() - bounds.Dy()*limit/100
}
func correctLine(min, max, bMin, bMax, exceed int) (int, int) {
if exceed <= 0 {
return min, max
}
min -= exceed / 2
max += exceed / 2
if min < bMin {
max += bMin - min
min = bMin
}
if max > bMax {
min -= max - bMax
max = bMax
}
return min, max
}

View File

@ -178,9 +178,7 @@ func (e *EPUBImageProcessor) transformImage(input *task, part int, right bool) *
src := input.Image src := input.Image
srcBounds := src.Bounds() srcBounds := src.Bounds()
// In portrait only, we don't need to keep aspect ratio between each split. if part > 0 {
// We first cut, the crop.
if part > 0 && !e.Image.KeepSplitDoublePageAspect {
g.Add(epubimagefilters.CropSplitDoublePage(right)) g.Add(epubimagefilters.CropSplitDoublePage(right))
} }
@ -207,18 +205,11 @@ func (e *EPUBImageProcessor) transformImage(input *task, part int, right bool) *
} }
} }
// With landscape support, we need to keep aspect ratio between each split
// We first crop, then cut
if part > 0 && e.Image.KeepSplitDoublePageAspect {
g.Add(epubimagefilters.CropSplitDoublePage(right))
}
dstBounds := g.Bounds(src.Bounds()) dstBounds := g.Bounds(src.Bounds())
// Original && Cropped version need to landscape oriented // Original && Cropped version need to landscape oriented
// Only part 0 can be a double page isDoublePage := srcBounds.Dx() > srcBounds.Dy() && dstBounds.Dx() > dstBounds.Dy()
isDoublePage := part == 0 && srcBounds.Dx() > srcBounds.Dy() && dstBounds.Dx() > dstBounds.Dy()
if e.Image.AutoRotate && isDoublePage { if part == 0 && e.Image.AutoRotate && isDoublePage {
g.Add(gift.Rotate90()) g.Add(gift.Rotate90())
} }

View File

@ -22,24 +22,23 @@ type View struct {
} }
type Image struct { type Image struct {
Crop *Crop Crop *Crop
Quality int Quality int
Brightness int Brightness int
Contrast int Contrast int
AutoContrast bool AutoContrast bool
AutoRotate bool AutoRotate bool
AutoSplitDoublePage bool AutoSplitDoublePage bool
KeepDoublePageIfSplit bool KeepDoublePageIfSplit bool
KeepSplitDoublePageAspect bool NoBlankImage bool
NoBlankImage bool Manga bool
Manga bool HasCover bool
HasCover bool View *View
View *View GrayScale bool
GrayScale bool GrayScaleMode int
GrayScaleMode int Resize bool
Resize bool Format string
Format string AppleBookCompatibility bool
AppleBookCompatibility bool
} }
type Options struct { type Options struct {

21
main.go
View File

@ -134,17 +134,16 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
Limit: cmd.Options.CropLimit, Limit: cmd.Options.CropLimit,
SkipIfLimitReached: cmd.Options.CropSkipIfLimitReached, SkipIfLimitReached: cmd.Options.CropSkipIfLimitReached,
}, },
Quality: cmd.Options.Quality, Quality: cmd.Options.Quality,
Brightness: cmd.Options.Brightness, Brightness: cmd.Options.Brightness,
Contrast: cmd.Options.Contrast, Contrast: cmd.Options.Contrast,
AutoContrast: cmd.Options.AutoContrast, AutoContrast: cmd.Options.AutoContrast,
AutoRotate: cmd.Options.AutoRotate, AutoRotate: cmd.Options.AutoRotate,
AutoSplitDoublePage: cmd.Options.AutoSplitDoublePage, AutoSplitDoublePage: cmd.Options.AutoSplitDoublePage,
KeepDoublePageIfSplit: cmd.Options.KeepDoublePageIfSplit, KeepDoublePageIfSplit: cmd.Options.KeepDoublePageIfSplit,
KeepSplitDoublePageAspect: cmd.Options.KeepSplitDoublePageAspect, NoBlankImage: cmd.Options.NoBlankImage,
NoBlankImage: cmd.Options.NoBlankImage, Manga: cmd.Options.Manga,
Manga: cmd.Options.Manga, HasCover: cmd.Options.HasCover,
HasCover: cmd.Options.HasCover,
View: &epuboptions.View{ View: &epuboptions.View{
Width: profile.Width, Width: profile.Width,
Height: profile.Height, Height: profile.Height,