Compare commits

...

7 Commits

Author SHA1 Message Date
2ce29d62ec
update README 2024-05-09 15:59:04 +02:00
84863e72d2
Merge branch '34-spacexhtml-bug-in-split-page-mode' 2024-05-09 15:51:45 +02:00
87faac877c
add option to not preserve aspect on split double page 2024-05-09 15:14:54 +02:00
62fc520ebb
cut more each side of doublepage split in portrait only 2024-05-09 12:28:48 +02:00
27d617640a
detect empty page 2024-05-08 18:49:01 +02:00
f9ebe71b9e
crop double page after autocrop
fix landscape display when each side can be cut differently.
A doublepage is 1 big image, and should be cut as one.
2024-05-07 08:55:42 +02:00
f7f8680eb3
fix doublePage issue when part crop are also a double page 2024-05-06 17:24:31 +02:00
7 changed files with 123 additions and 81 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 10% - Skip true Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false
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 10% - Skip true Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false
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 10% - Skip true Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false
Auto contrast : false Auto contrast : false
Auto rotate : false Auto rotate : false
Auto split double page : false Auto split double page : false
@ -285,11 +285,12 @@ 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 10% - Skip true Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false
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
@ -318,15 +319,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 10% - Skip true Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false
Auto contrast : true Auto contrast : false
Auto rotate : true Auto rotate : false
Auto split double page : true Auto split double page : false
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
@ -354,7 +353,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 10% - Skip true Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false
Auto contrast : false Auto contrast : false
Auto rotate : false Auto rotate : false
Auto split double page : false Auto split double page : false
@ -389,13 +388,14 @@ 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 10% - Skip true Crop ratio : 1 Left - 1 Up - 1 Right - 3 Bottom - Limit 0% - Skip false
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 (default 10) -crop-limit int
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 (default true) -crop-skip-if-limit-reached
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,6 +498,8 @@ 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,6 +122,7 @@ 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.")
@ -274,6 +275,11 @@ 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,6 +38,7 @@ 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"`
@ -90,11 +91,10 @@ func New() *Options {
CropRatioUp: 1, CropRatioUp: 1,
CropRatioRight: 1, CropRatioRight: 1,
CropRatioBottom: 3, CropRatioBottom: 3,
CropLimit: 10,
CropSkipIfLimitReached: true,
NoBlankImage: true, NoBlankImage: true,
HasCover: true, HasCover: true,
KeepDoublePageIfSplit: true, KeepDoublePageIfSplit: true,
KeepSplitDoublePageAspect: true,
SortPathMode: 1, SortPathMode: 1,
ForegroundColor: "000", ForegroundColor: "000",
BackgroundColor: "FFF", BackgroundColor: "FFF",
@ -179,6 +179,7 @@ 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 {
@ -285,6 +286,7 @@ 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,10 +28,8 @@ 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, maxCrop := imgArea.Min.X, maxCropX; x < imgArea.Max.X && (limit == 0 || maxCrop > 0); x, maxCrop = x+1, maxCrop-1 { for x := imgArea.Min.X; x < imgArea.Max.X; x++ {
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)) {
@ -42,13 +40,10 @@ LEFT:
} }
} }
imgArea.Min.X++ imgArea.Min.X++
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
UP: UP:
for y, maxCrop := imgArea.Min.Y, maxCropY; y < imgArea.Max.Y && (limit == 0 || maxCrop > 0); y, maxCrop = y+1, maxCrop-1 { for y := imgArea.Min.Y; y < imgArea.Max.Y; y++ {
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)) {
@ -59,13 +54,10 @@ UP:
} }
} }
imgArea.Min.Y++ imgArea.Min.Y++
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
RIGHT: RIGHT:
for x, maxCrop := imgArea.Max.X-1, maxCropX; x >= imgArea.Min.X && (limit == 0 || maxCrop > 0); x, maxCrop = x-1, maxCrop-1 { for x := imgArea.Max.X - 1; x >= imgArea.Min.X; x-- {
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)) {
@ -76,13 +68,10 @@ RIGHT:
} }
} }
imgArea.Max.X-- imgArea.Max.X--
if limit > 0 && maxCrop == 1 && skipIfLimitReached {
return bounds
}
} }
BOTTOM: BOTTOM:
for y, maxCrop := imgArea.Max.Y-1, maxCropY; y >= imgArea.Min.Y && (limit == 0 || maxCrop > 0); y, maxCrop = y-1, maxCrop-1 { for y := imgArea.Max.Y - 1; y >= imgArea.Min.Y; y-- {
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)) {
@ -93,10 +82,42 @@ BOTTOM:
} }
} }
imgArea.Max.Y-- imgArea.Max.Y--
if limit > 0 && maxCrop == 1 && skipIfLimitReached { }
// 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 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,7 +178,9 @@ func (e *EPUBImageProcessor) transformImage(input *task, part int, right bool) *
src := input.Image src := input.Image
srcBounds := src.Bounds() srcBounds := src.Bounds()
if part > 0 { // In portrait only, we don't need to keep aspect ratio between each split.
// We first cut, the crop.
if part > 0 && !e.Image.KeepSplitDoublePageAspect {
g.Add(epubimagefilters.CropSplitDoublePage(right)) g.Add(epubimagefilters.CropSplitDoublePage(right))
} }
@ -205,11 +207,18 @@ 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
isDoublePage := srcBounds.Dx() > srcBounds.Dy() && dstBounds.Dx() > dstBounds.Dy() // Only part 0 can be a double page
isDoublePage := part == 0 && srcBounds.Dx() > srcBounds.Dy() && dstBounds.Dx() > dstBounds.Dy()
if part == 0 && e.Image.AutoRotate && isDoublePage { if e.Image.AutoRotate && isDoublePage {
g.Add(gift.Rotate90()) g.Add(gift.Rotate90())
} }

View File

@ -30,6 +30,7 @@ type Image struct {
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 File

@ -141,6 +141,7 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
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,