// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zopflipng import ( "fmt" ) /* #cgo LDFLAGS: -lzopflipng -lzopfli -lstdc++ -lm #include #include #include "zopflipng_lib.h" */ import "C" import "unsafe" // Options allows overriding of some internal parameters. type Options struct { LossyTransparent bool Lossy8bit bool NumIterations int NumIterationsLarge int } // NewOptions creates an options struct with the default parameters. func NewOptions() *Options { ret := &Options{ LossyTransparent: false, Lossy8bit: false, NumIterations: 15, NumIterationsLarge: 5, } return ret } // Compress recompresses a PNG using Zopfli. func Compress(inputSlice []byte) ([]byte, error) { return CompressWithOptions(inputSlice, NewOptions()) } // CompressWithOptions allows overriding some internal parameters. func CompressWithOptions(inputSlice []byte, options *Options) ([]byte, error) { cOptions := createCOptions(options) input := (*C.uchar)(unsafe.Pointer(&inputSlice[0])) inputSize := (C.size_t)(len(inputSlice)) var compressed *C.uchar var compressedLength C.size_t errCode := int(C.CZopfliPNGOptimize(input, inputSize, &cOptions, 0, &compressed, &compressedLength)) defer C.free(unsafe.Pointer(compressed)) if errCode != 0 { return nil, fmt.Errorf("ZopfliPng failed with code: %d", errCode) } result := make([]byte, compressedLength) C.memmove(unsafe.Pointer(&result[0]), unsafe.Pointer(compressed), compressedLength) return result, nil } func createCOptions(options *Options) C.struct_CZopfliPNGOptions { var cOptions C.struct_CZopfliPNGOptions C.CZopfliPNGSetDefaults(&cOptions) cOptions.lossy_transparent = boolToInt(options.LossyTransparent) cOptions.lossy_8bit = boolToInt(options.Lossy8bit) cOptions.num_iterations = C.int(options.NumIterations) cOptions.num_iterations_large = C.int(options.NumIterationsLarge) return cOptions } func boolToInt(b bool) C.int { if b { return C.int(1) } return C.int(0) }