Skip to content

Commit 8a7abb6

Browse files
committed
[minor] Rearranging thumbnails handling:
* Added KFX reader * Restructure MOBI reader so both KFX and MOBI readers have similar behavior. * Removing "stretch" configuration for MOBI thumbnails - always false.
1 parent 6c61b81 commit 8a7abb6

39 files changed

+12000
-117
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,5 +217,4 @@ incorporate your changes.
217217

218218
### TODO
219219

220-
- Add thumbnail support for KFX files
221220
- Expand history reports with some useful statistics

config/config.yaml.tmpl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ thumbnails:
2222
#---- when thumbnail is prepared it will be scaled to following dimensions
2323
width: 330
2424
height: 470
25-
#---- when true - instead of using prepared thumbnail from book, its cover image (if available) will be
26-
#---- scaled to requested dimensions
27-
stretch: false
2825

2926
logging:
3027
#---- controls terminal (stdout, stderr) output

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
module sync2kindle
22

3-
go 1.23.5
3+
go 1.23
44

55
require (
6+
github.com/amazon-ion/ion-go v1.5.0
67
github.com/disintegration/imaging v1.6.2
78
github.com/dustin/go-humanize v1.0.1
89
github.com/go-ole/go-ole v1.3.0

go.sum

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
22
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
3+
github.com/amazon-ion/ion-go v1.5.0 h1:fxsAyFda8N9HsM2xYbQSxJ3Qi/oLn0xzLoiXWG3bseg=
4+
github.com/amazon-ion/ion-go v1.5.0/go.mod h1:3ZEje8i20TiIPVZlN+KE3B2ppZ1B8d9F/KaT7Dtec+k=
35
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
46
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
7+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
58
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
69
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
710
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
@@ -22,6 +25,7 @@ github.com/go-playground/validator/v10 v10.21.0 h1:4fZA11ovvtkdgaeev9RGWPgc1uj3H
2225
github.com/go-playground/validator/v10 v10.21.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
2326
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
2427
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
28+
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
2529
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
2630
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
2731
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -40,6 +44,8 @@ github.com/rupor-github/gencfg v1.0.2 h1:LJnOoOL7ob9PBjikL4eHEhVruAhl6zCOFvFheuE
4044
github.com/rupor-github/gencfg v1.0.2/go.mod h1:41OMdMXM3iYYcjxrPwh3WYkud3+0Pf+RM3P2FovXG80=
4145
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
4246
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
47+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
48+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
4349
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
4450
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
4551
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
@@ -76,8 +82,11 @@ golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
7682
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
7783
golang.org/x/tools v0.21.1-0.20240531212143-b6235391adb3 h1:SHq4Rl+B7WvyM4XODon1LXtP7gcG49+7Jubt1gWWswY=
7884
golang.org/x/tools v0.21.1-0.20240531212143-b6235391adb3/go.mod h1:bqv7PJ/TtlrzgJKhOAGdDUkUltQapRik/UEHubLVBWo=
85+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
86+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
7987
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
8088
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
89+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
8190
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
8291
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
8392
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=

thumbs/config.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package thumbs
22

33
type ThumbnailsConfig struct {
4-
Width int `yaml:"width" validate:"required,gt=0"`
5-
Height int `yaml:"height" validate:"required,gt=0"`
6-
Stretch bool `yaml:"stretch"`
4+
Width int `yaml:"width" validate:"required,gt=0"`
5+
Height int `yaml:"height" validate:"required,gt=0"`
76

87
Dir string `yaml:"-"` // internal use only
98
}

thumbs/imgutils/jfif.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package imgutils
2+
3+
import (
4+
"bytes"
5+
"encoding/binary"
6+
)
7+
8+
// This is specific to go - when encoding jpeg standard encoder does not create JFIF APP0 segment and Kindle does not like it.
9+
10+
// JpegDPIType specifyes type of the DPI units
11+
type JpegDPIType uint8
12+
13+
// DPI units type values
14+
const (
15+
DpiNoUnits JpegDPIType = iota
16+
DpiPxPerInch
17+
DpiPxPerSm
18+
)
19+
20+
var (
21+
marker = []byte{0xFF, 0xE0} // APP0 segment marker
22+
jfif = []byte{0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02} // jfif + version
23+
)
24+
25+
// SetJpegDPI creates JFIF APP0 with provided DPI if segment is missing in image.
26+
func SetJpegDPI(buf *bytes.Buffer, dpit JpegDPIType, xdensity, ydensity int16) (*bytes.Buffer, bool) {
27+
28+
data := buf.Bytes()
29+
30+
// If JFIF APP0 segment is there - do not do anything
31+
if bytes.Equal(data[2:4], marker) {
32+
return buf, false
33+
}
34+
35+
var newbuf = new(bytes.Buffer)
36+
37+
newbuf.Write(data[:2])
38+
newbuf.Write(marker)
39+
binary.Write(newbuf, binary.BigEndian, uint16(0x10)) // length
40+
newbuf.Write(jfif)
41+
binary.Write(newbuf, binary.BigEndian, uint8(dpit))
42+
binary.Write(newbuf, binary.BigEndian, uint16(xdensity))
43+
binary.Write(newbuf, binary.BigEndian, uint16(ydensity))
44+
binary.Write(newbuf, binary.BigEndian, uint16(0)) // no thumbnail segment
45+
newbuf.Write(data[2:])
46+
47+
return newbuf, true
48+
}

thumbs/kfx/ion.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package kfx
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
7+
"github.com/amazon-ion/ion-go/ion"
8+
)
9+
10+
const (
11+
largestKnownSymbol = 834
12+
//
13+
symBookMetadata = 490
14+
symCategorizedMetadata = 491
15+
symExternalResource = 164
16+
symThumbnails = 214
17+
symRawMedia = 417
18+
)
19+
20+
var (
21+
ionBVM = []byte{0xE0, 1, 0, 0xEA} // binary version marker
22+
sharedSymbolTable = createSST(largestKnownSymbol)
23+
)
24+
25+
// Actual names for symbols could be obtained by looking at EpubToKFXConverter-4.0.jar from Kindle Previewer 3
26+
// with enum of interest in class file "com.amazon.kaf.c/B.class" presently.
27+
func createSST(maxID uint64) ion.SharedSymbolTable {
28+
symbols := make([]string, 0, maxID)
29+
for i := len(ion.V1SystemSymbolTable.Symbols()) + 1; i <= len(ion.V1SystemSymbolTable.Symbols())+int(maxID); i++ {
30+
symbols = append(symbols, fmt.Sprintf("$%d", i))
31+
}
32+
return ion.NewSharedSymbolTable("YJ_symbols", 10, symbols)
33+
}
34+
35+
func createProlog() []byte {
36+
buf := bytes.Buffer{}
37+
if err := ion.NewBinaryWriter(&buf, sharedSymbolTable).Finish(); err != nil {
38+
panic(err)
39+
}
40+
return buf.Bytes()
41+
}
42+
43+
func decodeData(prolog, data []byte, v any) error {
44+
if err := ion.Unmarshal(append(prolog, data[len(ionBVM):]...), v, sharedSymbolTable); err != nil {
45+
return err
46+
}
47+
return nil
48+
}
49+
50+
func decodeST(data []byte) (ion.SymbolTable, error) {
51+
r := ion.NewReaderCat(bytes.NewReader(data), ion.NewCatalog(sharedSymbolTable))
52+
r.Next() // we are not interested in the actual values and in most cases this will return false anyways
53+
if err := r.Err(); err != nil {
54+
return nil, err
55+
}
56+
return r.SymbolTable(), nil
57+
}

0 commit comments

Comments
 (0)