Merge pull request #14 from celogeek/portrait-only-mode

Portrait only mode
This commit is contained in:
Celogeek 2023-05-04 22:20:22 +02:00 committed by GitHub
commit 003a91a07e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 42 deletions

View File

@ -128,6 +128,7 @@ func (c *Converter) InitParse() {
c.AddBoolParam(&c.Options.NoResize, "noresize", c.Options.NoResize, "Do not reduce image size if exceed device size") c.AddBoolParam(&c.Options.NoResize, "noresize", c.Options.NoResize, "Do not reduce image size if exceed device size")
c.AddStringParam(&c.Options.Format, "format", c.Options.Format, "Format of output images: jpeg (lossy), png (lossless)") c.AddStringParam(&c.Options.Format, "format", c.Options.Format, "Format of output images: jpeg (lossy), png (lossless)")
c.AddFloatParam(&c.Options.AspectRatio, "aspect-ratio", c.Options.AspectRatio, "Aspect ratio (height/width) of the output\n -1 = same as device\n 0 = same as source\n1.6 = amazon advice for kindle") c.AddFloatParam(&c.Options.AspectRatio, "aspect-ratio", c.Options.AspectRatio, "Aspect ratio (height/width) of the output\n -1 = same as device\n 0 = same as source\n1.6 = amazon advice for kindle")
c.AddBoolParam(&c.Options.PortraitOnly, "portrait-only", c.Options.PortraitOnly, "Portrait only: force orientation to portrait only.")
c.AddSection("Default config") c.AddSection("Default config")
c.AddBoolParam(&c.Options.Show, "show", false, "Show your default parameters") c.AddBoolParam(&c.Options.Show, "show", false, "Show your default parameters")

View File

@ -44,6 +44,7 @@ type Options struct {
NoResize bool `yaml:"noresize"` NoResize bool `yaml:"noresize"`
Format string `yaml:"format"` Format string `yaml:"format"`
AspectRatio float64 `yaml:"aspect_ratio"` AspectRatio float64 `yaml:"aspect_ratio"`
PortraitOnly bool `yaml:"portrait_only"`
// Default Config // Default Config
Show bool `yaml:"-"` Show bool `yaml:"-"`
@ -73,30 +74,20 @@ type Options struct {
// Initialize default options. // Initialize default options.
func New() *Options { func New() *Options {
return &Options{ return &Options{
Profile: "", 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,
Brightness: 0, HasCover: true,
Contrast: 0, SortPathMode: 1,
AutoRotate: false, ForegroundColor: "000",
AutoSplitDoublePage: false, BackgroundColor: "FFF",
NoBlankImage: true, Format: "jpeg",
Manga: false, profiles: profiles.New(),
HasCover: true,
LimitMb: 0,
StripFirstDirectoryFromToc: false,
SortPathMode: 1,
ForegroundColor: "000",
BackgroundColor: "FFF",
NoResize: false,
Format: "jpeg",
AspectRatio: 0,
profiles: profiles.New(),
} }
} }
@ -202,6 +193,7 @@ func (o *Options) ShowConfig() string {
{"Background Color", fmt.Sprintf("#%s", o.BackgroundColor), true}, {"Background Color", fmt.Sprintf("#%s", o.BackgroundColor), true},
{"Resize", !o.NoResize, true}, {"Resize", !o.NoResize, true},
{"Aspect Ratio", aspectRatio, true}, {"Aspect Ratio", aspectRatio, true},
{"Portrait Only", o.PortraitOnly, true},
} { } {
if v.Condition { if v.Condition {
b.WriteString(fmt.Sprintf("\n %-26s: %v", v.Key, v.Value)) b.WriteString(fmt.Sprintf("\n %-26s: %v", v.Key, v.Value))

View File

@ -299,9 +299,12 @@ func (e *ePub) Write() error {
if totalParts > 1 { if totalParts > 1 {
title = fmt.Sprintf("%s [%d/%d]", title, i+1, totalParts) title = fmt.Sprintf("%s [%d/%d]", title, i+1, totalParts)
} }
titleAlign := "left:0" titleAlign := ""
if e.Image.Manga { if !e.Image.View.PortraitOnly {
titleAlign = "right:0" titleAlign = "left:0"
if e.Image.Manga {
titleAlign = "right:0"
}
} }
content := []zipContent{ content := []zipContent{
@ -323,10 +326,7 @@ func (e *ePub) Write() error {
{"OEBPS/Text/style.css", e.render(epubtemplates.Style, map[string]any{ {"OEBPS/Text/style.css", e.render(epubtemplates.Style, map[string]any{
"View": e.Image.View, "View": e.Image.View,
})}, })},
{"OEBPS/Text/space_title.xhtml", e.render(epubtemplates.Blank, map[string]any{
"Title": "Blank Page Title",
"ViewPort": fmt.Sprintf("width=%d,height=%d", e.Image.View.Width, e.Image.View.Height),
})},
{"OEBPS/Text/title.xhtml", e.render(epubtemplates.Text, map[string]any{ {"OEBPS/Text/title.xhtml", e.render(epubtemplates.Text, map[string]any{
"Title": title, "Title": title,
"ViewPort": fmt.Sprintf("width=%d,height=%d", e.Image.View.Width, e.Image.View.Height), "ViewPort": fmt.Sprintf("width=%d,height=%d", e.Image.View.Width, e.Image.View.Height),
@ -334,6 +334,14 @@ func (e *ePub) Write() error {
"ImageStyle": part.Cover.ImgStyle(e.Image.View.Width, e.Image.View.Height, titleAlign), "ImageStyle": part.Cover.ImgStyle(e.Image.View.Width, e.Image.View.Height, titleAlign),
})}, })},
} }
if !e.Image.View.PortraitOnly {
content = append(content, zipContent{
"OEBPS/Text/space_title.xhtml", e.render(epubtemplates.Blank, map[string]any{
"Title": "Blank Page Title",
"ViewPort": fmt.Sprintf("width=%d,height=%d", e.Image.View.Width, e.Image.View.Height),
}),
})
}
if err = wz.WriteMagic(); err != nil { if err = wz.WriteMagic(); err != nil {
return err return err
@ -367,7 +375,7 @@ func (e *ePub) Write() error {
} }
// Double Page or Last Image that is not a double page // Double Page or Last Image that is not a double page
if img.DoublePage || (img.Part == 0 && img == lastImage) { if !e.Image.View.PortraitOnly && (img.DoublePage || (img.Part == 0 && img == lastImage)) {
if err := e.writeBlank(wz, img); err != nil { if err := e.writeBlank(wz, img); err != nil {
return err return err
} }

View File

@ -17,6 +17,7 @@ type Color struct {
type View struct { type View struct {
Width, Height int Width, Height int
AspectRatio float64 AspectRatio float64
PortraitOnly bool
Color Color Color Color
} }

View File

@ -67,7 +67,12 @@ func Content(o *ContentOptions) string {
} else { } else {
spine.CreateAttr("page-progression-direction", "ltr") spine.CreateAttr("page-progression-direction", "ltr")
} }
addToElement(spine, getSpine)
if o.ImageOptions.View.PortraitOnly {
addToElement(spine, getSpinePortrait)
} else {
addToElement(spine, getSpineAuto)
}
guide := pkg.CreateElement("guide") guide := pkg.CreateElement("guide")
addToElement(guide, getGuide) addToElement(guide, getGuide)
@ -82,9 +87,6 @@ func Content(o *ContentOptions) string {
func getMeta(o *ContentOptions) []tag { func getMeta(o *ContentOptions) []tag {
metas := []tag{ metas := []tag{
{"meta", tagAttrs{"property": "dcterms:modified"}, o.UpdatedAt}, {"meta", tagAttrs{"property": "dcterms:modified"}, o.UpdatedAt},
{"meta", tagAttrs{"property": "rendition:layout"}, "pre-paginated"},
{"meta", tagAttrs{"property": "rendition:spread"}, "auto"},
{"meta", tagAttrs{"property": "rendition:orientation"}, "auto"},
{"meta", tagAttrs{"property": "schema:accessMode"}, "visual"}, {"meta", tagAttrs{"property": "schema:accessMode"}, "visual"},
{"meta", tagAttrs{"property": "schema:accessModeSufficient"}, "visual"}, {"meta", tagAttrs{"property": "schema:accessModeSufficient"}, "visual"},
{"meta", tagAttrs{"property": "schema:accessibilityHazard"}, "noFlashingHazard"}, {"meta", tagAttrs{"property": "schema:accessibilityHazard"}, "noFlashingHazard"},
@ -102,6 +104,20 @@ func getMeta(o *ContentOptions) []tag {
{"dc:date", tagAttrs{}, o.UpdatedAt}, {"dc:date", tagAttrs{}, o.UpdatedAt},
} }
if o.ImageOptions.View.PortraitOnly {
metas = append(metas, []tag{
{"meta", tagAttrs{"property": "rendition:layout"}, "pre-paginated"},
{"meta", tagAttrs{"property": "rendition:spread"}, "none"},
{"meta", tagAttrs{"property": "rendition:orientation"}, "portrait"},
}...)
} else {
metas = append(metas, []tag{
{"meta", tagAttrs{"property": "rendition:layout"}, "pre-paginated"},
{"meta", tagAttrs{"property": "rendition:spread"}, "auto"},
{"meta", tagAttrs{"property": "rendition:orientation"}, "auto"},
}...)
}
if o.ImageOptions.Manga { if o.ImageOptions.Manga {
metas = append(metas, tag{"meta", tagAttrs{"name": "primary-writing-mode", "content": "horizontal-rl"}, ""}) metas = append(metas, tag{"meta", tagAttrs{"name": "primary-writing-mode", "content": "horizontal-rl"}, ""})
} else { } else {
@ -142,18 +158,21 @@ func getManifest(o *ContentOptions) []tag {
items := []tag{ items := []tag{
{"item", tagAttrs{"id": "toc", "href": "toc.xhtml", "properties": "nav", "media-type": "application/xhtml+xml"}, ""}, {"item", tagAttrs{"id": "toc", "href": "toc.xhtml", "properties": "nav", "media-type": "application/xhtml+xml"}, ""},
{"item", tagAttrs{"id": "css", "href": "Text/style.css", "media-type": "text/css"}, ""}, {"item", tagAttrs{"id": "css", "href": "Text/style.css", "media-type": "text/css"}, ""},
{"item", tagAttrs{"id": "space_title", "href": "Text/space_title.xhtml", "media-type": "application/xhtml+xml"}, ""},
{"item", tagAttrs{"id": "page_title", "href": "Text/title.xhtml", "media-type": "application/xhtml+xml"}, ""}, {"item", tagAttrs{"id": "page_title", "href": "Text/title.xhtml", "media-type": "application/xhtml+xml"}, ""},
{"item", tagAttrs{"id": "img_title", "href": fmt.Sprintf("Images/title.%s", o.ImageOptions.Format), "media-type": fmt.Sprintf("image/%s", o.ImageOptions.Format)}, ""}, {"item", tagAttrs{"id": "img_title", "href": fmt.Sprintf("Images/title.%s", o.ImageOptions.Format), "media-type": fmt.Sprintf("image/%s", o.ImageOptions.Format)}, ""},
} }
if !o.ImageOptions.View.PortraitOnly {
items = append(items, tag{"item", tagAttrs{"id": "space_title", "href": "Text/space_title.xhtml", "media-type": "application/xhtml+xml"}, ""})
}
if o.ImageOptions.HasCover || o.Current > 1 { if o.ImageOptions.HasCover || o.Current > 1 {
addTag(o.Cover, false) addTag(o.Cover, false)
} }
lastImage := o.Images[len(o.Images)-1] lastImage := o.Images[len(o.Images)-1]
for _, img := range o.Images { for _, img := range o.Images {
addTag(img, img.DoublePage || (img.Part == 0 && img == lastImage)) addTag(img, !o.ImageOptions.View.PortraitOnly && (img.DoublePage || (img.Part == 0 && img == lastImage)))
} }
items = append(items, imageTags...) items = append(items, imageTags...)
@ -164,7 +183,7 @@ func getManifest(o *ContentOptions) []tag {
} }
// spine part of the content // spine part of the content
func getSpine(o *ContentOptions) []tag { func getSpineAuto(o *ContentOptions) []tag {
isOnTheRight := !o.ImageOptions.Manga isOnTheRight := !o.ImageOptions.Manga
getSpread := func(isDoublePage bool) string { getSpread := func(isDoublePage bool) string {
isOnTheRight = !isOnTheRight isOnTheRight = !isOnTheRight
@ -214,6 +233,20 @@ func getSpine(o *ContentOptions) []tag {
return spine return spine
} }
func getSpinePortrait(o *ContentOptions) []tag {
spine := []tag{
{"itemref", tagAttrs{"idref": "page_title"}, ""},
}
for _, img := range o.Images {
spine = append(spine, tag{
"itemref",
tagAttrs{"idref": img.PageKey()},
"",
})
}
return spine
}
// guide part of the content // guide part of the content
func getGuide(o *ContentOptions) []tag { func getGuide(o *ContentOptions) []tag {
guide := []tag{} guide := []tag{}

View File

@ -130,9 +130,10 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
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,
AspectRatio: cmd.Options.AspectRatio, AspectRatio: cmd.Options.AspectRatio,
PortraitOnly: cmd.Options.PortraitOnly,
Color: epuboptions.Color{ Color: epuboptions.Color{
Foreground: cmd.Options.ForegroundColor, Foreground: cmd.Options.ForegroundColor,
Background: cmd.Options.BackgroundColor, Background: cmd.Options.BackgroundColor,