mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-05-23 23:32:38 +02:00
fully workable epub
This commit is contained in:
parent
7d8cbaa1fb
commit
5c44129fe7
7
go.mod
7
go.mod
@ -3,14 +3,9 @@ module go-comic-converter
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/bmaupin/go-epub v1.0.1
|
||||
github.com/gofrs/uuid v3.1.0+incompatible
|
||||
github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50
|
||||
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4
|
||||
golang.org/x/image v0.2.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
)
|
||||
require golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
|
9
go.sum
9
go.sum
@ -1,11 +1,5 @@
|
||||
github.com/bmaupin/go-epub v1.0.1 h1:LLbczYCXO/1sGpFd4/QRaDiEhevo4PYQxBQClZPRoco=
|
||||
github.com/bmaupin/go-epub v1.0.1/go.mod h1:mBan+0WgVv5JbPNw1xfnfQoTRN9iPMKBshZwPOL0SY0=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
github.com/gofrs/uuid v3.1.0+incompatible h1:q2rtkjaKT4YEr6E1kamy0Ha4RtepWlQBedyHx0uzKwA=
|
||||
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50 h1:uxE3GYdXIOfhMv3unJKETJEhw78gvzuQqRX/rVirc2A=
|
||||
github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U=
|
||||
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 h1:0sw0nJM544SpsihWx1bkXdYLQDlzRflMgFJQ4Yih9ts=
|
||||
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
@ -16,14 +10,12 @@ golang.org/x/image v0.2.0/go.mod h1:la7oBXb9w3YFjBqaAwtynVioc1ZvOnNteUNrifGNmAI=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -31,7 +23,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -13,12 +13,14 @@ import (
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/yosssi/gohtml"
|
||||
|
||||
imageconverter "go-comic-converter/internal/image-converter"
|
||||
)
|
||||
|
||||
type Images struct {
|
||||
Id int
|
||||
Title string
|
||||
Data []byte
|
||||
Data string
|
||||
Width int
|
||||
Height int
|
||||
}
|
||||
@ -135,10 +137,15 @@ func (e *EPub) LoadDir(dirname string) *EPub {
|
||||
sort.Strings(images)
|
||||
|
||||
titleFormat := fmt.Sprintf("%%0%dd", len(fmt.Sprint(len(images)-1)))
|
||||
for i := range images {
|
||||
for i, path := range images {
|
||||
fmt.Printf("Processing %d / %d\n", i+1, len(images))
|
||||
data, w, h := imageconverter.Convert(path, true, e.ViewWidth, e.ViewHeight, e.Quality)
|
||||
e.Images = append(e.Images, Images{
|
||||
Id: i,
|
||||
Title: fmt.Sprintf(titleFormat, i),
|
||||
Id: i,
|
||||
Title: fmt.Sprintf(titleFormat, i),
|
||||
Data: data,
|
||||
Width: w,
|
||||
Height: h,
|
||||
})
|
||||
}
|
||||
e.FirstImageTitle = e.Images[0].Title
|
||||
@ -164,8 +171,10 @@ func (e *EPub) Write() error {
|
||||
{"OEBPS/Text/style.css", TEMPLATE_STYLE},
|
||||
}
|
||||
for _, img := range e.Images {
|
||||
filename := fmt.Sprintf("OEBPS/Text/%s.xhtml", img.Title)
|
||||
zipContent = append(zipContent, []string{filename, e.Render(TEMPLATE_TEXT, img)})
|
||||
text := fmt.Sprintf("OEBPS/Text/%s.xhtml", img.Title)
|
||||
image := fmt.Sprintf("OEBPS/Images/%s.jpg", img.Title)
|
||||
zipContent = append(zipContent, []string{text, e.Render(TEMPLATE_TEXT, img)})
|
||||
zipContent = append(zipContent, []string{image, img.Data})
|
||||
}
|
||||
|
||||
wz := zip.NewWriter(w)
|
||||
|
@ -33,7 +33,7 @@
|
||||
<spine page-progression-direction="ltr" toc="ncx">
|
||||
{{ range .Images }}
|
||||
{{ if mod .Id 2 }}
|
||||
<itemref idref="page_{{ .Id }} " linear="yes" properties="page-spread-left"/>
|
||||
<itemref idref="page_{{ .Id }}" linear="yes" properties="page-spread-left"/>
|
||||
{{ else }}
|
||||
<itemref idref="page_{{ .Id }}" linear="yes" properties="page-spread-right"/>
|
||||
{{ end }}
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"image/jpeg"
|
||||
"os"
|
||||
|
||||
"github.com/vincent-petithory/dataurl"
|
||||
"golang.org/x/image/draw"
|
||||
)
|
||||
|
||||
@ -123,8 +122,7 @@ func Get(img *image.Gray, quality int) string {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
du := dataurl.EncodeBytes(b.Bytes())
|
||||
return du
|
||||
return string(b.Bytes())
|
||||
}
|
||||
|
||||
func Save(img *image.Gray, output string, quality int) {
|
||||
@ -144,11 +142,11 @@ func Save(img *image.Gray, output string, quality int) {
|
||||
}
|
||||
}
|
||||
|
||||
func Convert(path string, crop bool, w, h int, quality int) string {
|
||||
func Convert(path string, crop bool, w, h int, quality int) (string, int, int) {
|
||||
img := Load(path)
|
||||
if crop {
|
||||
img = CropMarging(img)
|
||||
}
|
||||
img = Resize(img, w, h)
|
||||
return Get(img, quality)
|
||||
return Get(img, quality), img.Bounds().Dx(), img.Bounds().Dy()
|
||||
}
|
||||
|
182
main.go
182
main.go
@ -1,114 +1,104 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-comic-converter/internal/epub"
|
||||
imageconverter "go-comic-converter/internal/image-converter"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
epub2 "github.com/bmaupin/go-epub"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
Path string
|
||||
Name string
|
||||
Title string
|
||||
Data string
|
||||
InternalPath string
|
||||
}
|
||||
// type File struct {
|
||||
// Path string
|
||||
// Name string
|
||||
// Title string
|
||||
// Data string
|
||||
// InternalPath string
|
||||
// }
|
||||
|
||||
func addImages(doc *epub2.Epub, imagesPath []string) {
|
||||
wg := &sync.WaitGroup{}
|
||||
todos := make(chan string, runtime.NumCPU())
|
||||
imageResult := make(chan *File)
|
||||
// func addImages(doc *epub2.Epub, imagesPath []string) {
|
||||
// wg := &sync.WaitGroup{}
|
||||
// todos := make(chan string, runtime.NumCPU())
|
||||
// imageResult := make(chan *File)
|
||||
|
||||
wg.Add(runtime.NumCPU())
|
||||
for i := 0; i < runtime.NumCPU(); i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for imagePath := range todos {
|
||||
name := filepath.Base(imagePath)
|
||||
ext := filepath.Ext(name)
|
||||
title := name[0 : len(name)-len(ext)]
|
||||
imageResult <- &File{
|
||||
Path: imagePath,
|
||||
Name: name,
|
||||
Title: title,
|
||||
Data: imageconverter.Convert(imagePath, true, 1860, 2480, 75),
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
go func() {
|
||||
for _, imagePath := range imagesPath {
|
||||
todos <- imagePath
|
||||
}
|
||||
close(todos)
|
||||
wg.Wait()
|
||||
close(imageResult)
|
||||
}()
|
||||
// wg.Add(runtime.NumCPU())
|
||||
// for i := 0; i < runtime.NumCPU(); i++ {
|
||||
// go func() {
|
||||
// defer wg.Done()
|
||||
// for imagePath := range todos {
|
||||
// name := filepath.Base(imagePath)
|
||||
// ext := filepath.Ext(name)
|
||||
// title := name[0 : len(name)-len(ext)]
|
||||
// imageResult <- &File{
|
||||
// Path: imagePath,
|
||||
// Name: name,
|
||||
// Title: title,
|
||||
// Data: imageconverter.Convert(imagePath, true, 1860, 2480, 75),
|
||||
// }
|
||||
// }
|
||||
// }()
|
||||
// }
|
||||
// go func() {
|
||||
// for _, imagePath := range imagesPath {
|
||||
// todos <- imagePath
|
||||
// }
|
||||
// close(todos)
|
||||
// wg.Wait()
|
||||
// close(imageResult)
|
||||
// }()
|
||||
|
||||
results := make([]*File, 0)
|
||||
for result := range imageResult {
|
||||
fmt.Println(result.Name)
|
||||
internalPath, _ := doc.AddImage(result.Data, result.Name)
|
||||
result.InternalPath = internalPath
|
||||
results = append(results, result)
|
||||
}
|
||||
sort.SliceStable(results, func(i, j int) bool {
|
||||
return strings.Compare(
|
||||
results[i].Path, results[j].Path,
|
||||
) < 0
|
||||
})
|
||||
for i, result := range results {
|
||||
if i == 0 {
|
||||
doc.SetCover(result.InternalPath, "")
|
||||
} else {
|
||||
doc.AddSection(
|
||||
fmt.Sprintf("<img src=\"%s\" />", result.InternalPath),
|
||||
result.Title,
|
||||
fmt.Sprintf("%s.xhtml", result.Title),
|
||||
"../css/cover.css",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// results := make([]*File, 0)
|
||||
// for result := range imageResult {
|
||||
// fmt.Println(result.Name)
|
||||
// internalPath, _ := doc.AddImage(result.Data, result.Name)
|
||||
// result.InternalPath = internalPath
|
||||
// results = append(results, result)
|
||||
// }
|
||||
// sort.SliceStable(results, func(i, j int) bool {
|
||||
// return strings.Compare(
|
||||
// results[i].Path, results[j].Path,
|
||||
// ) < 0
|
||||
// })
|
||||
// for i, result := range results {
|
||||
// if i == 0 {
|
||||
// doc.SetCover(result.InternalPath, "")
|
||||
// } else {
|
||||
// doc.AddSection(
|
||||
// fmt.Sprintf("<img src=\"%s\" />", result.InternalPath),
|
||||
// result.Title,
|
||||
// fmt.Sprintf("%s.xhtml", result.Title),
|
||||
// "../css/cover.css",
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func getImages(dirname string) []string {
|
||||
images := make([]string, 0)
|
||||
filepath.WalkDir(dirname, func(path string, d fs.DirEntry, err error) error {
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
ext := filepath.Ext(path)
|
||||
if strings.ToLower(ext) != ".jpg" {
|
||||
return nil
|
||||
}
|
||||
images = append(images, path)
|
||||
return nil
|
||||
})
|
||||
sort.Strings(images)
|
||||
return images
|
||||
}
|
||||
// func getImages(dirname string) []string {
|
||||
// images := make([]string, 0)
|
||||
// filepath.WalkDir(dirname, func(path string, d fs.DirEntry, err error) error {
|
||||
// if d.IsDir() {
|
||||
// return nil
|
||||
// }
|
||||
// ext := filepath.Ext(path)
|
||||
// if strings.ToLower(ext) != ".jpg" {
|
||||
// return nil
|
||||
// }
|
||||
// images = append(images, path)
|
||||
// return nil
|
||||
// })
|
||||
// sort.Strings(images)
|
||||
// return images
|
||||
// }
|
||||
|
||||
func main2() {
|
||||
imagesPath := getImages("/Users/vincent/Downloads/Bleach T01 (Tite KUBO) [eBook officiel 1920]")
|
||||
// func main2() {
|
||||
// imagesPath := getImages("/Users/vincent/Downloads/Bleach T01 (Tite KUBO) [eBook officiel 1920]")
|
||||
|
||||
doc := epub2.NewEpub("Bleach T01 (Tite KUBO) [eBook officiel 1920]")
|
||||
doc.SetAuthor("Bachelier Vincent")
|
||||
// doc := epub2.NewEpub("Bleach T01 (Tite KUBO) [eBook officiel 1920]")
|
||||
// doc.SetAuthor("Bachelier Vincent")
|
||||
|
||||
addImages(doc, imagesPath)
|
||||
// addImages(doc, imagesPath)
|
||||
|
||||
if err := doc.Write("/Users/vincent/Downloads/test.epub"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// if err := doc.Write("/Users/vincent/Downloads/test.epub"); err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
func main() {
|
||||
err := epub.NewEpub("/Users/vincent/Downloads/test.epub").
|
||||
|
Loading…
x
Reference in New Issue
Block a user