17 Commits

Author SHA1 Message Date
Milan Nikolic f01e858a24 Update build 2023-09-02 18:20:46 +02:00
Milan Nikolic 8c21b430a9 Update actions 2023-09-02 17:19:36 +02:00
Milan Nikolic 5fbd462a78 Update actions 2023-09-02 16:17:46 +02:00
Milan Nikolic 0797c8456f Add actions 2023-09-02 16:14:32 +02:00
Milan Nikolic c3f6c5a499 Update README.md 2023-09-02 12:14:06 +02:00
Milan Nikolic fa162972b2 Update README.md 2023-09-02 12:11:24 +02:00
Milan Nikolic aa65bfa4f4 Add tests 2023-09-02 12:11:09 +02:00
Milan Nikolic 6c293adc1f Update modules 2023-09-02 10:11:03 +02:00
Milan Nikolic 6936f697b4 Remove flip 2023-09-02 10:02:08 +02:00
Milan Nikolic 83d7a1ea6e Update README.md 2023-09-02 09:23:02 +02:00
Milan Nikolic 3d56765415 Update modules 2023-09-02 09:20:33 +02:00
Milan Nikolic b1fcf530da Add version and preview 2023-09-02 09:18:47 +02:00
Milan Nikolic 7dc21fc0b4 Update modules 2023-08-29 20:15:22 +02:00
Milan Nikolic fdfa80875e Add File type 2023-08-29 20:07:35 +02:00
Milan Nikolic 50b0911586 Close archive 2023-08-27 11:43:19 +02:00
Milan Nikolic 8db1690d3c Update thumbnail 2023-08-27 11:38:41 +02:00
Milan Nikolic 91e336f772 Update README.md 2023-08-24 15:04:51 +02:00
18 changed files with 491 additions and 154 deletions
+78
View File
@@ -0,0 +1,78 @@
on: [push, pull_request]
name: Test
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '3.27.x'
- name: Wget libaom
uses: wei/wget@v1
with:
args: https://storage.googleapis.com/aom-releases/libaom-3.7.0.tar.gz
- name: Unpack libaom
run: |
tar -xpf libaom-3.7.0.tar.gz && mkdir build
- name: Configure libaom
working-directory: build
run: |
cmake -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_DOCS=OFF \
-DENABLE_EXAMPLES=OFF -DENABLE_NASM=OFF -DENABLE_TESTS=OFF -DENABLE_TOOLS=OFF -DENABLE_WERROR=OFF \
-DAOM_TARGET_CPU=generic ../libaom-3.7.0
- name: Install libaom
working-directory: build
run: |
make -j3 && sudo make install
- name: Wget libheif
uses: wei/wget@v1
with:
args: https://github.com/strukturag/libheif/releases/download/v1.15.2/libheif-1.15.2.tar.gz
- name: Unpack libheif
run: |
tar -xpf libheif-1.15.2.tar.gz
- name: Configure libheif
working-directory: libheif-1.15.2
run: |
./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --enable-shared --disable-static --disable-libde265 \
--disable-dav1d --disable-go --enable-aom --disable-gdk-pixbuf --disable-rav1e --disable-tests --disable-x265
- name: Install libheif
working-directory: libheif-1.15.2
run: |
make -j3 && sudo make install
- name: Wget ImageMagick
uses: wei/wget@v1
with:
args: -O ImageMagick-7.1.1-15.tar.gz https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.1-15.tar.gz
- name: Unpack ImageMagick
run: |
tar -xpf ImageMagick-7.1.1-15.tar.gz
- name: Configure ImageMagick
working-directory: ImageMagick-7.1.1-15
run: |
./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --enable-shared --disable-static --enable-zero-configuration \
--without-frozenpaths --without-utilities --disable-hdri --disable-opencl --without-modules --without-magick-plus-plus --without-perl \
--without-bzlib --without-x --without-zip --with-zlib --without-dps --without-djvu --without-autotrace --without-fftw \
--without-fpx --without-fontconfig --without-freetype --without-gslib --without-gvc --without-jbig --without-openjp2 \
--without-jxl --without-lcms --without-lqr --without-lzma --without-openexr --without-pango --without-raw \
--without-rsvg --without-wmf --without-xml --disable-openmp --with-jpeg --with-heic --with-png --with-tiff --with-webp
- name: Install ImageMagick
working-directory: ImageMagick-7.1.1-15
run: |
make -j3 && sudo make install
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.21
- name: Checkout code
uses: actions/checkout@v2
- name: Test
run: go test
+29 -17
View File
@@ -8,21 +8,21 @@ It can convert comics to different formats to fit your various devices.
### Features
* reads RAR, ZIP, 7Z, CBR, CBZ, CB7, CBT, PDF, EPUB, MOBI and plain directory
* saves processed comics in CBZ (ZIP) archive format or CBT (TAR)
* reads CBR (RAR), CBZ (ZIP), CB7 (7Z), CBT (TAR), PDF, EPUB, MOBI and plain directory
* saves processed comics in ZIP archive format or TAR
* images can be converted to JPEG, PNG, TIFF, WEBP, AVIF, or 4-Bit BMP (16 colors) file format
* rotate, flip, adjust brightness/contrast, adjust levels (Photoshop-like) or grayscale images
* resize algorithms (NearestNeighbor, Box, Linear, MitchellNetravali, CatmullRom, Gaussian, Lanczos)
* rotate, adjust brightness/contrast, adjust levels (Photoshop-like) or grayscale images
* resize filters (NearestNeighbor, Box, Linear, MitchellNetravali, CatmullRom, Gaussian, Lanczos)
* export covers from comics
* create thumbnails from covers by [FreeDesktop](http://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html) specification
### Download
* [Windows x86_64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.8.3-windows-x86_64.zip)
* [Linux x86_64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.8.3-linux-x86_64.tar.gz)
* [Linux aarch64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.8.3-linux-aarch64.tar.gz)
* [macOS x86_64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.8.3-darwin-x86_64.zip)
* [macOS aarch64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.8.3-darwin-aarch64.zip)
* [Windows x86_64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.9.0-windows-x86_64.zip)
* [Linux x86_64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.9.0-linux-x86_64.tar.gz)
* [Linux aarch64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.9.0-linux-aarch64.tar.gz)
* [macOS x86_64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.9.0-darwin-x86_64.zip)
* [macOS aarch64](https://github.com/gen2brain/cbconvert/releases/latest/download/cbconvert-0.9.0-darwin-aarch64.zip)
### Using cbconvert in file managers to generate FreeDesktop thumbnails
@@ -79,8 +79,6 @@ This is what it looks like in the PCManFM file manager:
            Convert images to grayscale (monochromatic) (default "false")
        --rotate
            Rotate images, valid values are 0, 90, 180, 270 (default "0")
        --flip
            Flip images, valid values are none, horizontal, vertical (default "none")
        --brightness
            Adjust the brightness of the images, must be in the range (-100, 100) (default "0")
        --contrast
@@ -170,22 +168,36 @@ This is what it looks like in the PCManFM file manager:
### Examples
Rescale images to 1200px for all supported files found in a directory with a size larger than 60MB:
* Rescale images to 1200px for all supported files found in a directory with a size larger than 60MB:
`cbconvert --recursive --width 1200 --size 60 /media/comics/Thorgal/`
Convert all images in pdf to 4bit BMP images and save the result in ~/comics directory:
* Convert all images in pdf to 4bit BMP images and save the result in ~/comics directory:
`cbconvert --bmp --outdir ~/comics /media/comics/Garfield/Garfield_01.pdf`
`cbconvert --format bmp --outdir ~/comics /media/comics/Garfield/Garfield_01.pdf`
[BMP](http://en.wikipedia.org/wiki/BMP_file_format) format is a very good choice for black&white pages. Archive size can be smaller 2-3x and the file will be readable by comic readers.
Extract covers to ~/covers dir for all supported files found in the directory, Lanczos algorithm is used for resizing:
* Extract covers to ~/covers dir for all supported files found in the directory, Lanczos algorithm is used for resizing:
`cbconvert cover --outdir ~/covers --filter=7 /media/comics/GrooTheWanderer/`
* Convert all images to AVIF format:
`cbconvert --format avif --quality 50 --width 1280 --outdir ~/comics /media/comics/Misc/`
### Quality settings
This table maps quality settings for JPEG to the respective AVIF and WEBP quality settings:
| | | | | |
|--------------|----|----|----|----|
| JPEG quality | 50 | 60 | 70 | 80 |
| AVIF quality | 48 | 51 | 56 | 64 |
| WEBP quality | 55 | 64 | 72 | 82 |
### Compile
Install ImageMagick7 and libheif (with libaom) libraries and headers and then install to GOBIN:
Install ImageMagick7, MuPDF and libheif (with libaom) libraries and headers and then install to GOBIN:
`go install github.com/gen2brain/cbconvert/cmd/cbconvert@latest`
`go install -tags extlib github.com/gen2brain/cbconvert/cmd/cbconvert@latest`
+186 -78
View File
@@ -6,10 +6,11 @@ import (
"bytes"
"context"
"crypto/md5"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"mime"
"os"
"path/filepath"
"runtime"
@@ -26,11 +27,12 @@ import (
"image/png"
"github.com/chai2010/webp"
_ "github.com/hotei/bmp" // allow bmp decoding
_ "github.com/hotei/bmp" // allow 4-bit bmp decoding
"github.com/strukturag/libheif/go/heif"
"golang.org/x/image/tiff"
"github.com/disintegration/imaging"
"github.com/dustin/go-humanize"
"github.com/fvbommel/sortorder"
"github.com/gen2brain/go-fitz"
"github.com/gen2brain/go-unarr"
@@ -100,6 +102,8 @@ type Options struct {
Thumbnail bool
// CBZ metadata
Meta bool
// Version
Version bool
// ZIP comment
Comment bool
// ZIP comment body
@@ -109,35 +113,33 @@ type Options struct {
// Remove file
FileRemove string
// Output file
Outfile string
OutFile string
// Output directory
Outdir string
OutDir string
// Convert images to grayscale (monochromatic)
Grayscale bool
// Rotate images, valid values are 0, 90, 180, 270
Rotate int
// Flip images, valid values are none, horizontal, vertical
Flip string
// Adjust the brightness of the images, must be in the range (-100, 100)
Brightness float64
Brightness int
// Adjust the contrast of the images, must be in the range (-100, 100)
Contrast float64
Contrast int
// Process subdirectories recursively
Recursive bool
// Process only files larger than size (in MB)
Size int64
Size int
// Hide console output
Quiet bool
// Shadow input value
LevelsInMin float64
LevelsInMin int
// Highlight input value
LevelsInMax float64
LevelsInMax int
// Midpoint/gamma
LevelsGamma float64
// Shadow output value
LevelsOutMin float64
LevelsOutMin int
// Highlight output value
LevelsOutMax float64
LevelsOutMax int
}
// Convertor type.
@@ -162,6 +164,22 @@ type Convertor struct {
OnCompress func()
}
// File type.
type File struct {
Name string
Path string
Stat os.FileInfo
SizeHuman string
}
// Image type.
type Image struct {
Image image.Image
Width int
Height int
SizeHuman string
}
// New returns new convertor.
func New(o Options) *Convertor {
c := &Convertor{}
@@ -282,9 +300,10 @@ func (c *Convertor) convertArchive(fileName string) error {
var img image.Image
img, err = c.imageDecode(bytes.NewReader(data), pathName)
if err != nil {
e := err
img, err = c.imDecode(bytes.NewReader(data), pathName)
if err != nil {
return fmt.Errorf("convertArchive: %w", err)
return fmt.Errorf("convertArchive: %w: %w", e, err)
}
}
@@ -383,9 +402,15 @@ func (c *Convertor) convertDirectory(dirPath string) error {
var i image.Image
i, err = c.imageDecode(file, img)
if err != nil {
e := err
_, err = file.Seek(0, io.SeekStart)
if err != nil {
return fmt.Errorf("convertDirectory: %w: %w", e, err)
}
i, err = c.imDecode(file, img)
if err != nil {
return fmt.Errorf("convertDirectory: %w", err)
return fmt.Errorf("convertDirectory: %w: %w", e, err)
}
}
@@ -469,7 +494,7 @@ func (c *Convertor) imageConvert(ctx context.Context, img image.Image, index int
return nil
}
// imageTransform transforms image (resize, rotate, flip, brightness, contrast).
// imageTransform transforms image (resize, rotate, brightness, contrast).
func (c *Convertor) imageTransform(img image.Image) image.Image {
var i = img
@@ -492,21 +517,16 @@ func (c *Convertor) imageTransform(img image.Image) image.Image {
}
}
if c.Opts.Flip != "none" {
switch c.Opts.Flip {
case "horizontal":
i = imaging.FlipH(i)
case "vertical":
i = imaging.FlipV(i)
}
}
if c.Opts.Brightness != 0 {
i = imaging.AdjustBrightness(i, c.Opts.Brightness)
i = imaging.AdjustBrightness(i, float64(c.Opts.Brightness))
}
if c.Opts.Contrast != 0 {
i = imaging.AdjustContrast(i, c.Opts.Contrast)
i = imaging.AdjustContrast(i, float64(c.Opts.Contrast))
}
if c.Opts.Grayscale {
i = imageToGray(i)
}
return i
@@ -526,16 +546,16 @@ func (c *Convertor) imageLevel(img image.Image) (image.Image, error) {
_, qrange := imagick.GetQuantumRange()
quantumRange := float64(qrange)
inmin := (quantumRange * c.Opts.LevelsInMin) / 255
inmax := (quantumRange * c.Opts.LevelsInMax) / 255
outmin := (quantumRange * c.Opts.LevelsOutMin) / 255
outmax := (quantumRange * c.Opts.LevelsOutMax) / 255
inMin := (quantumRange * float64(c.Opts.LevelsInMin)) / 255
inMax := (quantumRange * float64(c.Opts.LevelsInMax)) / 255
outMin := (quantumRange * float64(c.Opts.LevelsOutMin)) / 255
outMax := (quantumRange * float64(c.Opts.LevelsOutMax)) / 255
if err := mw.LevelImage(inmin, c.Opts.LevelsGamma, inmax); err != nil {
if err := mw.LevelImage(inMin, c.Opts.LevelsGamma, inMax); err != nil {
return img, fmt.Errorf("imageLevel: %w", err)
}
if err := mw.LevelImage(-outmin, 1.0, quantumRange+(quantumRange-outmax)); err != nil {
if err := mw.LevelImage(-outMin, 1.0, quantumRange+(quantumRange-outMax)); err != nil {
return img, fmt.Errorf("imageLevel: %w", err)
}
@@ -544,9 +564,10 @@ func (c *Convertor) imageLevel(img image.Image) (image.Image, error) {
var i image.Image
i, err = c.imageDecode(bytes.NewReader(blob), "levels")
if err != nil {
e := err
i, err = c.imDecode(bytes.NewReader(blob), "levels")
if err != nil {
return nil, fmt.Errorf("imageLevel: %w", err)
return nil, fmt.Errorf("imageLevel: %w: %w", e, err)
}
}
@@ -614,10 +635,6 @@ func (c *Convertor) imageEncode(img image.Image, fileName string) error {
}
defer file.Close()
if c.Opts.Grayscale {
img = imageToGray(img)
}
switch filepath.Ext(fileName) {
case ".png":
err = png.Encode(file, img)
@@ -659,12 +676,6 @@ func (c *Convertor) imEncode(i image.Image, fileName string) error {
return fmt.Errorf("imEncode: %w", err)
}
if c.Opts.Grayscale {
if err := mw.TransformImageColorspace(imagick.COLORSPACE_GRAY); err != nil {
return fmt.Errorf("imEncode: %w", err)
}
}
switch filepath.Ext(fileName) {
case ".png":
if err := mw.SetImageFormat("PNG"); err != nil {
@@ -753,14 +764,14 @@ func (c *Convertor) archiveSaveZip(fileName string) error {
var zipName string
if c.Opts.Recursive {
err := os.MkdirAll(filepath.Join(c.Opts.Outdir, filepath.Dir(fileName)), 0755)
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Dir(fileName)), 0755)
if err != nil {
return fmt.Errorf("archiveSaveZip: %w", err)
}
zipName = filepath.Join(c.Opts.Outdir, filepath.Dir(fileName), fmt.Sprintf("%s%s.cbz", c.baseNoExt(fileName), c.Opts.Suffix))
zipName = filepath.Join(c.Opts.OutDir, filepath.Dir(fileName), fmt.Sprintf("%s%s.cbz", c.baseNoExt(fileName), c.Opts.Suffix))
} else {
zipName = filepath.Join(c.Opts.Outdir, fmt.Sprintf("%s%s.cbz", c.baseNoExt(fileName), c.Opts.Suffix))
zipName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%s%s.cbz", c.baseNoExt(fileName), c.Opts.Suffix))
}
zipFile, err := os.Create(zipName)
@@ -827,14 +838,14 @@ func (c *Convertor) archiveSaveTar(fileName string) error {
var tarName string
if c.Opts.Recursive {
err := os.MkdirAll(filepath.Join(c.Opts.Outdir, filepath.Dir(fileName)), 0755)
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Dir(fileName)), 0755)
if err != nil {
return fmt.Errorf("archiveSaveTar: %w", err)
}
tarName = filepath.Join(c.Opts.Outdir, filepath.Dir(fileName), fmt.Sprintf("%s%s.cbt", c.baseNoExt(fileName), c.Opts.Suffix))
tarName = filepath.Join(c.Opts.OutDir, filepath.Dir(fileName), fmt.Sprintf("%s%s.cbt", c.baseNoExt(fileName), c.Opts.Suffix))
} else {
tarName = filepath.Join(c.Opts.Outdir, fmt.Sprintf("%s%s.cbt", c.baseNoExt(fileName), c.Opts.Suffix))
tarName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%s%s.cbt", c.baseNoExt(fileName), c.Opts.Suffix))
}
tarFile, err := os.Create(tarName)
@@ -916,6 +927,7 @@ func (c *Convertor) archiveComment(fileName string) (string, error) {
if err != nil {
return "", fmt.Errorf("archiveComment: %w", err)
}
defer zr.Close()
return zr.Comment, nil
}
@@ -1178,9 +1190,10 @@ func (c *Convertor) coverArchive(fileName string) (image.Image, error) {
var img image.Image
img, err = c.imageDecode(bytes.NewReader(data), cover)
if err != nil {
e := err
img, err = c.imDecode(bytes.NewReader(data), cover)
if err != nil {
return nil, fmt.Errorf("coverArchive: %w", err)
return nil, fmt.Errorf("coverArchive: %w: %w", e, err)
}
}
@@ -1223,9 +1236,15 @@ func (c *Convertor) coverDirectory(dir string) (image.Image, error) {
var img image.Image
img, err = c.imageDecode(file, cover)
if err != nil {
e := err
_, err = file.Seek(0, io.SeekStart)
if err != nil {
return nil, fmt.Errorf("coverDirectory: %w: %w", e, err)
}
img, err = c.imDecode(file, cover)
if err != nil {
return nil, fmt.Errorf("coverDirectory: %w", err)
return nil, fmt.Errorf("coverDirectory: %w: %w", e, err)
}
}
@@ -1416,7 +1435,7 @@ func (c *Convertor) isNonImage(f string) bool {
// isSize checks size of file.
func (c *Convertor) isSize(size int64) bool {
if c.Opts.Size > 0 {
if size < c.Opts.Size*(1024*1024) {
if size < int64(c.Opts.Size)*(1024*1024) {
return false
}
}
@@ -1439,6 +1458,13 @@ func (c *Convertor) baseNoExt(filename string) string {
return strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
}
// tempName generates a temporary name.
func (c *Convertor) tempName(prefix, suffix string) string {
randBytes := make([]byte, 16)
_, _ = rand.Read(randBytes)
return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes)+suffix)
}
// copyFile copies reader to file.
func (c *Convertor) copyFile(reader io.Reader, filename string) error {
err := os.MkdirAll(filepath.Dir(filename), 0755)
@@ -1471,8 +1497,17 @@ func (c *Convertor) Terminate() {
}
// Files returns list of found comic files.
func (c *Convertor) Files(args []string) ([]string, error) {
var files []string
func (c *Convertor) Files(args []string) ([]File, error) {
var files []File
toFile := func(fp string, f os.FileInfo) File {
var file File
file.Name = filepath.Base(fp)
file.Path = fp
file.Stat = f
file.SizeHuman = humanize.IBytes(uint64(f.Size()))
return file
}
walkFiles := func(fp string, f os.FileInfo, err error) error {
if f.IsDir() {
@@ -1480,7 +1515,7 @@ func (c *Convertor) Files(args []string) ([]string, error) {
}
if c.isArchive(fp) || c.isDocument(fp) {
if c.isSize(f.Size()) {
files = append(files, fp)
files = append(files, toFile(fp, f))
}
}
@@ -1502,7 +1537,7 @@ func (c *Convertor) Files(args []string) ([]string, error) {
}
if count > 1 {
files = append(files, fp)
files = append(files, toFile(fp, f))
}
}
@@ -1523,7 +1558,7 @@ func (c *Convertor) Files(args []string) ([]string, error) {
if !stat.IsDir() {
if c.isArchive(path) || c.isDocument(path) {
if c.isSize(stat.Size()) {
files = append(files, path)
files = append(files, toFile(path, stat))
}
}
} else {
@@ -1544,7 +1579,7 @@ func (c *Convertor) Files(args []string) ([]string, error) {
return files, fmt.Errorf("%s: %w", arg, err)
}
if c.isSize(info.Size()) {
files = append(files, filepath.Join(path, f.Name()))
files = append(files, toFile(filepath.Join(path, f.Name()), info))
}
}
}
@@ -1557,7 +1592,7 @@ func (c *Convertor) Files(args []string) ([]string, error) {
return files, fmt.Errorf("%s: %w", arg, err)
}
} else {
files = append(files, path)
files = append(files, toFile(path, stat))
}
}
}
@@ -1587,14 +1622,14 @@ func (c *Convertor) Cover(fileName string, fileInfo os.FileInfo) error {
var fName string
if c.Opts.Recursive {
err := os.MkdirAll(filepath.Join(c.Opts.Outdir, filepath.Dir(fileName)), 0755)
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Dir(fileName)), 0755)
if err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
fName = filepath.Join(c.Opts.Outdir, filepath.Dir(fileName), fmt.Sprintf("%s.%s", c.baseNoExt(fileName), c.Opts.Format))
fName = filepath.Join(c.Opts.OutDir, filepath.Dir(fileName), fmt.Sprintf("%s.%s", c.baseNoExt(fileName), c.Opts.Format))
} else {
fName = filepath.Join(c.Opts.Outdir, fmt.Sprintf("%s.%s", c.baseNoExt(fileName), c.Opts.Format))
fName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%s.%s", c.baseNoExt(fileName), c.Opts.Format))
}
switch c.Opts.Format {
@@ -1612,10 +1647,10 @@ func (c *Convertor) Cover(fileName string, fileInfo os.FileInfo) error {
}
// Thumbnail extracts thumbnail.
func (c *Convertor) Thumbnail(fileName string, info os.FileInfo) error {
func (c *Convertor) Thumbnail(fileName string, fileInfo os.FileInfo) error {
c.CurrFile++
cover, err := c.coverImage(fileName, info)
cover, err := c.coverImage(fileName, fileInfo)
if err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
@@ -1642,21 +1677,21 @@ func (c *Convertor) Thumbnail(fileName string, info os.FileInfo) error {
var fName string
var fURI string
if c.Opts.Outfile == "" {
if c.Opts.OutFile == "" {
fURI = "file://" + fileName
if c.Opts.Recursive {
err := os.MkdirAll(filepath.Join(c.Opts.Outdir, filepath.Dir(fileName)), 0755)
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Dir(fileName)), 0755)
if err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
fName = filepath.Join(c.Opts.Outdir, filepath.Dir(fileName), fmt.Sprintf("%x.png", md5.Sum([]byte(fURI))))
fName = filepath.Join(c.Opts.OutDir, filepath.Dir(fileName), fmt.Sprintf("%x.png", md5.Sum([]byte(fURI))))
} else {
fName = filepath.Join(c.Opts.Outdir, fmt.Sprintf("%x.png", md5.Sum([]byte(fURI))))
fName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%x.png", md5.Sum([]byte(fURI))))
}
} else {
abs, _ := filepath.Abs(c.Opts.Outfile)
abs, _ := filepath.Abs(c.Opts.OutFile)
fURI = "file://" + abs
fName = abs
}
@@ -1667,19 +1702,16 @@ func (c *Convertor) Thumbnail(fileName string, info os.FileInfo) error {
if err := mw.SetImageProperty("Software", "CBconvert"); err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
if err := mw.SetImageProperty("Description", "Thumbnail of "+fURI); err != nil {
if err := mw.SetImageProperty("Description", "Thumbnail of "+fileName); err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
if err := mw.SetImageProperty("Thumb::URI", fURI); err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
if err := mw.SetImageProperty("Thumb::MTime", strconv.FormatInt(info.ModTime().Unix(), 10)); err != nil {
if err := mw.SetImageProperty("Thumb::MTime", strconv.FormatInt(fileInfo.ModTime().Unix(), 10)); err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
if err := mw.SetImageProperty("Thumb::Size", strconv.FormatInt(info.Size(), 10)); err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
if err := mw.SetImageProperty("Thumb::Mimetype", mime.TypeByExtension(filepath.Ext(fileName))); err != nil {
if err := mw.SetImageProperty("Thumb::Size", strconv.FormatInt(fileInfo.Size(), 10)); err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
@@ -1738,12 +1770,88 @@ func (c *Convertor) Meta(fileName string) (any, error) {
return "", nil
}
// Preview returns image preview.
func (c *Convertor) Preview(fileName string, fileInfo os.FileInfo, width, height int) (Image, error) {
var img Image
i, err := c.coverImage(fileName, fileInfo)
if err != nil {
return img, fmt.Errorf("%s: %w", fileName, err)
}
i = c.imageTransform(i)
if c.Opts.LevelsInMin != 0 || c.Opts.LevelsInMax != 255 || c.Opts.LevelsGamma != 1.0 ||
c.Opts.LevelsOutMin != 0 || c.Opts.LevelsOutMax != 255 {
i, err = c.imageLevel(i)
if err != nil {
return img, fmt.Errorf("%s: %w", fileName, err)
}
}
tmpName := c.tempName("cbc", "."+c.Opts.Format)
switch c.Opts.Format {
case "jpeg", "png", "tiff", "webp", "avif":
if err := c.imageEncode(i, tmpName); err != nil {
return img, fmt.Errorf("%s: %w", fileName, err)
}
case "bmp":
if err := c.imEncode(i, tmpName); err != nil {
return img, fmt.Errorf("%s: %w", fileName, err)
}
}
stat, err := os.Stat(tmpName)
if err != nil {
return img, fmt.Errorf("%s: %w", fileName, err)
}
img.Width = i.Bounds().Dx()
img.Height = i.Bounds().Dy()
img.SizeHuman = humanize.IBytes(uint64(stat.Size()))
f, err := os.Open(tmpName)
if err != nil {
return img, fmt.Errorf("%s: %w", fileName, err)
}
defer os.Remove(tmpName)
dec, err := c.imageDecode(f, tmpName)
if err != nil {
e := err
_, err = f.Seek(0, io.SeekStart)
if err != nil {
return img, fmt.Errorf("%s: %w: %w", tmpName, e, err)
}
dec, err = c.imDecode(f, tmpName)
if err != nil {
return img, fmt.Errorf("%s: %w: %w", tmpName, e, err)
}
}
err = f.Close()
if err != nil {
return img, fmt.Errorf("%s: %w", fileName, err)
}
if width != 0 && height != 0 {
dec = imaging.Fit(dec, width, height, filters[c.Opts.Filter])
}
img.Image = dec
return img, nil
}
// Convert converts comic book.
func (c *Convertor) Convert(fileName string, info os.FileInfo) error {
func (c *Convertor) Convert(fileName string, fileInfo os.FileInfo) error {
c.CurrFile++
switch {
case info.IsDir():
case fileInfo.IsDir():
if err := c.convertDirectory(fileName); err != nil {
return fmt.Errorf("%s: %w", fileName, err)
}
+117
View File
@@ -0,0 +1,117 @@
package cbconvert
import (
"fmt"
"os"
"path/filepath"
"testing"
)
func TestConvert(t *testing.T) {
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
t.Error(err)
}
opts := Options{}
opts.OutDir = tmpDir
opts.Archive = "zip"
opts.Quality = 75
opts.Filter = 2
conv := New(opts)
conv.Initialize()
defer conv.Terminate()
files, err := conv.Files([]string{"testdata/test", "testdata"})
if err != nil {
t.Error(err)
}
for _, format := range []string{"jpeg", "png", "tiff", "bmp", "webp", "avif"} {
conv.Opts.Format = format
for _, file := range files {
conv.Opts.Suffix = fmt.Sprintf("_%s%s", format, filepath.Ext(file.Path))
err = conv.Convert(file.Path, file.Stat)
if err != nil {
t.Errorf("format %s: file %s: %v", format, file.Name, err)
}
}
}
err = os.RemoveAll(tmpDir)
if err != nil {
t.Error(err)
}
}
func TestCover(t *testing.T) {
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
t.Error(err)
}
opts := Options{}
opts.OutDir = tmpDir
opts.Quality = 75
opts.Filter = 2
opts.Format = "jpeg"
conv := New(opts)
conv.Initialize()
defer conv.Terminate()
files, err := conv.Files([]string{"testdata/test.cbt"})
if err != nil {
t.Error(err)
}
for _, file := range files {
err = conv.Cover(file.Path, file.Stat)
if err != nil {
t.Error(err)
}
}
err = os.RemoveAll(tmpDir)
if err != nil {
t.Error(err)
}
}
func TestThumbnail(t *testing.T) {
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
if err != nil {
t.Error(err)
}
opts := Options{}
opts.OutDir = tmpDir
opts.Filter = 2
conv := New(opts)
conv.Initialize()
defer conv.Terminate()
files, err := conv.Files([]string{"testdata/test.pdf"})
if err != nil {
t.Error(err)
}
for _, file := range files {
err = conv.Thumbnail(file.Path, file.Stat)
if err != nil {
t.Error(err)
}
}
err = os.RemoveAll(tmpDir)
if err != nil {
t.Error(err)
}
}
+2 -1
View File
@@ -5,7 +5,7 @@ go 1.21
toolchain go1.21.0
require (
github.com/gen2brain/cbconvert v0.0.0-20230824094314-e938b140f074
github.com/gen2brain/cbconvert v0.0.0-20230902080208-6936f697b466
github.com/schollz/progressbar/v3 v3.10.0
github.com/spf13/pflag v1.0.5
)
@@ -13,6 +13,7 @@ require (
require (
github.com/chai2010/webp v1.1.1 // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/gen2brain/go-fitz v1.23.1 // indirect
github.com/gen2brain/go-unarr v0.1.7 // indirect
+4 -2
View File
@@ -5,10 +5,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
github.com/gen2brain/cbconvert v0.0.0-20230824094314-e938b140f074 h1:fUW60MgEEH44Y4ZNpi4Y4GwHeUzNayvJy+bJ5J1QiJI=
github.com/gen2brain/cbconvert v0.0.0-20230824094314-e938b140f074/go.mod h1:8eCyHuxeUYNvyYr1nCS+M7zL0fjnb3CO5R5JIOgG4Tk=
github.com/gen2brain/cbconvert v0.0.0-20230902080208-6936f697b466 h1:xrc1+L/Wc9BHokp+smaBt/A2R2+nfK0Ws0cvyzTHE7I=
github.com/gen2brain/cbconvert v0.0.0-20230902080208-6936f697b466/go.mod h1:5CIPgEHKNZtfH7FR0zzGMAzkFwagUyH7FcjIUDEx7Ps=
github.com/gen2brain/go-fitz v1.23.1 h1:x69/szWZXpI3jZ57mMqCg7WqqvtYnQG0lXts3L6M1Fc=
github.com/gen2brain/go-fitz v1.23.1/go.mod h1:HU04vc+RisUh/kvEd2pB0LAxmK1oyXdN4ftyshUr9rQ=
github.com/gen2brain/go-unarr v0.1.7 h1:mEE7bPShJIsmAX67t6BW2ibpEUO7j5WK152KgNM9NbQ=
+67 -38
View File
@@ -7,6 +7,7 @@ import (
"os"
"os/signal"
"path/filepath"
"runtime/debug"
"syscall"
"github.com/gen2brain/cbconvert"
@@ -14,8 +15,43 @@ import (
flag "github.com/spf13/pflag"
)
var appVersion string
func init() {
if appVersion != "" {
return
}
info, ok := debug.ReadBuildInfo()
if !ok {
return
}
if info.Main.Version != "" {
appVersion = info.Main.Version
}
for _, kv := range info.Settings {
if kv.Value == "" {
continue
}
if kv.Key == "vcs.revision" {
appVersion = kv.Value
if len(appVersion) > 10 {
appVersion = kv.Value[:10]
}
}
}
}
func main() {
opts, args := parseFlags()
if opts.Version {
fmt.Println(filepath.Base(os.Args[0]), appVersion)
os.Exit(0)
}
conv := cbconvert.New(opts)
c := make(chan os.Signal, 2)
@@ -30,8 +66,8 @@ func main() {
}
}()
if _, err := os.Stat(opts.Outdir); err != nil {
if err := os.MkdirAll(opts.Outdir, 0775); err != nil {
if _, err := os.Stat(opts.OutDir); err != nil {
if err := os.MkdirAll(opts.OutDir, 0775); err != nil {
fmt.Println(err)
}
os.Exit(1)
@@ -83,15 +119,9 @@ func main() {
}
for _, file := range files {
stat, err := os.Stat(file)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
switch {
case opts.Meta:
ret, err := conv.Meta(file)
ret, err := conv.Meta(file.Path)
if err != nil {
fmt.Println(err)
os.Exit(1)
@@ -105,14 +135,14 @@ func main() {
continue
case opts.Cover:
if err := conv.Cover(file, stat); err != nil {
if err := conv.Cover(file.Path, file.Stat); err != nil {
fmt.Println(err)
os.Exit(1)
}
continue
case opts.Thumbnail:
if err = conv.Thumbnail(file, stat); err != nil {
if err = conv.Thumbnail(file.Path, file.Stat); err != nil {
fmt.Println(err)
os.Exit(1)
}
@@ -120,7 +150,7 @@ func main() {
continue
}
if err := conv.Convert(file, stat); err != nil {
if err := conv.Convert(file.Path, file.Stat); err != nil {
fmt.Println(err)
os.Exit(1)
}
@@ -150,17 +180,16 @@ func parseFlags() (cbconvert.Options, []string) {
convert.BoolVar(&opts.NoConvert, "no-convert", false, "Do not transform or convert images")
convert.BoolVar(&opts.Grayscale, "grayscale", false, "Convert images to grayscale (monochromatic)")
convert.IntVar(&opts.Rotate, "rotate", 0, "Rotate images, valid values are 0, 90, 180, 270")
convert.StringVar(&opts.Flip, "flip", "none", "Flip images, valid values are none, horizontal, vertical")
convert.Float64Var(&opts.Brightness, "brightness", 0, "Adjust the brightness of the images, must be in the range (-100, 100)")
convert.Float64Var(&opts.Contrast, "contrast", 0, "Adjust the contrast of the images, must be in the range (-100, 100)")
convert.IntVar(&opts.Brightness, "brightness", 0, "Adjust the brightness of the images, must be in the range (-100, 100)")
convert.IntVar(&opts.Contrast, "contrast", 0, "Adjust the contrast of the images, must be in the range (-100, 100)")
convert.StringVar(&opts.Suffix, "suffix", "", "Add suffix to file basename")
convert.Float64Var(&opts.LevelsInMin, "levels-inmin", 0, "Shadow input value")
convert.IntVar(&opts.LevelsInMin, "levels-inmin", 0, "Shadow input value")
convert.Float64Var(&opts.LevelsGamma, "levels-gamma", 1.0, "Midpoint/Gamma")
convert.Float64Var(&opts.LevelsInMax, "levels-inmax", 255, "Highlight input value")
convert.Float64Var(&opts.LevelsOutMin, "levels-outmin", 0, "Shadow output value")
convert.Float64Var(&opts.LevelsOutMax, "levels-outmax", 255, "Highlight output value")
convert.StringVar(&opts.Outdir, "outdir", ".", "Output directory")
convert.Int64Var(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
convert.IntVar(&opts.LevelsInMax, "levels-inmax", 255, "Highlight input value")
convert.IntVar(&opts.LevelsOutMin, "levels-outmin", 0, "Shadow output value")
convert.IntVar(&opts.LevelsOutMax, "levels-outmax", 255, "Highlight output value")
convert.StringVar(&opts.OutDir, "outdir", ".", "Output directory")
convert.IntVar(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
convert.BoolVar(&opts.Recursive, "recursive", false, "Process subdirectories recursively")
convert.BoolVar(&opts.Quiet, "quiet", false, "Hide console output")
@@ -172,8 +201,8 @@ func parseFlags() (cbconvert.Options, []string) {
cover.StringVar(&opts.Format, "format", "jpeg", "Image format, valid values are jpeg, png, tiff, bmp, webp, avif")
cover.IntVar(&opts.Quality, "quality", 75, "Image quality")
cover.IntVar(&opts.Filter, "filter", 2, "0=NearestNeighbor, 1=Box, 2=Linear, 3=MitchellNetravali, 4=CatmullRom, 6=Gaussian, 7=Lanczos")
cover.StringVar(&opts.Outdir, "outdir", ".", "Output directory")
cover.Int64Var(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
cover.StringVar(&opts.OutDir, "outdir", ".", "Output directory")
cover.IntVar(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
cover.BoolVar(&opts.Recursive, "recursive", false, "Process subdirectories recursively")
cover.BoolVar(&opts.Quiet, "quiet", false, "Hide console output")
@@ -183,9 +212,9 @@ func parseFlags() (cbconvert.Options, []string) {
thumbnail.IntVar(&opts.Height, "height", 0, "Image height")
thumbnail.BoolVar(&opts.Fit, "fit", false, "Best fit for required width and height")
thumbnail.IntVar(&opts.Filter, "filter", 2, "0=NearestNeighbor, 1=Box, 2=Linear, 3=MitchellNetravali, 4=CatmullRom, 6=Gaussian, 7=Lanczos")
thumbnail.StringVar(&opts.Outdir, "outdir", ".", "Output directory")
thumbnail.StringVar(&opts.Outfile, "outfile", "", "Output file")
thumbnail.Int64Var(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
thumbnail.StringVar(&opts.OutDir, "outdir", ".", "Output directory")
thumbnail.StringVar(&opts.OutFile, "outfile", "", "Output file")
thumbnail.IntVar(&opts.Size, "size", 0, "Process only files larger than size (in MB)")
thumbnail.BoolVar(&opts.Recursive, "recursive", false, "Process subdirectories recursively")
thumbnail.BoolVar(&opts.Quiet, "quiet", false, "Hide console output")
@@ -197,34 +226,32 @@ func parseFlags() (cbconvert.Options, []string) {
meta.StringVar(&opts.FileAdd, "file-add", "", "Add file to archive")
meta.StringVar(&opts.FileRemove, "file-remove", "", "Remove file from archive (glob pattern, i.e. *.xml)")
convert.Usage = func() {
flag.NewFlagSet("version", flag.ExitOnError)
flag.Usage = func() {
_, _ = fmt.Fprintf(os.Stderr, "Usage: %s <command> [<flags>] [file1 dir1 ... fileOrDirN]\n\n", filepath.Base(os.Args[0]))
_, _ = fmt.Fprintf(os.Stderr, "\nCommands:\n")
_, _ = fmt.Fprintf(os.Stderr, "\n convert\n \tConvert archive or document\n\n")
convert.VisitAll(func(f *flag.Flag) {
_, _ = fmt.Fprintf(os.Stderr, " --%s", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "\n \t")
_, _ = fmt.Fprintf(os.Stderr, " --%s\n \t", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "%v (default %q)\n", f.Usage, f.DefValue)
})
_, _ = fmt.Fprintf(os.Stderr, "\n cover\n \tExtract cover\n\n")
cover.VisitAll(func(f *flag.Flag) {
_, _ = fmt.Fprintf(os.Stderr, " --%s", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "\n \t")
_, _ = fmt.Fprintf(os.Stderr, " --%s\n \t", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "%v (default %q)\n", f.Usage, f.DefValue)
})
_, _ = fmt.Fprintf(os.Stderr, "\n thumbnail\n \tExtract cover thumbnail (freedesktop spec.)\n\n")
thumbnail.VisitAll(func(f *flag.Flag) {
_, _ = fmt.Fprintf(os.Stderr, " --%s", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "\n \t")
_, _ = fmt.Fprintf(os.Stderr, " --%s\n \t", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "%v (default %q)\n", f.Usage, f.DefValue)
})
_, _ = fmt.Fprintf(os.Stderr, "\n meta\n \tCBZ metadata\n\n")
meta.VisitAll(func(f *flag.Flag) {
_, _ = fmt.Fprintf(os.Stderr, " --%s", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "\n \t")
_, _ = fmt.Fprintf(os.Stderr, " --%s\n \t", f.Name)
_, _ = fmt.Fprintf(os.Stderr, "%v (default %q)\n", f.Usage, f.DefValue)
})
_, _ = fmt.Fprintf(os.Stderr, "\n")
_, _ = fmt.Fprintf(os.Stderr, "\n version\n \tPrint version\n\n")
}
if len(os.Args) < 2 {
@@ -262,10 +289,12 @@ func parseFlags() (cbconvert.Options, []string) {
if !pipe {
args = meta.Args()
}
case "version":
opts.Version = true
}
if len(args) == 0 {
convert.Usage()
if len(args) == 0 && !opts.Version {
flag.Usage()
_, _ = fmt.Fprintf(os.Stderr, "no arguments\n")
os.Exit(1)
}
+5 -18
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env bash
GLIBC_x86_64="/usr/x86_64-pc-linux-gnu-static"
MUSL_x86_64="/usr/x86_64-pc-linux-musl"
MUSL_aarch64="/usr/aarch64-pc-linux-musl"
MINGW_x86_64="/usr/x86_64-w64-mingw32"
MACOS_x86_64="/usr/x86_64-apple-darwin"
@@ -17,22 +16,10 @@ PKG_CONFIG_LIBDIR="$GLIBC_x86_64/usr/lib64/pkgconfig" \
CGO_CFLAGS="-I$GLIBC_x86_64/usr/include" \
CGO_LDFLAGS="-L$GLIBC_x86_64/usr/lib64" \
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w '-extldflags=-static'" && \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w -X main.appVersion=${VERSION} '-extldflags=-static'" && \
cp ../../README.md ../../AUTHORS ../../COPYING ${BUILDDIR} && tar -czf "${BUILDDIR}-linux-x86_64.tar.gz" ${BUILDDIR}
rm -rf ${BUILDDIR}
#BUILDDIR="cbconvert-${VERSION}"; mkdir -p ${BUILDDIR}
#CC=x86_64-pc-linux-musl-gcc \
#PKG_CONFIG="x86_64-pc-linux-musl-pkg-config" \
#PKG_CONFIG_PATH="$MUSL_x86_64/usr/lib/pkgconfig" \
#PKG_CONFIG_LIBDIR="$MUSL_x86_64/usr/lib/pkgconfig" \
#CGO_CFLAGS="-I$MUSL_x86_64/usr/include" \
#CGO_LDFLAGS="-L$MUSL_x86_64/usr/lib" \
#CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \
#go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w '-extldflags=-static'" && \
#cp ../../README.md ../../AUTHORS ../../COPYING ${BUILDDIR} && tar -czf "${BUILDDIR}-linux-x86_64.tar.gz" ${BUILDDIR}
#rm -rf ${BUILDDIR}
BUILDDIR="cbconvert-${VERSION}"; mkdir -p ${BUILDDIR}
CC=aarch64-pc-linux-musl-gcc \
PKG_CONFIG="aarch64-pc-linux-musl-pkg-config" \
@@ -41,7 +28,7 @@ PKG_CONFIG_LIBDIR="$MUSL_aarch64/usr/lib/pkgconfig" \
CGO_CFLAGS="-I$MUSL_aarch64/usr/include" \
CGO_LDFLAGS="-L$MUSL_aarch64/usr/lib" \
CGO_ENABLED=1 GOOS=linux GOARCH=arm64 \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w '-extldflags=-static'" && \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w -X main.appVersion=${VERSION} '-extldflags=-static'" && \
cp ../../README.md ../../AUTHORS ../../COPYING ${BUILDDIR} && tar -czf "${BUILDDIR}-linux-aarch64.tar.gz" ${BUILDDIR}
rm -rf ${BUILDDIR}
@@ -53,7 +40,7 @@ PKG_CONFIG_LIBDIR="$MINGW_x86_64/usr/lib/pkgconfig" \
CGO_CFLAGS="-I$MINGW_x86_64/usr/include" \
CGO_LDFLAGS="-L$MINGW_x86_64/usr/lib" \
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert.exe -ldflags "-s -w '-extldflags=-static -Wl,--allow-multiple-definition'" && \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert.exe -ldflags "-s -w -X main.appVersion=${VERSION} '-extldflags=-static -Wl,--allow-multiple-definition'" && \
cp ../../README.md ../../AUTHORS ../../COPYING ${BUILDDIR} && zip -rq "${BUILDDIR}-windows-x86_64.zip" ${BUILDDIR}
rm -rf ${BUILDDIR}
@@ -67,7 +54,7 @@ PKG_CONFIG_LIBDIR="$MACOS_x86_64/SDK/MacOSX12.1.sdk/usr/lib/pkgconfig" \
CGO_CFLAGS="-I$MACOS_x86_64/usr/include -I$MACOS_x86_64/macports/pkgs/opt/local/include" \
CGO_LDFLAGS="-L$MACOS_x86_64/SDK/MacOSX12.1.sdk/usr/lib -L$MACOS_x86_64/macports/pkgs/opt/local/lib -mmacosx-version-min=10.13" \
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w" && \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w -X main.appVersion=${VERSION}" && \
cp ../../README.md ../../AUTHORS ../../COPYING ${BUILDDIR} && zip -rq "${BUILDDIR}-darwin-x86_64.zip" ${BUILDDIR}
rm -rf ${BUILDDIR}
@@ -81,6 +68,6 @@ PKG_CONFIG_LIBDIR="$MACOS_aarch64/SDK/MacOSX12.1.sdk/usr/lib/pkgconfig" \
CGO_CFLAGS="-I$MACOS_aarch64/usr/include -I$MACOS_aarch64/macports/pkgs/opt/local/include" \
CGO_LDFLAGS="-L$MACOS_aarch64/SDK/MacOSX12.1.sdk/usr/lib -L$MACOS_aarch64/macports/pkgs/opt/local/lib -mmacosx-version-min=10.13" \
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w" && \
go build -trimpath -tags 'extlib pkgconfig' -v -o ${BUILDDIR}/cbconvert -ldflags "-linkmode external -s -w -X main.appVersion=${VERSION}" && \
cp ../../README.md ../../AUTHORS ../../COPYING ${BUILDDIR} && zip -rq "${BUILDDIR}-darwin-aarch64.zip" ${BUILDDIR}
rm -rf ${BUILDDIR}
+1
View File
@@ -5,6 +5,7 @@ go 1.21
require (
github.com/chai2010/webp v1.1.1
github.com/disintegration/imaging v1.6.2
github.com/dustin/go-humanize v1.0.1
github.com/fvbommel/sortorder v1.1.0
github.com/gen2brain/go-fitz v1.23.1
github.com/gen2brain/go-unarr v0.1.7
+2
View File
@@ -2,6 +2,8 @@ github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk=
github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
github.com/gen2brain/go-fitz v1.23.1 h1:x69/szWZXpI3jZ57mMqCg7WqqvtYnQG0lXts3L6M1Fc=
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB