package epubzip import ( "archive/zip" "bytes" "compress/flate" "fmt" "hash/crc32" "image" "image/jpeg" "image/png" "time" ) type Image struct { Header *zip.FileHeader Data []byte } var naiveJFIFHeader = []byte{ 0xFF, 0xD8, // SOI 0xFF, 0xE0, // APP0 Marker 0x00, 0x10, // Length 0x4A, 0x46, 0x49, 0x46, 0x00, // JFIF\0 0x01, 0x02, // 1.02 0x00, // Density type 0x00, 0x01, // X Density 0x00, 0x01, // Y Density 0x00, 0x00, // No Thumbnail } // CompressImage create gzip encoded jpeg func CompressImage(filename string, format string, img image.Image, quality int) (Image, error) { var ( data, cdata bytes.Buffer err error ) switch format { case "png": err = png.Encode(&data, img) case "jpeg": // static JFIF header for better compatibility with Kindle devices var b bytes.Buffer err = jpeg.Encode(&b, img, &jpeg.Options{Quality: quality}) data.Write(naiveJFIFHeader) data.Write(b.Bytes()[2:]) default: err = fmt.Errorf("unknown format %q", format) } if err != nil { return Image{}, err } wcdata, err := flate.NewWriter(&cdata, flate.BestCompression) if err != nil { return Image{}, err } _, err = wcdata.Write(data.Bytes()) if err != nil { return Image{}, err } err = wcdata.Close() if err != nil { return Image{}, err } t := time.Now() //goland:noinspection GoDeprecation return Image{ &zip.FileHeader{ Name: filename, CompressedSize64: uint64(cdata.Len()), UncompressedSize64: uint64(data.Len()), CRC32: crc32.Checksum(data.Bytes(), crc32.IEEETable), Method: zip.Deflate, ModifiedTime: uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11), ModifiedDate: uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9), }, cdata.Bytes(), }, nil }