1// Copyright 2019 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14package zopflipng 15 16import ( 17 "fmt" 18) 19 20/* 21#cgo LDFLAGS: -lzopflipng -lzopfli -lstdc++ -lm 22#include <stdlib.h> 23#include <string.h> 24#include "zopflipng_lib.h" 25*/ 26import "C" 27import "unsafe" 28 29// Options allows overriding of some internal parameters. 30type Options struct { 31 LossyTransparent bool 32 Lossy8bit bool 33 NumIterations int 34 NumIterationsLarge int 35} 36 37// NewOptions creates an options struct with the default parameters. 38func NewOptions() *Options { 39 ret := &Options{ 40 LossyTransparent: false, 41 Lossy8bit: false, 42 NumIterations: 15, 43 NumIterationsLarge: 5, 44 } 45 return ret 46} 47 48// Compress recompresses a PNG using Zopfli. 49func Compress(inputSlice []byte) ([]byte, error) { 50 return CompressWithOptions(inputSlice, NewOptions()) 51} 52 53// CompressWithOptions allows overriding some internal parameters. 54func CompressWithOptions(inputSlice []byte, options *Options) ([]byte, error) { 55 cOptions := createCOptions(options) 56 input := (*C.uchar)(unsafe.Pointer(&inputSlice[0])) 57 inputSize := (C.size_t)(len(inputSlice)) 58 var compressed *C.uchar 59 var compressedLength C.size_t 60 errCode := int(C.CZopfliPNGOptimize(input, inputSize, &cOptions, 0, &compressed, &compressedLength)) 61 defer C.free(unsafe.Pointer(compressed)) 62 if errCode != 0 { 63 return nil, fmt.Errorf("ZopfliPng failed with code: %d", errCode) 64 } 65 66 result := make([]byte, compressedLength) 67 C.memmove(unsafe.Pointer(&result[0]), unsafe.Pointer(compressed), compressedLength) 68 return result, nil 69} 70 71func createCOptions(options *Options) C.struct_CZopfliPNGOptions { 72 var cOptions C.struct_CZopfliPNGOptions 73 C.CZopfliPNGSetDefaults(&cOptions) 74 cOptions.lossy_transparent = boolToInt(options.LossyTransparent) 75 cOptions.lossy_8bit = boolToInt(options.Lossy8bit) 76 cOptions.num_iterations = C.int(options.NumIterations) 77 cOptions.num_iterations_large = C.int(options.NumIterationsLarge) 78 return cOptions 79} 80 81func boolToInt(b bool) C.int { 82 if b { 83 return C.int(1) 84 } 85 return C.int(0) 86} 87