Merge branch '34-spacexhtml-bug-in-split-page-mode'

This commit is contained in:
Celogeek 2024-05-09 15:51:45 +02:00
commit 84863e72d2
Signed by: celogeek
SSH Key Fingerprint: SHA256:njNJLzoLQdbV9PC6ehcruRb0QnEgxABoCYZ+0+aUIYc
6 changed files with 107 additions and 67 deletions

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,