mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-25 16:22:37 +02:00
Compare commits
8 Commits
ef27485273
...
418d51662c
Author | SHA1 | Date | |
---|---|---|---|
418d51662c | |||
88eea07747 | |||
51c04fecb0 | |||
d96e63bc50 | |||
b27a826cd2 | |||
4a43760535 | |||
bc19e5e4ce | |||
7f195a0b79 |
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/celogeek/go-comic-converter/v2/internal/converter/profiles"
|
||||
"gopkg.in/yaml.v3"
|
||||
@ -111,7 +112,7 @@ func (o *Options) LoadDefault() error {
|
||||
}
|
||||
|
||||
func (o *Options) ShowDefault() string {
|
||||
var profileDesc string
|
||||
var profileDesc, viewDesc string
|
||||
profile := o.GetProfile()
|
||||
if profile != nil {
|
||||
profileDesc = fmt.Sprintf(
|
||||
@ -121,6 +122,13 @@ func (o *Options) ShowDefault() string {
|
||||
profile.Width,
|
||||
profile.Height,
|
||||
)
|
||||
|
||||
perfectWidth, perfectHeight := profile.PerfectDim()
|
||||
viewDesc = fmt.Sprintf(
|
||||
"%dx%d",
|
||||
perfectWidth,
|
||||
perfectHeight,
|
||||
)
|
||||
}
|
||||
limitmb := "nolimit"
|
||||
if o.LimitMb > 0 {
|
||||
@ -139,6 +147,8 @@ func (o *Options) ShowDefault() string {
|
||||
|
||||
return fmt.Sprintf(`
|
||||
Profile : %s
|
||||
ViewRatio : 1:%s
|
||||
View : %s
|
||||
Quality : %d
|
||||
Crop : %v
|
||||
Brightness : %d
|
||||
@ -152,6 +162,8 @@ func (o *Options) ShowDefault() string {
|
||||
StripFirstDirectoryFromToc: %v
|
||||
SortPathMode : %s`,
|
||||
profileDesc,
|
||||
strings.TrimRight(fmt.Sprintf("%f", profiles.PerfectRatio), "0"),
|
||||
viewDesc,
|
||||
o.Quality,
|
||||
o.Crop,
|
||||
o.Brightness,
|
@ -12,6 +12,19 @@ type Profile struct {
|
||||
Height int
|
||||
}
|
||||
|
||||
const PerfectRatio = 1.5
|
||||
|
||||
func (p Profile) PerfectDim() (int, int) {
|
||||
width, height := float64(p.Width), float64(p.Height)
|
||||
perfectWidth, perfectHeight := height/PerfectRatio, width*PerfectRatio
|
||||
if perfectWidth > width {
|
||||
perfectWidth = width
|
||||
} else {
|
||||
perfectHeight = height
|
||||
}
|
||||
return int(perfectWidth), int(perfectHeight)
|
||||
}
|
||||
|
||||
type Profiles []Profile
|
||||
|
||||
func New() Profiles {
|
@ -98,13 +98,9 @@ func (e *ePub) writeImage(wz *epubZip, img *Image) error {
|
||||
fmt.Sprintf("OEBPS/%s", img.TextPath()),
|
||||
e.render(textTmpl, map[string]any{
|
||||
"Title": fmt.Sprintf("Image %d Part %d", img.Id, img.Part),
|
||||
"ViewPort": fmt.Sprintf("width=%d, height=%d", e.ViewWidth, e.ViewHeight),
|
||||
"ImageStyle": fmt.Sprintf(
|
||||
"width:%dpx; height:%dpx;",
|
||||
img.Width,
|
||||
img.Height,
|
||||
),
|
||||
"ViewPort": fmt.Sprintf("width=%d,height=%d", e.ViewWidth, e.ViewHeight),
|
||||
"ImagePath": img.ImgPath(),
|
||||
"ImageStyle": img.ImgStyle(e.ViewWidth, e.ViewHeight, e.Manga),
|
||||
}),
|
||||
)
|
||||
|
||||
@ -120,7 +116,7 @@ func (e *ePub) writeBlank(wz *epubZip, img *Image) error {
|
||||
fmt.Sprintf("OEBPS/Text/%d_sp.xhtml", img.Id),
|
||||
e.render(blankTmpl, map[string]any{
|
||||
"Title": fmt.Sprintf("Blank Page %d", img.Id),
|
||||
"ViewPort": fmt.Sprintf("width=%d, height=%d", e.ViewWidth, e.ViewHeight),
|
||||
"ViewPort": fmt.Sprintf("width=%d,height=%d", e.ViewWidth, e.ViewHeight),
|
||||
}),
|
||||
)
|
||||
}
|
@ -24,7 +24,6 @@ func (e *ePub) getMeta(title string, part *epubPart, currentPart, totalPart int)
|
||||
{"meta", TagAttrs{"property": "rendition:layout"}, "pre-paginated"},
|
||||
{"meta", TagAttrs{"property": "rendition:spread"}, "auto"},
|
||||
{"meta", TagAttrs{"property": "rendition:orientation"}, "auto"},
|
||||
{"meta", TagAttrs{"property": "ibooks:specified-fonts"}, "true"},
|
||||
{"meta", TagAttrs{"property": "schema:accessMode"}, "visual"},
|
||||
{"meta", TagAttrs{"property": "schema:accessModeSufficient"}, "visual"},
|
||||
{"meta", TagAttrs{"property": "schema:accessibilityHazard"}, "noFlashingHazard"},
|
||||
@ -151,7 +150,7 @@ func (e *ePub) getContent(title string, part *epubPart, currentPart, totalPart i
|
||||
pkg.CreateAttr("xmlns", "http://www.idpf.org/2007/opf")
|
||||
pkg.CreateAttr("unique-identifier", "ean")
|
||||
pkg.CreateAttr("version", "3.0")
|
||||
pkg.CreateAttr("prefix", "rendition: http://www.idpf.org/vocab/rendition/# ibooks: http://vocabulary.itunes.apple.com/rdf/ibooks/vocabulary-extensions-1.0/")
|
||||
pkg.CreateAttr("prefix", "rendition: http://www.idpf.org/vocab/rendition/#")
|
||||
|
||||
addToElement := func(elm *etree.Element, meth func(title string, part *epubPart, currentPart, totalPart int) []Tag) {
|
||||
for _, p := range meth(title, part, currentPart, totalPart) {
|
@ -20,7 +20,6 @@ func NewGift(options *ImageOptions) *gift.GIFT {
|
||||
}
|
||||
g.Add(
|
||||
filters.Resize(options.ViewWidth, options.ViewHeight, gift.LanczosResampling),
|
||||
filters.Position(options.ViewWidth, options.ViewHeight, filters.PositionCenter),
|
||||
filters.Pixel(),
|
||||
)
|
||||
return g
|
||||
@ -37,7 +36,7 @@ func NewGiftSplitDoublePage(options *ImageOptions) []*gift.GIFT {
|
||||
filters.CropSplitDoublePage(!options.Manga),
|
||||
)
|
||||
|
||||
for i, g := range gifts {
|
||||
for _, g := range gifts {
|
||||
if options.Contrast != 0 {
|
||||
g.Add(gift.Contrast(float32(options.Contrast)))
|
||||
}
|
||||
@ -45,14 +44,8 @@ func NewGiftSplitDoublePage(options *ImageOptions) []*gift.GIFT {
|
||||
g.Add(gift.Brightness(float32(options.Brightness)))
|
||||
}
|
||||
|
||||
position := filters.PositionLeft
|
||||
if (i == 1) == options.Manga {
|
||||
position = filters.PositionRight
|
||||
}
|
||||
|
||||
g.Add(
|
||||
filters.Resize(options.ViewWidth, options.ViewHeight, gift.LanczosResampling),
|
||||
filters.Position(options.ViewWidth, options.ViewHeight, position),
|
||||
)
|
||||
}
|
||||
|
@ -53,6 +53,36 @@ func (i *Image) ImgPath() string {
|
||||
return fmt.Sprintf("Images/%d_p%d.jpg", i.Id, i.Part)
|
||||
}
|
||||
|
||||
func (i *Image) ImgStyle(viewWidth, viewHeight int, manga bool) string {
|
||||
marginW, marginH := float64(viewWidth-i.Width)/2, float64(viewHeight-i.Height)/2
|
||||
left, top := marginW*100/float64(viewWidth), marginH*100/float64(viewHeight)
|
||||
var align string
|
||||
switch i.Part {
|
||||
case 0:
|
||||
align = fmt.Sprintf("left:%.2f%%", left)
|
||||
case 1:
|
||||
if manga {
|
||||
align = "left:0"
|
||||
} else {
|
||||
align = "right:0"
|
||||
}
|
||||
case 2:
|
||||
if manga {
|
||||
align = "right:0"
|
||||
} else {
|
||||
align = "left:0"
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"width:%dpx; height:%dpx; top:%.2f%%; %s;",
|
||||
i.Width,
|
||||
i.Height,
|
||||
top,
|
||||
align,
|
||||
)
|
||||
}
|
||||
|
||||
func (i *Image) SpacePath() string {
|
||||
return fmt.Sprintf("Text/%d_sp.xhtml", i.Id)
|
||||
}
|
@ -10,7 +10,6 @@ import (
|
||||
func NewBar(max int, description string, currentJob, totalJob int) *progressbar.ProgressBar {
|
||||
fmtJob := fmt.Sprintf("%%0%dd", len(fmt.Sprint(totalJob)))
|
||||
fmtDesc := fmt.Sprintf("[%s/%s] %%-15s", fmtJob, fmtJob)
|
||||
return progressbar.DefaultBytesSilent(int64(max))
|
||||
return progressbar.NewOptions(max,
|
||||
progressbar.OptionSetWriter(os.Stderr),
|
||||
progressbar.OptionOnCompletion(func() {
|
21
internal/epub/epub_templates.go
Normal file
21
internal/epub/epub_templates.go
Normal file
@ -0,0 +1,21 @@
|
||||
package epub
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed "templates/epub_templates_container.xml.tmpl"
|
||||
var containerTmpl string
|
||||
|
||||
//go:embed "templates/epub_templates_applebooks.xml.tmpl"
|
||||
var appleBooksTmpl string
|
||||
|
||||
//go:embed "templates/epub_templates_style.css.tmpl"
|
||||
var styleTmpl string
|
||||
|
||||
//go:embed "templates/epub_templates_title.xhtml.tmpl"
|
||||
var titleTmpl string
|
||||
|
||||
//go:embed "templates/epub_templates_text.xhtml.tmpl"
|
||||
var textTmpl string
|
||||
|
||||
//go:embed "templates/epub_templates_blank.xhtml.tmpl"
|
||||
var blankTmpl string
|
@ -1,56 +0,0 @@
|
||||
package filters
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/disintegration/gift"
|
||||
)
|
||||
|
||||
const (
|
||||
PositionCenter = iota
|
||||
PositionLeft
|
||||
PositionRight
|
||||
)
|
||||
|
||||
func Position(viewWidth, viewHeight int, align int) gift.Filter {
|
||||
return &positionFilter{
|
||||
viewWidth, viewHeight, align,
|
||||
}
|
||||
}
|
||||
|
||||
type positionFilter struct {
|
||||
viewWidth, viewHeight, align int
|
||||
}
|
||||
|
||||
func (p *positionFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
||||
return image.Rect(0, 0, p.viewWidth, p.viewHeight)
|
||||
}
|
||||
|
||||
func (p *positionFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
||||
draw.Draw(dst, dst.Bounds(), image.White, dst.Bounds().Min, draw.Over)
|
||||
|
||||
srcBounds := src.Bounds()
|
||||
left, top := 0, (p.viewHeight-srcBounds.Dy())/2
|
||||
|
||||
if p.align == PositionCenter {
|
||||
left = (p.viewWidth - srcBounds.Dx()) / 2
|
||||
}
|
||||
|
||||
if p.align == PositionRight {
|
||||
left = p.viewWidth - srcBounds.Dx()
|
||||
}
|
||||
|
||||
draw.Draw(
|
||||
dst,
|
||||
image.Rect(
|
||||
left,
|
||||
top,
|
||||
p.viewWidth,
|
||||
p.viewHeight,
|
||||
),
|
||||
src,
|
||||
srcBounds.Min,
|
||||
draw.Over,
|
||||
)
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package epub
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed "templates/container.xml.tmpl"
|
||||
var containerTmpl string
|
||||
|
||||
//go:embed "templates/applebooks.xml.tmpl"
|
||||
var appleBooksTmpl string
|
||||
|
||||
//go:embed "templates/style.css.tmpl"
|
||||
var styleTmpl string
|
||||
|
||||
//go:embed "templates/title.xhtml.tmpl"
|
||||
var titleTmpl string
|
||||
|
||||
//go:embed "templates/text.xhtml.tmpl"
|
||||
var textTmpl string
|
||||
|
||||
//go:embed "templates/blank.xhtml.tmpl"
|
||||
var blankTmpl string
|
@ -2,6 +2,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{{ .Title }}</title>
|
||||
<link href="style.css" type="text/css" rel="stylesheet"/>
|
||||
<meta name="viewport" content="{{ .ViewPort }}"/>
|
@ -1,13 +1,18 @@
|
||||
body {
|
||||
color: #000;
|
||||
background: #FFF;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: {{ .PageWidth }}px;
|
||||
height: {{ .PageHeight }}px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div {
|
||||
img {
|
||||
position: absolute;
|
||||
margin:0;
|
||||
padding:0;
|
||||
z-index:0;
|
||||
}
|
@ -2,13 +2,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{{ .Title }}</title>
|
||||
<link href="style.css" type="text/css" rel="stylesheet"/>
|
||||
<meta name="viewport" content="{{ .ViewPort }}"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<img style="{{ .ImageStyle }}" src="../{{ .ImagePath }}"/>
|
||||
<img src="../{{ .ImagePath }}" alt="{{ .Title }}" style="{{ .ImageStyle }}"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -2,6 +2,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Part {{ .Part }}</title>
|
||||
<link href="style.css" type="text/css" rel="stylesheet"/>
|
||||
<meta name="viewport" content="width={{ .Info.ViewWidth }}, height={{ .Info.ViewHeight }}"/>
|
6
main.go
6
main.go
@ -91,6 +91,8 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
||||
fmt.Fprintln(os.Stderr, cmd.Options)
|
||||
|
||||
profile := cmd.Options.GetProfile()
|
||||
perfectWidth, perfectHeight := profile.PerfectDim()
|
||||
|
||||
if err := epub.NewEpub(&epub.EpubOptions{
|
||||
Input: cmd.Options.Input,
|
||||
Output: cmd.Options.Output,
|
||||
@ -102,8 +104,8 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
||||
DryVerbose: cmd.Options.DryVerbose,
|
||||
SortPathMode: cmd.Options.SortPathMode,
|
||||
ImageOptions: &epub.ImageOptions{
|
||||
ViewWidth: profile.Width,
|
||||
ViewHeight: profile.Height,
|
||||
ViewWidth: perfectWidth,
|
||||
ViewHeight: perfectHeight,
|
||||
Quality: cmd.Options.Quality,
|
||||
Crop: cmd.Options.Crop,
|
||||
Brightness: cmd.Options.Brightness,
|
||||
|
Loading…
x
Reference in New Issue
Block a user