fix: move orientation FFI bindings out of generated file; fix bool.toNSNumber

This commit is contained in:
JohnE 2026-02-19 23:29:18 -08:00
parent 7edaf83d04
commit a8ab7c4217
2 changed files with 99 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import 'dart:typed_data';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
import 'package:objective_c/objective_c.dart'; import 'package:objective_c/objective_c.dart';
import 'package:platform_image_converter/src/darwin/bindings.g.dart'; import 'package:platform_image_converter/src/darwin/bindings.g.dart';
import 'package:platform_image_converter/src/darwin/orientation_bindings.dart';
import 'package:platform_image_converter/src/image_conversion_exception.dart'; import 'package:platform_image_converter/src/image_conversion_exception.dart';
import 'package:platform_image_converter/src/image_converter_platform_interface.dart'; import 'package:platform_image_converter/src/image_converter_platform_interface.dart';
import 'package:platform_image_converter/src/output_format.dart'; import 'package:platform_image_converter/src/output_format.dart';

View File

@ -0,0 +1,98 @@
// Hand-written FFI bindings for EXIF/CGImageSource orientation APIs.
//
// These supplement the auto-generated bindings.g.dart without modifying it.
// They bind the CoreFoundation / ImageIO symbols needed to read and apply
// the EXIF orientation tag when converting images on Darwin (iOS/macOS).
//
// Relevant Apple documentation:
// - CGImageSourceCopyPropertiesAtIndex:
// https://developer.apple.com/documentation/imageio/cgimagesourcecopypropertiesatindex
// - CGImageSourceCreateThumbnailAtIndex:
// https://developer.apple.com/documentation/imageio/cgimagesourcecreatethumbnailatindex
// - kCGImagePropertyOrientation:
// https://developer.apple.com/documentation/imageio/kcgimagepropertyorientation
// - kCGImageSourceCreateThumbnailWithTransform:
// https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailwithtransform
// ignore_for_file: type=lint, non_constant_identifier_names
import 'dart:ffi' as ffi;
import 'package:objective_c/objective_c.dart' as objc;
import 'bindings.g.dart';
// CGImageSource properties
/// Copies the properties dictionary for the image at [index] inside [isrc].
///
/// Returns a retained `CFDictionaryRef` the caller must `CFRelease` it.
/// Returns `nullptr` if the source or image is invalid.
@ffi.Native<CFDictionaryRef Function(CGImageSourceRef, ffi.Size, CFDictionaryRef)>()
external CFDictionaryRef CGImageSourceCopyPropertiesAtIndex(
CGImageSourceRef isrc,
int index,
CFDictionaryRef options,
);
/// Creates an orientation-corrected image for the entry at [index].
///
/// With `kCGImageSourceCreateThumbnailWithTransform = kCFBooleanTrue` in
/// [options], ImageIO bakes the EXIF rotation and/or flip into the returned
/// pixel data, giving correctly-oriented pixels for any orientation value.
///
/// Returns a retained `CGImageRef` the caller must `CFRelease` it.
@ffi.Native<CGImageRef Function(CGImageSourceRef, ffi.Size, CFDictionaryRef)>()
external CGImageRef CGImageSourceCreateThumbnailAtIndex(
CGImageSourceRef isrc,
int index,
CFDictionaryRef options,
);
// CFDictionary / CFNumber lookup
/// Returns the value associated with [key] in [theDict], or `nullptr`.
///
/// The returned pointer is not retained do not `CFRelease` it.
@ffi.Native<ffi.Pointer<ffi.Void> Function(CFDictionaryRef, ffi.Pointer<ffi.Void>)>()
external ffi.Pointer<ffi.Void> CFDictionaryGetValue(
CFDictionaryRef theDict,
ffi.Pointer<ffi.Void> key,
);
/// Extracts the numeric value from a `CFNumber` into a native Dart pointer.
///
/// [theType] selects the C numeric type; 9 = `kCFNumberSInt32Type` (int32).
/// Returns `true` on success.
@ffi.Native<ffi.Bool Function(ffi.Pointer<ffi.Void>, ffi.Int32, ffi.Pointer<ffi.Void>)>()
external bool CFNumberGetValue(
ffi.Pointer<ffi.Void> number,
int theType,
ffi.Pointer<ffi.Void> valuePtr,
);
// ImageIO option keys
/// Key: EXIF/CGImage orientation tag in CGImageSource properties dicts.
///
/// Value is a `CFNumberRef` (int32) matching `CGImagePropertyOrientation`:
/// 1=Up, 2=UpMirrored, 3=Down, 4=DownMirrored,
/// 5=LeftMirrored, 6=Right, 7=RightMirrored, 8=Left.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImagePropertyOrientation;
/// Key: when `kCFBooleanTrue`, creates a thumbnail from the full image even
/// when no embedded thumbnail is present.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImageSourceCreateThumbnailFromImageIfAbsent;
/// Key: when `kCFBooleanTrue`, rotates/flips the thumbnail to match the EXIF
/// orientation tag, producing pixel-correct upright image data.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImageSourceCreateThumbnailWithTransform;
/// Key: maximum pixel size (longest edge) for the thumbnail.
///
/// Set this to the source image's longest edge to get full-resolution output
/// from `CGImageSourceCreateThumbnailAtIndex`.
@ffi.Native<ffi.Pointer<objc.CFString>>()
external ffi.Pointer<objc.CFString> kCGImageSourceThumbnailMaxPixelSize;