Skip to content

Commit

Permalink
Add decoder / encoder parameters.
Browse files Browse the repository at this point in the history
  • Loading branch information
fancycode committed Aug 27, 2024
1 parent 843894b commit bb61398
Show file tree
Hide file tree
Showing 7 changed files with 425 additions and 0 deletions.
97 changes: 97 additions & 0 deletions decoding_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import "C"
import (
"errors"
"runtime"
"unsafe"
)

// DecodingOptions contain options that are used for decoding.
Expand All @@ -36,6 +37,9 @@ type DecodingOptions struct {
}

func freeHeifDecodingOptions(options *DecodingOptions) {
if options.options.decoder_id != nil {
C.free(unsafe.Pointer(options.options.decoder_id))
}
C.heif_decoding_options_free(options.options)
options.options = nil
}
Expand All @@ -55,5 +59,98 @@ func NewDecodingOptions() (*DecodingOptions, error) {

runtime.SetFinalizer(options, freeHeifDecodingOptions)
options.options.version = 5
options.options.color_conversion_options.version = 1
return options, nil
}

// SetIgnoreTransformations sets whether geometric transformations like
// cropping, rotation, mirroring should be ignored.
func (o *DecodingOptions) SetIgnoreTransformations(ignore bool) {
o.options.ignore_transformations = convertBool[C.uchar](ignore)
}

// GetIgnoreTransformations returns true if geometric transformations like
// cropping, rotation, mirroring should be ignored.
func (o *DecodingOptions) GetIgnoreTransformations() bool {
return o.options.ignore_transformations != 0
}

// SetConvertHDRTo8Bit defines whether HDR images should be converted to 8bit
// during decoding.
func (o *DecodingOptions) SetConvertHDRTo8Bit(convert bool) {
o.options.convert_hdr_to_8bit = convertBool[C.uchar](convert)
}

// GetConvertHDRTo8Bit returns true if HDR images will be converted to 8bit
// during decoding.
func (o *DecodingOptions) GetConvertHDRTo8Bit() bool {
return o.options.convert_hdr_to_8bit != 0
}

// SetStrictDecoding enabled strict decoding and an error is returned for
// invalid input. Otherwise, it will try its best and add decoding warnings
// to the decoded heif_image. Default is non-strict.
func (o *DecodingOptions) SetStrictDecoding(strict bool) {
o.options.strict_decoding = convertBool[C.uchar](strict)
}

// GetStrictDecoding returns true if strict decoding is enabled.
func (o *DecodingOptions) GetStrictDecoding() bool {
return o.options.strict_decoding != 0
}

// SetDecoderId sets the id of the decoder to use. If an empty id is specified
// (the default), the highest priority decoder is chosen.
// The priority is defined in the plugin.
func (o *DecodingOptions) SetDecoderId(decoder string) {
if o.options.decoder_id != nil {
C.free(unsafe.Pointer(o.options.decoder_id))
}

if decoder == "" {
o.options.decoder_id = nil
} else {
o.options.decoder_id = C.CString(decoder)
}
}

// GetDecoderId returns the decoder id that should be used.
func (o *DecodingOptions) GetDecoderId() string {
if o.options.decoder_id == nil {
return ""
}

return C.GoString(o.options.decoder_id)
}

// SetChromaDownsamplingAlgorithm sets the chroma downsampling algorithm to use.
func (o *DecodingOptions) SetChromaDownsamplingAlgorithm(algorithm ChromaDownsamplingAlgorithm) {
o.options.color_conversion_options.preferred_chroma_downsampling_algorithm = uint32(algorithm)
}

// GetChromaDownsamplingAlgorithm returns the chroma downsampling algorithm to use.
func (o *DecodingOptions) GetChromaDownsamplingAlgorithm() ChromaDownsamplingAlgorithm {
return ChromaDownsamplingAlgorithm(o.options.color_conversion_options.preferred_chroma_downsampling_algorithm)
}

// SetChromaUpsamplingAlgorithm sets the chroma upsampling algorithm to use.
func (o *DecodingOptions) SetChromaUpsamplingAlgorithm(algorithm ChromaUpsamplingAlgorithm) {
o.options.color_conversion_options.preferred_chroma_upsampling_algorithm = uint32(algorithm)
}

// GetChromaUpsamplingAlgorithm returns the chroma upsampling algorithm to use.
func (o *DecodingOptions) GetChromaUpsamplingAlgorithm() ChromaUpsamplingAlgorithm {
return ChromaUpsamplingAlgorithm(o.options.color_conversion_options.preferred_chroma_upsampling_algorithm)
}

// SetOnlyUsePreferredChromaAlgorithm enforces to use the preferred algorithm.
// If set to false, libheif may also use a different algorithm if the preferred
// one is not available.
func (o *DecodingOptions) SetOnlyUsePreferredChromaAlgorithm(preferred bool) {
o.options.color_conversion_options.only_use_preferred_chroma_algorithm = convertBool[C.uchar](preferred)
}

// GetOnlyUsePreferredChromaAlgorithm returns true if only the preferred chroma algorithm should be used
func (o *DecodingOptions) GetOnlyUsePreferredChromaAlgorithm() bool {
return o.options.color_conversion_options.only_use_preferred_chroma_algorithm != 0
}
8 changes: 8 additions & 0 deletions defines.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,11 @@ const (
ChromaUpsamplingNearestNeighbor ChromaUpsamplingAlgorithm = C.heif_chroma_upsampling_nearest_neighbor
ChromaUpsamplingBilinear ChromaUpsamplingAlgorithm = C.heif_chroma_upsampling_bilinear
)

type EncoderParameterType C.enum_heif_encoder_parameter_type

const (
EncoderParameterTypeInteger EncoderParameterType = C.heif_encoder_parameter_type_integer
EncoderParameterTypeBoolean EncoderParameterType = C.heif_encoder_parameter_type_boolean
EncoderParameterTypeString EncoderParameterType = C.heif_encoder_parameter_type_string
)
136 changes: 136 additions & 0 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ package libheif
import "C"

import (
"errors"
"runtime"
"unsafe"
)

const (
// encoderParamStringSize is the maximum length of a string value that is
// returned by the GetParameter / GetParameterString functions.
encoderParamStringSize = 1024
)

// Encoder contains a libheif encoder object.
Expand Down Expand Up @@ -74,3 +82,131 @@ func (e *Encoder) SetLoggingLevel(l LoggingLevel) error {
err := C.heif_encoder_set_logging_level(e.encoder, C.int(l))
return convertHeifError(err)
}

// ListParameters returns a list of parameters this encoder supports.
func (e *Encoder) ListParameters() []EncoderParameter {
defer runtime.KeepAlive(e)

parameters := C.heif_encoder_list_parameters(e.encoder)
if parameters == nil {
return nil
}

var result []EncoderParameter
for *parameters != nil {
result = append(result, newEncoderParameter(*parameters))
parameters = nextPointer(parameters)
}
return result
}

// SetParameter sets a parameter of any type to the string value.
// Integer values are parsed from the string.
// Boolean values can be "true", "false", "1", "0".
//
// x265 encoder specific note:
// When using the x265 encoder, you may pass any of its parameters by
// prefixing the parameter name with 'x265:'. Hence, to set the 'ctu' parameter,
// you will have to set 'x265:ctu' in libheif.
// Note that there is no checking for valid parameters when using the prefix.
func (e *Encoder) SetParameter(name string, value string) error {
defer runtime.KeepAlive(e)

err := C.heif_encoder_set_parameter(e.encoder, C.CString(name), C.CString(value))
return convertHeifError(err)
}

// GetParameter returns the current value of a parameter of any type as a human
// readable string.
// The returned string is compatible with SetParameter().
func (e *Encoder) GetParameter(name string) (string, error) {
defer runtime.KeepAlive(e)

value := (*C.char)(C.malloc(encoderParamStringSize))
if value == nil {
return "", errors.New("can't allocate memory for value")
}

defer C.free(unsafe.Pointer(value))
err := C.heif_encoder_get_parameter(e.encoder, C.CString(name), value, encoderParamStringSize)
if err := convertHeifError(err); err != nil {
return "", err
}

return C.GoString(value), nil
}

// HasDefault returns true if a parameter has a default value.
func (e *Encoder) HasDefault(name string) bool {
defer runtime.KeepAlive(e)

return C.heif_encoder_has_default(e.encoder, C.CString(name)) != 0
}

// SetParameterInteger sets the integer parameter.
func (e *Encoder) SetParameterInteger(name string, value int) error {
defer runtime.KeepAlive(e)

err := C.heif_encoder_set_parameter_integer(e.encoder, C.CString(name), C.int(value))
return convertHeifError(err)
}

// GetParameterInteger returns the value of the integer parameter.
func (e *Encoder) GetParameterInteger(name string) (int, error) {
defer runtime.KeepAlive(e)

var value C.int
err := C.heif_encoder_get_parameter_integer(e.encoder, C.CString(name), &value)
if err := convertHeifError(err); err != nil {
return 0, err
}

return int(value), nil
}

// SetParameterBool sets the boolean parameter.
func (e *Encoder) SetParameterBool(name string, value bool) error {
defer runtime.KeepAlive(e)

err := C.heif_encoder_set_parameter_boolean(e.encoder, C.CString(name), convertBool[C.int](value))
return convertHeifError(err)
}

// GetParameterBool returns the value of the boolean parameter.
func (e *Encoder) GetParameterBool(name string) (bool, error) {
defer runtime.KeepAlive(e)

var value C.int
err := C.heif_encoder_get_parameter_boolean(e.encoder, C.CString(name), &value)
if err := convertHeifError(err); err != nil {
return false, err
}

return value != 0, nil
}

// SetParameterString sets the string parameter.
func (e *Encoder) SetParameterString(name string, value string) error {
defer runtime.KeepAlive(e)

err := C.heif_encoder_set_parameter_string(e.encoder, C.CString(name), C.CString(value))
return convertHeifError(err)
}

// GetParameterString returns the value of the string parameter.
func (e *Encoder) GetParameterString(name string) (string, error) {
defer runtime.KeepAlive(e)

value := (*C.char)(C.malloc(encoderParamStringSize))
if value == nil {
return "", errors.New("can't allocate memory for value")
}

defer C.free(unsafe.Pointer(value))
err := C.heif_encoder_get_parameter_string(e.encoder, C.CString(name), value, encoderParamStringSize)
if err := convertHeifError(err); err != nil {
return "", err
}

return C.GoString(value), nil
}
Loading

0 comments on commit bb61398

Please sign in to comment.