1

I want to encode image into webp in dart. I created libwebp.dll file (sources https://github.com/jacklicn/libwebp)

Now I have to use this library for encoding process:

import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';

typedef NativeEncodeFunc =
    Uint64 Function(
      Pointer<Uint8> rgb,
      Int32 width,
      Int32 height,
      Int32 stride,
      Float quality_factor,
      Pointer<Pointer<Uint8>> output,
    );

typedef DartEncodeFunc =
    int Function(
      Pointer<Uint8> rgb,
      int width,
      int height,
      int stride,
      double quality_factor,
      Pointer<Pointer<Uint8>> output,
    );

typedef NativeFreeFunc = Void Function(Pointer<Uint8>);
typedef DartFreeFunc = void Function(Pointer<Uint8>);

class WebPFFI {
  late final DynamicLibrary _lib;
  late final DartEncodeFunc _encode;
  late final DartFreeFunc _free;

  WebPFFI() {
    final path = _getLibraryPath();
    try {
      _lib = DynamicLibrary.open(path);
      _encode = _lib
          .lookup<NativeFunction<NativeEncodeFunc>>('WebPEncodeRGB')
          .asFunction();
      _free = _lib
          .lookup<NativeFunction<NativeFreeFunc>>('WebPFree')
          .asFunction();
    } catch (e) {
      throw Exception('Failed to load WebP library ($path): $e');
    }
  }

  Uint8List encode(Uint8List rgb, int width, int height, int quality) {
    // size check
    if (width <= 0 || height <= 0) {
      throw ArgumentError('Invalid dimensions: $width x $height');
    }
    if (quality < 0 || quality > 100) {
      throw ArgumentError('Quality must be between 0 and 100');
    }

    final rgbPtr = malloc<Uint8>(rgb.length);
    rgbPtr.asTypedList(rgb.length).setAll(0, rgb);
    final outputPtr = calloc<Pointer<Uint8>>();

    try {
      // WEBP_EXTERN(size_t) WebPEncodeRGB(const uint8_t* rgb,
      //                        int width, int height, int stride,
      //                        float quality_factor, uint8_t**
      final resultSize = _encode(
        rgbPtr,
        width,
        height,
        width * 3, // stride -> RGB
        quality.toDouble(),
        outputPtr,
      );

      if (resultSize == 0) {
        throw Exception('WebP encoding failed');
      }

      final result = outputPtr.value.asTypedList(resultSize);
      return Uint8List.fromList(result);
    } finally {
      if (outputPtr.value != nullptr) {
        _free(outputPtr.value);
      }
      calloc.free(outputPtr);
      malloc.free(rgbPtr);
    }
  }

  String _getLibraryPath() {
    if (Platform.isWindows) return 'windows/libwebp.dll';
    if (Platform.isLinux) return 'linux/libwebp.so';
    if (Platform.isMacOS) return 'macos/libwebp.dylib';
    if (Platform.isAndroid) return 'android/libwebp.soso';
    if (Platform.isIOS) return 'ios/libwebp.soso';
    if (kIsWeb) return 'web/libwebp.idk what should I use here';

    throw UnsupportedError('_getLibraryPath not supported for WebP');
  }
}

This function causes whole app crash without any exception: final resultSize = _encode( rgbPtr, width, height, width * 3, // stride -> RGB quality.toDouble(), outputPtr, );

_encode is not null, _lib is not null too. Where is a bug? How to encode image into webp?

Update:

1) dumpbin /EXPORTS libwebp.dll | findstr "WebPEncodeRGB"

     30   1D 00033A60 WebPEncodeRGB
     31   1E 00033AA0 WebPEncodeRGBA

2) Doesn't throw an exception:

if (_lib.providesSymbol('WebPEncodeRGB') == false) {
        throw Exception('Symbol WebPEncodeRGB not found in library');
      }

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.