mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-26 00:32:37 +02:00
Compare commits
6 Commits
3f874dc43e
...
abf3b8facf
Author | SHA1 | Date | |
---|---|---|---|
abf3b8facf | |||
728129aba2 | |||
a816350c97 | |||
58cd5f5399 | |||
ee00ed2615 | |||
13103b0eba |
@ -110,7 +110,6 @@ func (c *Converter) InitParse() {
|
|||||||
c.AddIntParam(&c.Options.Brightness, "brightness", c.Options.Brightness, "Brightness readjustement: between -100 and 100, > 0 lighter, < 0 darker")
|
c.AddIntParam(&c.Options.Brightness, "brightness", c.Options.Brightness, "Brightness readjustement: between -100 and 100, > 0 lighter, < 0 darker")
|
||||||
c.AddIntParam(&c.Options.Contrast, "contrast", c.Options.Contrast, "Contrast readjustement: between -100 and 100, > 0 more contrast, < 0 less contrast")
|
c.AddIntParam(&c.Options.Contrast, "contrast", c.Options.Contrast, "Contrast readjustement: between -100 and 100, > 0 more contrast, < 0 less contrast")
|
||||||
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.Auto, "auto", false, "Activate all automatic options")
|
|
||||||
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.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)")
|
||||||
@ -120,12 +119,22 @@ func (c *Converter) InitParse() {
|
|||||||
c.AddIntParam(&c.Options.SortPathMode, "sort", c.Options.SortPathMode, "Sort path mode\n0 = alpha for path and file\n1 = alphanum for path and alpha for file\n2 = alphanum for path and file")
|
c.AddIntParam(&c.Options.SortPathMode, "sort", c.Options.SortPathMode, "Sort path mode\n0 = alpha for path and file\n1 = alphanum for path and alpha for file\n2 = alphanum for path and file")
|
||||||
c.AddStringParam(&c.Options.ForegroundColor, "foreground-color", c.Options.ForegroundColor, "Foreground color in hexa format RGB. Black=000, White=FFF")
|
c.AddStringParam(&c.Options.ForegroundColor, "foreground-color", c.Options.ForegroundColor, "Foreground color in hexa format RGB. Black=000, White=FFF")
|
||||||
c.AddStringParam(&c.Options.BackgroundColor, "background-color", c.Options.BackgroundColor, "Background color in hexa format RGB. Black=000, White=FFF, Light Gray=DDD, Dark Gray=777")
|
c.AddStringParam(&c.Options.BackgroundColor, "background-color", c.Options.BackgroundColor, "Background color in hexa format RGB. Black=000, White=FFF, Light Gray=DDD, Dark Gray=777")
|
||||||
|
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.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")
|
||||||
c.AddBoolParam(&c.Options.Save, "save", false, "Save your parameters as default")
|
c.AddBoolParam(&c.Options.Save, "save", false, "Save your parameters as default")
|
||||||
c.AddBoolParam(&c.Options.Reset, "reset", false, "Reset your parameters to default")
|
c.AddBoolParam(&c.Options.Reset, "reset", false, "Reset your parameters to default")
|
||||||
|
|
||||||
|
c.AddSection("Shortcut")
|
||||||
|
c.AddBoolParam(&c.Options.Auto, "auto", false, "Activate all automatic options")
|
||||||
|
c.AddBoolParam(&c.Options.NoFilter, "nofilter", false, "Deactivate all filters")
|
||||||
|
c.AddBoolParam(&c.Options.MaxQuality, "maxquality", false, "Max quality: color png + noresize")
|
||||||
|
c.AddBoolParam(&c.Options.BestQuality, "bestquality", false, "Max quality: color jpg q100 + noresize")
|
||||||
|
c.AddBoolParam(&c.Options.GreatQuality, "greatquality", false, "Max quality: grayscale jpg q90 + noresize")
|
||||||
|
c.AddBoolParam(&c.Options.GoodQuality, "goodquality", false, "Max quality: grayscale jpg q90")
|
||||||
|
|
||||||
c.AddSection("Other")
|
c.AddSection("Other")
|
||||||
c.AddIntParam(&c.Options.Workers, "workers", runtime.NumCPU(), "Number of workers")
|
c.AddIntParam(&c.Options.Workers, "workers", runtime.NumCPU(), "Number of workers")
|
||||||
c.AddBoolParam(&c.Options.Dry, "dry", false, "Dry run to show all options")
|
c.AddBoolParam(&c.Options.Dry, "dry", false, "Dry run to show all options")
|
||||||
@ -211,6 +220,36 @@ func (c *Converter) Parse() {
|
|||||||
c.Options.AutoRotate = true
|
c.Options.AutoRotate = true
|
||||||
c.Options.AutoSplitDoublePage = true
|
c.Options.AutoSplitDoublePage = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Options.MaxQuality {
|
||||||
|
c.Options.Format = "png"
|
||||||
|
c.Options.Grayscale = false
|
||||||
|
c.Options.NoResize = true
|
||||||
|
} else if c.Options.BestQuality {
|
||||||
|
c.Options.Format = "jpeg"
|
||||||
|
c.Options.Quality = 100
|
||||||
|
c.Options.Grayscale = false
|
||||||
|
c.Options.NoResize = true
|
||||||
|
} else if c.Options.GreatQuality {
|
||||||
|
c.Options.Format = "jpeg"
|
||||||
|
c.Options.Quality = 90
|
||||||
|
c.Options.Grayscale = true
|
||||||
|
c.Options.NoResize = true
|
||||||
|
} else if c.Options.GoodQuality {
|
||||||
|
c.Options.Format = "jpeg"
|
||||||
|
c.Options.Quality = 90
|
||||||
|
c.Options.Grayscale = true
|
||||||
|
c.Options.NoResize = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Options.NoFilter {
|
||||||
|
c.Options.Crop = false
|
||||||
|
c.Options.Brightness = 0
|
||||||
|
c.Options.Contrast = 0
|
||||||
|
c.Options.AutoRotate = false
|
||||||
|
c.Options.NoBlankImage = false
|
||||||
|
c.Options.NoResize = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check parameters
|
// Check parameters
|
||||||
@ -307,6 +346,11 @@ func (c *Converter) Validate() error {
|
|||||||
return errors.New("background color must have color format in hexa: [0-9A-F]{3}")
|
return errors.New("background color must have color format in hexa: [0-9A-F]{3}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format
|
||||||
|
if !(c.Options.Format == "jpeg" || c.Options.Format == "png") {
|
||||||
|
return errors.New("format should be jpeg or png")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ type Options struct {
|
|||||||
CropRatioBottom int `yaml:"crop_ratio_bottom"`
|
CropRatioBottom int `yaml:"crop_ratio_bottom"`
|
||||||
Brightness int `yaml:"brightness"`
|
Brightness int `yaml:"brightness"`
|
||||||
Contrast int `yaml:"contrast"`
|
Contrast int `yaml:"contrast"`
|
||||||
Auto bool `yaml:"-"`
|
|
||||||
AutoRotate bool `yaml:"auto_rotate"`
|
AutoRotate bool `yaml:"auto_rotate"`
|
||||||
AutoSplitDoublePage bool `yaml:"auto_split_double_page"`
|
AutoSplitDoublePage bool `yaml:"auto_split_double_page"`
|
||||||
NoBlankImage bool `yaml:"no_blank_image"`
|
NoBlankImage bool `yaml:"no_blank_image"`
|
||||||
@ -42,12 +41,22 @@ type Options struct {
|
|||||||
SortPathMode int `yaml:"sort_path_mode"`
|
SortPathMode int `yaml:"sort_path_mode"`
|
||||||
ForegroundColor string `yaml:"foreground_color"`
|
ForegroundColor string `yaml:"foreground_color"`
|
||||||
BackgroundColor string `yaml:"background_color"`
|
BackgroundColor string `yaml:"background_color"`
|
||||||
|
NoResize bool `yaml:"noresize"`
|
||||||
|
Format string `yaml:"format"`
|
||||||
|
|
||||||
// Default Config
|
// Default Config
|
||||||
Show bool `yaml:"-"`
|
Show bool `yaml:"-"`
|
||||||
Save bool `yaml:"-"`
|
Save bool `yaml:"-"`
|
||||||
Reset bool `yaml:"-"`
|
Reset bool `yaml:"-"`
|
||||||
|
|
||||||
|
// Shortcut
|
||||||
|
Auto bool `yaml:"-"`
|
||||||
|
NoFilter bool `yaml:"-"`
|
||||||
|
MaxQuality bool `yaml:"-"`
|
||||||
|
BestQuality bool `yaml:"-"`
|
||||||
|
GreatQuality bool `yaml:"-"`
|
||||||
|
GoodQuality bool `yaml:"-"`
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
Workers int `yaml:"-"`
|
Workers int `yaml:"-"`
|
||||||
Dry bool `yaml:"-"`
|
Dry bool `yaml:"-"`
|
||||||
@ -83,6 +92,8 @@ func New() *Options {
|
|||||||
SortPathMode: 1,
|
SortPathMode: 1,
|
||||||
ForegroundColor: "000",
|
ForegroundColor: "000",
|
||||||
BackgroundColor: "FFF",
|
BackgroundColor: "FFF",
|
||||||
|
NoResize: false,
|
||||||
|
Format: "jpeg",
|
||||||
profiles: profiles.New(),
|
profiles: profiles.New(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,10 +163,6 @@ func (o *Options) ShowConfig() string {
|
|||||||
perfectHeight,
|
perfectHeight,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
limitmb := "nolimit"
|
|
||||||
if o.LimitMb > 0 {
|
|
||||||
limitmb = fmt.Sprintf("%d Mb", o.LimitMb)
|
|
||||||
}
|
|
||||||
|
|
||||||
sortpathmode := ""
|
sortpathmode := ""
|
||||||
switch o.SortPathMode {
|
switch o.SortPathMode {
|
||||||
@ -169,30 +176,35 @@ func (o *Options) ShowConfig() string {
|
|||||||
|
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
for _, v := range []struct {
|
for _, v := range []struct {
|
||||||
K string
|
Key string
|
||||||
V any
|
Value any
|
||||||
|
Condition bool
|
||||||
}{
|
}{
|
||||||
{"Profile", profileDesc},
|
{"Profile", profileDesc, true},
|
||||||
{"ViewRatio", fmt.Sprintf("1:%s", strings.TrimRight(fmt.Sprintf("%f", profiles.PerfectRatio), "0"))},
|
{"ViewRatio", fmt.Sprintf("1:%s", strings.TrimRight(fmt.Sprintf("%f", profiles.PerfectRatio), "0")), true},
|
||||||
{"View", viewDesc},
|
{"View", viewDesc, true},
|
||||||
{"Quality", o.Quality},
|
{"Format", o.Format, true},
|
||||||
{"Grayscale", o.Grayscale},
|
{"Quality", o.Quality, o.Format == "jpeg"},
|
||||||
{"Crop", o.Crop},
|
{"Grayscale", o.Grayscale, true},
|
||||||
{"CropRatio", fmt.Sprintf("%d Left - %d Up - %d Right - %d Bottom", o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom)},
|
{"Crop", o.Crop, true},
|
||||||
{"Brightness", o.Brightness},
|
{"CropRatio", fmt.Sprintf("%d Left - %d Up - %d Right - %d Bottom", o.CropRatioLeft, o.CropRatioUp, o.CropRatioRight, o.CropRatioBottom), o.Crop},
|
||||||
{"Contrast", o.Contrast},
|
{"Brightness", o.Brightness, o.Brightness != 0},
|
||||||
{"AutoRotate", o.AutoRotate},
|
{"Contrast", o.Contrast, o.Contrast != 0},
|
||||||
{"AutoSplitDoublePage", o.AutoSplitDoublePage},
|
{"AutoRotate", o.AutoRotate, true},
|
||||||
{"NoBlankImage", o.NoBlankImage},
|
{"AutoSplitDoublePage", o.AutoSplitDoublePage, true},
|
||||||
{"Manga", o.Manga},
|
{"NoBlankImage", o.NoBlankImage, true},
|
||||||
{"HasCover", o.HasCover},
|
{"Manga", o.Manga, true},
|
||||||
{"LimitMb", limitmb},
|
{"HasCover", o.HasCover, true},
|
||||||
{"StripFirstDirectoryFromToc", o.StripFirstDirectoryFromToc},
|
{"LimitMb", fmt.Sprintf("%d Mb", o.LimitMb), o.LimitMb != 0},
|
||||||
{"SortPathMode", sortpathmode},
|
{"StripFirstDirectoryFromToc", o.StripFirstDirectoryFromToc, true},
|
||||||
{"Foreground Color", fmt.Sprintf("#%s", o.ForegroundColor)},
|
{"SortPathMode", sortpathmode, true},
|
||||||
{"Background Color", fmt.Sprintf("#%s", o.BackgroundColor)},
|
{"Foreground Color", fmt.Sprintf("#%s", o.ForegroundColor), true},
|
||||||
|
{"Background Color", fmt.Sprintf("#%s", o.BackgroundColor), true},
|
||||||
|
{"Resize", !o.NoResize, true},
|
||||||
} {
|
} {
|
||||||
b.WriteString(fmt.Sprintf("\n %-26s: %v", v.K, v.V))
|
if v.Condition {
|
||||||
|
b.WriteString(fmt.Sprintf("\n %-26s: %v", v.Key, v.Value))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ func (e *ePub) Write() error {
|
|||||||
{"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),
|
||||||
"ImagePath": "Images/title.jpg",
|
"ImagePath": fmt.Sprintf("Images/title.%s", e.Image.Format),
|
||||||
"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),
|
||||||
})},
|
})},
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package epubimage
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Image struct {
|
type Image struct {
|
||||||
@ -20,6 +21,7 @@ type Image struct {
|
|||||||
Path string
|
Path string
|
||||||
Name string
|
Name string
|
||||||
Position string
|
Position string
|
||||||
|
Format string
|
||||||
}
|
}
|
||||||
|
|
||||||
// key name of the blank plage after the image
|
// key name of the blank plage after the image
|
||||||
@ -59,7 +61,7 @@ func (i *Image) ImgKey() string {
|
|||||||
|
|
||||||
// image path
|
// image path
|
||||||
func (i *Image) ImgPath() string {
|
func (i *Image) ImgPath() string {
|
||||||
return fmt.Sprintf("Images/%s.jpg", i.ImgKey())
|
return fmt.Sprintf("Images/%s.%s", i.ImgKey(), i.Format)
|
||||||
}
|
}
|
||||||
|
|
||||||
// image path into the EPUB
|
// image path into the EPUB
|
||||||
@ -72,24 +74,48 @@ func (i *Image) EPUBImgPath() string {
|
|||||||
// center by default.
|
// center by default.
|
||||||
// align to left or right if it's part of the splitted double page.
|
// align to left or right if it's part of the splitted double page.
|
||||||
func (i *Image) ImgStyle(viewWidth, viewHeight int, align string) string {
|
func (i *Image) ImgStyle(viewWidth, viewHeight int, align string) string {
|
||||||
marginW, marginH := float64(viewWidth-i.Width)/2, float64(viewHeight-i.Height)/2
|
relWidth, relHeight := i.RelSize(viewWidth, viewHeight)
|
||||||
|
marginW, marginH := float64(viewWidth-relWidth)/2, float64(viewHeight-relHeight)/2
|
||||||
|
|
||||||
|
style := []string{}
|
||||||
|
|
||||||
|
style = append(style, fmt.Sprintf("width:%dpx", relWidth))
|
||||||
|
style = append(style, fmt.Sprintf("height:%dpx", relHeight))
|
||||||
|
style = append(style, fmt.Sprintf("top:%.2f%%", marginH*100/float64(viewHeight)))
|
||||||
if align == "" {
|
if align == "" {
|
||||||
switch i.Position {
|
switch i.Position {
|
||||||
case "rendition:page-spread-left":
|
case "rendition:page-spread-left":
|
||||||
align = "right:0"
|
style = append(style, "right:0")
|
||||||
case "rendition:page-spread-right":
|
case "rendition:page-spread-right":
|
||||||
align = "left:0"
|
style = append(style, "left:0")
|
||||||
default:
|
default:
|
||||||
align = fmt.Sprintf("left:%.2f%%", marginW*100/float64(viewWidth))
|
style = append(style, fmt.Sprintf("left:%.2f%%", marginW*100/float64(viewWidth)))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
style = append(style, align)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return strings.Join(style, "; ")
|
||||||
"width:%dpx; height:%dpx; top:%.2f%%; %s;",
|
}
|
||||||
i.Width,
|
|
||||||
i.Height,
|
func (i *Image) RelSize(viewWidth, viewHeight int) (relWidth, relHeight int) {
|
||||||
marginH*100/float64(viewHeight),
|
w, h := viewWidth, viewHeight
|
||||||
align,
|
srcw, srch := i.Width, i.Height
|
||||||
)
|
|
||||||
|
if w <= 0 || h <= 0 || srcw <= 0 || srch <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wratio := float64(srcw) / float64(w)
|
||||||
|
hratio := float64(srch) / float64(h)
|
||||||
|
|
||||||
|
if wratio > hratio {
|
||||||
|
relWidth = w
|
||||||
|
relHeight = int(float64(srch)/wratio + 0.5)
|
||||||
|
} else {
|
||||||
|
relHeight = h
|
||||||
|
relWidth = int(float64(srcw)/hratio + 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package epubimagefilters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image"
|
|
||||||
"image/draw"
|
|
||||||
|
|
||||||
"github.com/disintegration/gift"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Resize image by keeping aspect ratio.
|
|
||||||
// This will reduce or enlarge image to fit into the viewWidth and viewHeight.
|
|
||||||
func Resize(viewWidth, viewHeight int, resampling gift.Resampling) gift.Filter {
|
|
||||||
return &resizeFilter{
|
|
||||||
viewWidth, viewHeight, resampling,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type resizeFilter struct {
|
|
||||||
viewWidth, viewHeight int
|
|
||||||
resampling gift.Resampling
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *resizeFilter) Bounds(srcBounds image.Rectangle) image.Rectangle {
|
|
||||||
w, h := p.viewWidth, p.viewHeight
|
|
||||||
srcw, srch := srcBounds.Dx(), srcBounds.Dy()
|
|
||||||
|
|
||||||
if w <= 0 || h <= 0 || srcw <= 0 || srch <= 0 {
|
|
||||||
return image.Rect(0, 0, 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
wratio := float64(srcw) / float64(w)
|
|
||||||
hratio := float64(srch) / float64(h)
|
|
||||||
|
|
||||||
var dstw, dsth int
|
|
||||||
if wratio > hratio {
|
|
||||||
dstw = w
|
|
||||||
dsth = int(float64(srch)/wratio + 0.5)
|
|
||||||
} else {
|
|
||||||
dsth = h
|
|
||||||
dstw = int(float64(srcw)/hratio + 0.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
return image.Rect(0, 0, dstw, dsth)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *resizeFilter) Draw(dst draw.Image, src image.Image, options *gift.Options) {
|
|
||||||
gift.Resize(dst.Bounds().Dx(), dst.Bounds().Dy(), p.resampling).Draw(dst, src, options)
|
|
||||||
}
|
|
@ -38,9 +38,10 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
|
|||||||
if e.Dry {
|
if e.Dry {
|
||||||
for img := range imageInput {
|
for img := range imageInput {
|
||||||
images = append(images, &epubimage.Image{
|
images = append(images, &epubimage.Image{
|
||||||
Id: img.Id,
|
Id: img.Id,
|
||||||
Path: img.Path,
|
Path: img.Path,
|
||||||
Name: img.Name,
|
Name: img.Name,
|
||||||
|
Format: e.Image.Format,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,13 +60,17 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
|
|||||||
})
|
})
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
imgStorage, err := epubzip.NewEPUBZipStorageImageWriter(e.ImgStorage())
|
imgStorage, err := epubzip.NewEPUBZipStorageImageWriter(e.ImgStorage(), e.Image.Format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bar.Close()
|
bar.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < e.WorkersRatio(50); i++ {
|
wr := 50
|
||||||
|
if e.Image.Format == "png" {
|
||||||
|
wr = 100
|
||||||
|
}
|
||||||
|
for i := 0; i < e.WorkersRatio(wr); i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
@ -90,6 +95,7 @@ func (e *EPUBImageProcessor) Load() (images []*epubimage.Image, err error) {
|
|||||||
DoublePage: part == 0 && src.Bounds().Dx() > src.Bounds().Dy(),
|
DoublePage: part == 0 && src.Bounds().Dx() > src.Bounds().Dy(),
|
||||||
Path: input.Path,
|
Path: input.Path,
|
||||||
Name: input.Name,
|
Name: input.Name,
|
||||||
|
Format: e.Image.Format,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = imgStorage.Add(img.EPUBImgPath(), dst, e.Image.Quality); err != nil {
|
if err = imgStorage.Add(img.EPUBImgPath(), dst, e.Image.Quality); err != nil {
|
||||||
@ -201,10 +207,12 @@ func (e *EPUBImageProcessor) transformImage(src image.Image, srcId int) []image.
|
|||||||
splitFilter = append(splitFilter, f)
|
splitFilter = append(splitFilter, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
filters = append(filters,
|
if e.Image.Resize {
|
||||||
epubimagefilters.Resize(e.Image.View.Width, e.Image.View.Height, gift.LanczosResampling),
|
f := gift.ResizeToFit(e.Image.View.Width, e.Image.View.Height, gift.LanczosResampling)
|
||||||
epubimagefilters.Pixel(),
|
filters = append(filters, f)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
filters = append(filters, epubimagefilters.Pixel())
|
||||||
|
|
||||||
// convert
|
// convert
|
||||||
{
|
{
|
||||||
@ -232,10 +240,10 @@ func (e *EPUBImageProcessor) transformImage(src image.Image, srcId int) []image.
|
|||||||
// convert double page
|
// convert double page
|
||||||
for _, b := range []bool{e.Image.Manga, !e.Image.Manga} {
|
for _, b := range []bool{e.Image.Manga, !e.Image.Manga} {
|
||||||
g := gift.New(splitFilter...)
|
g := gift.New(splitFilter...)
|
||||||
g.Add(
|
g.Add(epubimagefilters.CropSplitDoublePage(b))
|
||||||
epubimagefilters.CropSplitDoublePage(b),
|
if e.Image.Resize {
|
||||||
epubimagefilters.Resize(e.Image.View.Width, e.Image.View.Height, gift.LanczosResampling),
|
g.Add(gift.ResizeToFit(e.Image.View.Width, e.Image.View.Height, gift.LanczosResampling))
|
||||||
)
|
}
|
||||||
dst := e.createImage(src, g.Bounds(src.Bounds()))
|
dst := e.createImage(src, g.Bounds(src.Bounds()))
|
||||||
g.Draw(dst, src)
|
g.Draw(dst, src)
|
||||||
images = append(images, dst)
|
images = append(images, dst)
|
||||||
@ -251,5 +259,10 @@ func (e *EPUBImageProcessor) CoverTitleData(src image.Image, title string) (*epu
|
|||||||
dst := e.createImage(src, g.Bounds(src.Bounds()))
|
dst := e.createImage(src, g.Bounds(src.Bounds()))
|
||||||
g.Draw(dst, src)
|
g.Draw(dst, src)
|
||||||
|
|
||||||
return epubzip.CompressImage("OEBPS/Images/title.jpg", dst, e.Image.Quality)
|
return epubzip.CompressImage(
|
||||||
|
fmt.Sprintf("OEBPS/Images/title.%s", e.Image.Format),
|
||||||
|
e.Image.Format,
|
||||||
|
dst,
|
||||||
|
e.Image.Quality,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,8 @@ type Image struct {
|
|||||||
HasCover bool
|
HasCover bool
|
||||||
View *View
|
View *View
|
||||||
GrayScale bool
|
GrayScale bool
|
||||||
|
Resize bool
|
||||||
|
Format string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
@ -127,7 +127,7 @@ func getManifest(o *ContentOptions) []tag {
|
|||||||
var imageTags, pageTags, spaceTags []tag
|
var imageTags, pageTags, spaceTags []tag
|
||||||
addTag := func(img *epubimage.Image, withSpace bool) {
|
addTag := func(img *epubimage.Image, withSpace bool) {
|
||||||
imageTags = append(imageTags,
|
imageTags = append(imageTags,
|
||||||
tag{"item", tagAttrs{"id": img.ImgKey(), "href": img.ImgPath(), "media-type": "image/jpeg"}, ""},
|
tag{"item", tagAttrs{"id": img.ImgKey(), "href": img.ImgPath(), "media-type": fmt.Sprintf("image/%s", o.ImageOptions.Format)}, ""},
|
||||||
)
|
)
|
||||||
pageTags = append(pageTags,
|
pageTags = append(pageTags,
|
||||||
tag{"item", tagAttrs{"id": img.PageKey(), "href": img.PagePath(), "media-type": "application/xhtml+xml"}, ""},
|
tag{"item", tagAttrs{"id": img.PageKey(), "href": img.PagePath(), "media-type": "application/xhtml+xml"}, ""},
|
||||||
@ -144,7 +144,7 @@ func getManifest(o *ContentOptions) []tag {
|
|||||||
{"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": "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": "Images/title.jpg", "media-type": "image/jpeg"}, ""},
|
{"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.HasCover || o.Current > 1 {
|
if o.ImageOptions.HasCover || o.Current > 1 {
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
<meta name="viewport" content="{{ .ViewPort }}"/>
|
<meta name="viewport" content="{{ .ViewPort }}"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<img src="../{{ .ImagePath }}" alt="{{ .Title }}" style="{{ .ImageStyle }}"/>
|
||||||
<img src="../{{ .ImagePath }}" alt="{{ .Title }}" style="{{ .ImageStyle }}"/>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -4,9 +4,11 @@ import (
|
|||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/flate"
|
"compress/flate"
|
||||||
|
"fmt"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"image"
|
"image"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,13 +18,20 @@ type ZipImage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create gzip encoded jpeg
|
// create gzip encoded jpeg
|
||||||
func CompressImage(filename string, img image.Image, quality int) (*ZipImage, error) {
|
func CompressImage(filename string, format string, img image.Image, quality int) (*ZipImage, error) {
|
||||||
var (
|
var (
|
||||||
data, cdata bytes.Buffer
|
data, cdata bytes.Buffer
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
err = jpeg.Encode(&data, img, &jpeg.Options{Quality: quality})
|
switch format {
|
||||||
|
case "png":
|
||||||
|
err = png.Encode(&data, img)
|
||||||
|
case "jpeg":
|
||||||
|
err = jpeg.Encode(&data, img, &jpeg.Options{Quality: quality})
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unknown format %q", format)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type EPUBZipStorageImageWriter struct {
|
type EPUBZipStorageImageWriter struct {
|
||||||
fh *os.File
|
fh *os.File
|
||||||
fz *zip.Writer
|
fz *zip.Writer
|
||||||
|
format string
|
||||||
mut *sync.Mutex
|
mut *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEPUBZipStorageImageWriter(filename string) (*EPUBZipStorageImageWriter, error) {
|
func NewEPUBZipStorageImageWriter(filename string, format string) (*EPUBZipStorageImageWriter, error) {
|
||||||
fh, err := os.Create(filename)
|
fh, err := os.Create(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fz := zip.NewWriter(fh)
|
fz := zip.NewWriter(fh)
|
||||||
return &EPUBZipStorageImageWriter{fh, fz, &sync.Mutex{}}, nil
|
return &EPUBZipStorageImageWriter{fh, fz, format, &sync.Mutex{}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EPUBZipStorageImageWriter) Close() error {
|
func (e *EPUBZipStorageImageWriter) Close() error {
|
||||||
@ -32,7 +32,7 @@ func (e *EPUBZipStorageImageWriter) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *EPUBZipStorageImageWriter) Add(filename string, img image.Image, quality int) error {
|
func (e *EPUBZipStorageImageWriter) Add(filename string, img image.Image, quality int) error {
|
||||||
zipImage, err := CompressImage(filename, img, quality)
|
zipImage, err := CompressImage(filename, e.format, img, quality)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
2
main.go
2
main.go
@ -138,6 +138,8 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
|
|||||||
Background: cmd.Options.BackgroundColor,
|
Background: cmd.Options.BackgroundColor,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Resize: !cmd.Options.NoResize,
|
||||||
|
Format: cmd.Options.Format,
|
||||||
},
|
},
|
||||||
}).Write(); err != nil {
|
}).Write(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user