imgconv.go

 1//go:build cgo
 2
 3package clib
 4
 5/*
 6#cgo LDFLAGS: -lm
 7#include "imgconv.h"
 8#include <stdlib.h>
 9*/
10import "C"
11import "unsafe"
12
13// DecodeToPNG takes raw image bytes (JPEG, PNG, BMP, GIF, etc.) and returns
14// PNG-encoded bytes along with image dimensions. Uses stb_image for decoding
15// and stb_image_write for PNG encoding in C, which is faster than Go's
16// image stdlib for large images.
17func DecodeToPNG(data []byte) (ImageConvertResult, bool) {
18	if len(data) == 0 {
19		return ImageConvertResult{}, false
20	}
21
22	cData := C.CBytes(data)
23	defer C.free(cData)
24
25	result := C.decode_to_png((*C.uchar)(cData), C.size_t(len(data)))
26	if result.ok == 0 {
27		return ImageConvertResult{}, false
28	}
29	defer C.free_image_result(&result) //nolint:gocritic
30
31	pngData := C.GoBytes(unsafe.Pointer(result.png_data), C.int(result.png_len))
32
33	return ImageConvertResult{
34		PNGData: pngData,
35		Width:   int(result.width),
36		Height:  int(result.height),
37	}, true
38}
39
40// ImageDimensions returns the width and height of an image without fully
41// decoding pixel data. This is faster than DecodeToPNG when you only need
42// the dimensions (e.g. to calculate terminal row count).
43func ImageDimensions(data []byte) (width, height int, ok bool) {
44	if len(data) == 0 {
45		return 0, 0, false
46	}
47
48	cData := C.CBytes(data)
49	defer C.free(cData)
50
51	var cw, ch C.int
52	ret := C.image_dimensions((*C.uchar)(cData), C.size_t(len(data)), &cw, &ch)
53	if ret == 0 {
54		return 0, 0, false
55	}
56	return int(cw), int(ch), true
57}