mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-24 15:52:38 +02:00
Merge branch '34-spacexhtml-bug-in-split-page-mode'
This commit is contained in:
commit
84863e72d2
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"`
|
||||||
@ -82,25 +83,24 @@ 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,
|
||||||
CropLimit: 10,
|
NoBlankImage: true,
|
||||||
CropSkipIfLimitReached: true,
|
HasCover: true,
|
||||||
NoBlankImage: true,
|
KeepDoublePageIfSplit: true,
|
||||||
HasCover: true,
|
KeepSplitDoublePageAspect: true,
|
||||||
KeepDoublePageIfSplit: true,
|
SortPathMode: 1,
|
||||||
SortPathMode: 1,
|
ForegroundColor: "000",
|
||||||
ForegroundColor: "000",
|
BackgroundColor: "FFF",
|
||||||
BackgroundColor: "FFF",
|
Format: "jpeg",
|
||||||
Format: "jpeg",
|
TitlePage: 1,
|
||||||
TitlePage: 1,
|
profiles: profiles.New(),
|
||||||
profiles: profiles.New(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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},
|
||||||
|
@ -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 {
|
|
||||||
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
|
||||||
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,23 +22,24 @@ 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
|
||||||
NoBlankImage bool
|
KeepSplitDoublePageAspect bool
|
||||||
Manga bool
|
NoBlankImage bool
|
||||||
HasCover bool
|
Manga bool
|
||||||
View *View
|
HasCover bool
|
||||||
GrayScale bool
|
View *View
|
||||||
GrayScaleMode int
|
GrayScale bool
|
||||||
Resize bool
|
GrayScaleMode int
|
||||||
Format string
|
Resize bool
|
||||||
AppleBookCompatibility bool
|
Format string
|
||||||
|
AppleBookCompatibility bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
21
main.go
21
main.go
@ -134,16 +134,17 @@ $ 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,
|
||||||
NoBlankImage: cmd.Options.NoBlankImage,
|
KeepSplitDoublePageAspect: cmd.Options.KeepSplitDoublePageAspect,
|
||||||
Manga: cmd.Options.Manga,
|
NoBlankImage: cmd.Options.NoBlankImage,
|
||||||
HasCover: cmd.Options.HasCover,
|
Manga: cmd.Options.Manga,
|
||||||
|
HasCover: cmd.Options.HasCover,
|
||||||
View: &epuboptions.View{
|
View: &epuboptions.View{
|
||||||
Width: profile.Width,
|
Width: profile.Width,
|
||||||
Height: profile.Height,
|
Height: profile.Height,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user