aboutsummaryrefslogtreecommitdiff
path: root/go/zopflipng/zopflipng.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/zopflipng/zopflipng.go')
-rw-r--r--go/zopflipng/zopflipng.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/go/zopflipng/zopflipng.go b/go/zopflipng/zopflipng.go
new file mode 100644
index 0000000..f532321
--- /dev/null
+++ b/go/zopflipng/zopflipng.go
@@ -0,0 +1,86 @@
+// 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 <stdlib.h>
+#include <string.h>
+#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)
+}