fully workable epub

This commit is contained in:
Celogeek 2022-12-26 20:39:06 +01:00
parent 7d8cbaa1fb
commit 5c44129fe7
Signed by: celogeek
GPG Key ID: E6B7BDCFC446233A
6 changed files with 106 additions and 123 deletions

7
go.mod
View File

@ -3,14 +3,9 @@ module go-comic-converter
go 1.19 go 1.19
require ( require (
github.com/bmaupin/go-epub v1.0.1
github.com/gofrs/uuid v3.1.0+incompatible 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 github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4
golang.org/x/image v0.2.0 golang.org/x/image v0.2.0
) )
require ( require golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
github.com/gabriel-vasile/mimetype v1.3.1 // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
)

9
go.sum
View File

@ -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 h1:q2rtkjaKT4YEr6E1kamy0Ha4RtepWlQBedyHx0uzKwA=
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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 h1:0sw0nJM544SpsihWx1bkXdYLQDlzRflMgFJQ4Yih9ts=
github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE= 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= 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/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-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-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 h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 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-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/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-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-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-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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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/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.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.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.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/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -13,12 +13,14 @@ import (
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
"github.com/yosssi/gohtml" "github.com/yosssi/gohtml"
imageconverter "go-comic-converter/internal/image-converter"
) )
type Images struct { type Images struct {
Id int Id int
Title string Title string
Data []byte Data string
Width int Width int
Height int Height int
} }
@ -135,10 +137,15 @@ func (e *EPub) LoadDir(dirname string) *EPub {
sort.Strings(images) sort.Strings(images)
titleFormat := fmt.Sprintf("%%0%dd", len(fmt.Sprint(len(images)-1))) 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{ e.Images = append(e.Images, Images{
Id: i, Id: i,
Title: fmt.Sprintf(titleFormat, i), Title: fmt.Sprintf(titleFormat, i),
Data: data,
Width: w,
Height: h,
}) })
} }
e.FirstImageTitle = e.Images[0].Title e.FirstImageTitle = e.Images[0].Title
@ -164,8 +171,10 @@ func (e *EPub) Write() error {
{"OEBPS/Text/style.css", TEMPLATE_STYLE}, {"OEBPS/Text/style.css", TEMPLATE_STYLE},
} }
for _, img := range e.Images { for _, img := range e.Images {
filename := fmt.Sprintf("OEBPS/Text/%s.xhtml", img.Title) text := fmt.Sprintf("OEBPS/Text/%s.xhtml", img.Title)
zipContent = append(zipContent, []string{filename, e.Render(TEMPLATE_TEXT, img)}) 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) wz := zip.NewWriter(w)

View File

@ -7,7 +7,6 @@ import (
"image/jpeg" "image/jpeg"
"os" "os"
"github.com/vincent-petithory/dataurl"
"golang.org/x/image/draw" "golang.org/x/image/draw"
) )
@ -123,8 +122,7 @@ func Get(img *image.Gray, quality int) string {
if err != nil { if err != nil {
panic(err) panic(err)
} }
du := dataurl.EncodeBytes(b.Bytes()) return string(b.Bytes())
return du
} }
func Save(img *image.Gray, output string, quality int) { 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) img := Load(path)
if crop { if crop {
img = CropMarging(img) img = CropMarging(img)
} }
img = Resize(img, w, h) img = Resize(img, w, h)
return Get(img, quality) return Get(img, quality), img.Bounds().Dx(), img.Bounds().Dy()
} }

182
main.go
View File

@ -1,114 +1,104 @@
package main package main
import ( import (
"fmt"
"go-comic-converter/internal/epub" "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 { // type File struct {
Path string // Path string
Name string // Name string
Title string // Title string
Data string // Data string
InternalPath string // InternalPath string
} // }
func addImages(doc *epub2.Epub, imagesPath []string) { // func addImages(doc *epub2.Epub, imagesPath []string) {
wg := &sync.WaitGroup{} // wg := &sync.WaitGroup{}
todos := make(chan string, runtime.NumCPU()) // todos := make(chan string, runtime.NumCPU())
imageResult := make(chan *File) // imageResult := make(chan *File)
wg.Add(runtime.NumCPU()) // wg.Add(runtime.NumCPU())
for i := 0; i < runtime.NumCPU(); i++ { // for i := 0; i < runtime.NumCPU(); i++ {
go func() { // go func() {
defer wg.Done() // defer wg.Done()
for imagePath := range todos { // for imagePath := range todos {
name := filepath.Base(imagePath) // name := filepath.Base(imagePath)
ext := filepath.Ext(name) // ext := filepath.Ext(name)
title := name[0 : len(name)-len(ext)] // title := name[0 : len(name)-len(ext)]
imageResult <- &File{ // imageResult <- &File{
Path: imagePath, // Path: imagePath,
Name: name, // Name: name,
Title: title, // Title: title,
Data: imageconverter.Convert(imagePath, true, 1860, 2480, 75), // Data: imageconverter.Convert(imagePath, true, 1860, 2480, 75),
} // }
} // }
}() // }()
} // }
go func() { // go func() {
for _, imagePath := range imagesPath { // for _, imagePath := range imagesPath {
todos <- imagePath // todos <- imagePath
} // }
close(todos) // close(todos)
wg.Wait() // wg.Wait()
close(imageResult) // close(imageResult)
}() // }()
results := make([]*File, 0) // results := make([]*File, 0)
for result := range imageResult { // for result := range imageResult {
fmt.Println(result.Name) // fmt.Println(result.Name)
internalPath, _ := doc.AddImage(result.Data, result.Name) // internalPath, _ := doc.AddImage(result.Data, result.Name)
result.InternalPath = internalPath // result.InternalPath = internalPath
results = append(results, result) // results = append(results, result)
} // }
sort.SliceStable(results, func(i, j int) bool { // sort.SliceStable(results, func(i, j int) bool {
return strings.Compare( // return strings.Compare(
results[i].Path, results[j].Path, // results[i].Path, results[j].Path,
) < 0 // ) < 0
}) // })
for i, result := range results { // for i, result := range results {
if i == 0 { // if i == 0 {
doc.SetCover(result.InternalPath, "") // doc.SetCover(result.InternalPath, "")
} else { // } else {
doc.AddSection( // doc.AddSection(
fmt.Sprintf("<img src=\"%s\" />", result.InternalPath), // fmt.Sprintf("<img src=\"%s\" />", result.InternalPath),
result.Title, // result.Title,
fmt.Sprintf("%s.xhtml", result.Title), // fmt.Sprintf("%s.xhtml", result.Title),
"../css/cover.css", // "../css/cover.css",
) // )
} // }
} // }
} // }
func getImages(dirname string) []string { // func getImages(dirname string) []string {
images := make([]string, 0) // images := make([]string, 0)
filepath.WalkDir(dirname, func(path string, d fs.DirEntry, err error) error { // filepath.WalkDir(dirname, func(path string, d fs.DirEntry, err error) error {
if d.IsDir() { // if d.IsDir() {
return nil // return nil
} // }
ext := filepath.Ext(path) // ext := filepath.Ext(path)
if strings.ToLower(ext) != ".jpg" { // if strings.ToLower(ext) != ".jpg" {
return nil // return nil
} // }
images = append(images, path) // images = append(images, path)
return nil // return nil
}) // })
sort.Strings(images) // sort.Strings(images)
return images // return images
} // }
func main2() { // func main2() {
imagesPath := getImages("/Users/vincent/Downloads/Bleach T01 (Tite KUBO) [eBook officiel 1920]") // imagesPath := getImages("/Users/vincent/Downloads/Bleach T01 (Tite KUBO) [eBook officiel 1920]")
doc := epub2.NewEpub("Bleach T01 (Tite KUBO) [eBook officiel 1920]") // doc := epub2.NewEpub("Bleach T01 (Tite KUBO) [eBook officiel 1920]")
doc.SetAuthor("Bachelier Vincent") // doc.SetAuthor("Bachelier Vincent")
addImages(doc, imagesPath) // addImages(doc, imagesPath)
if err := doc.Write("/Users/vincent/Downloads/test.epub"); err != nil { // if err := doc.Write("/Users/vincent/Downloads/test.epub"); err != nil {
panic(err) // panic(err)
} // }
} // }
func main() { func main() {
err := epub.NewEpub("/Users/vincent/Downloads/test.epub"). err := epub.NewEpub("/Users/vincent/Downloads/test.epub").