From 6e91a0ebba705ec77ce074002b90fd2736e62cb8 Mon Sep 17 00:00:00 2001 From: Yury Date: Wed, 30 Oct 2024 11:23:56 +0300 Subject: [PATCH] cg image props example --- cidre/examples/cg-image-props/main.rs | 26 +++ cidre/src/cg/image/source.rs | 67 +++++++- cidre/src/cg/image_properties.rs | 237 +++++++++++++++++++++++++- 3 files changed, 326 insertions(+), 4 deletions(-) create mode 100644 cidre/examples/cg-image-props/main.rs diff --git a/cidre/examples/cg-image-props/main.rs b/cidre/examples/cg-image-props/main.rs new file mode 100644 index 00000000..6dbb528e --- /dev/null +++ b/cidre/examples/cg-image-props/main.rs @@ -0,0 +1,26 @@ +use std::path::PathBuf; + +use cidre::{cf, cg}; +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + /// Image file path to analyse + path: PathBuf, +} + +fn main() { + let args = Args::parse(); + let url = cf::Url::with_path(&args.path, false).unwrap(); + let src = cg::ImageSrc::with_url(&url, None).unwrap(); + let count = src.count(); + println!("images count: {count}"); + let props = src.props(None).unwrap(); + props.show(); + + for i in 0..count { + let img = src.image_at(i, None).unwrap(); + img.show(); + } +} diff --git a/cidre/src/cg/image/source.rs b/cidre/src/cg/image/source.rs index 25d7ce03..96bb4d15 100644 --- a/cidre/src/cg/image/source.rs +++ b/cidre/src/cg/image/source.rs @@ -1,4 +1,4 @@ -use crate::{arc, cf, define_cf_type}; +use crate::{arc, cf, cg, define_cf_type}; #[repr(i32)] pub enum Status { @@ -24,11 +24,13 @@ impl Src { unsafe { CGImageSourceCopyTypeIdentifiers() } } + #[doc(alias = "CGImageSourceCreateWithData")] #[inline] pub fn with_data(data: &cf::Data, options: Option<&cf::Dictionary>) -> Option> { unsafe { CGImageSourceCreateWithData(data, options) } } + #[doc(alias = "CGImageSourceCreateWithURL")] #[inline] pub fn with_url(url: &cf::Url, options: Option<&cf::Dictionary>) -> Option> { unsafe { CGImageSourceCreateWithURL(url, options) } @@ -40,19 +42,57 @@ impl Src { } /// Return the number of images (not including thumbnails) in the image source + #[doc(alias = "CGImageSourceGetCount")] #[inline] pub fn count(&self) -> usize { unsafe { CGImageSourceGetCount(self) } } + #[doc(alias = "CGImageSourceGetStatus")] #[inline] pub fn status(&self) -> Status { unsafe { CGImageSourceGetStatus(self) } } + + #[doc(alias = "CGImageSourceCopyProperties")] + #[inline] + pub fn props(&self, options: Option<&cf::Dictionary>) -> Option> { + unsafe { CGImageSourceCopyProperties(self, options) } + } + + #[doc(alias = "CGImageSourceCopyPropertiesAtIndex")] + #[inline] + pub fn props_at( + &self, + index: usize, + options: Option<&cf::Dictionary>, + ) -> Option> { + unsafe { CGImageSourceCopyPropertiesAtIndex(self, index, options) } + } + + #[doc(alias = "CGImageSourceCreateImageAtIndex")] + #[inline] + pub fn image_at( + &self, + index: usize, + options: Option<&cf::Dictionary>, + ) -> Option> { + unsafe { CGImageSourceCreateImageAtIndex(self, index, options) } + } + + #[doc(alias = "CGImageSourceCreateThumbnailAtIndex")] + #[inline] + pub fn thumbnail_at( + &self, + index: usize, + options: Option<&cf::Dictionary>, + ) -> Option> { + unsafe { CGImageSourceCreateThumbnailAtIndex(self, index, options) } + } } #[link(name = "ImageIO", kind = "framework")] -extern "C" { +extern "C-unwind" { fn CGImageSourceGetTypeID() -> cf::TypeId; fn CGImageSourceCopyTypeIdentifiers() -> arc::R>; @@ -71,6 +111,29 @@ extern "C" { fn CGImageSourceGetCount(isrc: &Src) -> usize; fn CGImageSourceGetStatus(isrc: &Src) -> Status; + + fn CGImageSourceCopyProperties( + isrc: &Src, + options: Option<&cf::Dictionary>, + ) -> Option>; + + fn CGImageSourceCopyPropertiesAtIndex( + isrc: &Src, + index: usize, + options: Option<&cf::Dictionary>, + ) -> Option>; + + fn CGImageSourceCreateImageAtIndex( + isrc: &Src, + index: usize, + options: Option<&cf::Dictionary>, + ) -> Option>; + + fn CGImageSourceCreateThumbnailAtIndex( + isrc: &Src, + index: usize, + options: Option<&cf::Dictionary>, + ) -> Option>; } #[cfg(test)] diff --git a/cidre/src/cg/image_properties.rs b/cidre/src/cg/image_properties.rs index 77ea34e1..5e255431 100644 --- a/cidre/src/cg/image_properties.rs +++ b/cidre/src/cg/image_properties.rs @@ -1,30 +1,37 @@ -// TODO: It is actually belongs to ImageIO - +#[doc(alias = "kCGImagePropertyOrientation")] #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[repr(u32)] pub enum Orientation { /// 0th row at top, 0th column on left - default orientation + #[doc(alias = "kCGImagePropertyOrientationUp")] Up = 1, /// 0th row at top, 0th column on right - horizontal flip + #[doc(alias = "kCGImagePropertyOrientationUpMirrored")] UpMirrored, /// 0th row at bottom, 0th column on right - 180 deg rotation + #[doc(alias = "kCGImagePropertyOrientationDown")] Down, /// 0th row at bottom, 0th column on left - vertical flip + #[doc(alias = "kCGImagePropertyOrientationDownMirrored")] DownMirrored, /// 0th row on left, 0th column at top + #[doc(alias = "kCGImagePropertyOrientationLeftMirrored")] LeftMirrored, /// 0th row on right, 0th column at top - 90 deg CW + #[doc(alias = "kCGImagePropertyOrientationRight")] Right, /// 0th row on right, 0th column on bottom + #[doc(alias = "kCGImagePropertyOrientationRightMirrored")] RightMirrored, /// 0th row on left, 0th column at bottom - 90 deg CCW + #[doc(alias = "kCGImagePropertyOrientationLeft")] Left, } @@ -33,3 +40,229 @@ impl Default for Orientation { Self::Up } } + +/// Properties that, if returned by CGImageSourceCopyProperties or +/// CGImageSourceCopyPropertiesAtIndex, contain a dictionary of file-format +/// or metadata-format specific key-values. +pub mod dictionary { + use crate::cf; + + #[doc(alias = "kCGImagePropertyTIFFDictionary")] + #[inline] + pub fn tiff() -> &'static cf::String { + unsafe { kCGImagePropertyTIFFDictionary } + } + + #[doc(alias = "kCGImagePropertyGIFDictionary")] + #[inline] + pub fn gif() -> &'static cf::String { + unsafe { kCGImagePropertyGIFDictionary } + } + + #[doc(alias = "kCGImagePropertyHEIFDictionary")] + #[inline] + pub fn heif() -> &'static cf::String { + unsafe { kCGImagePropertyHEIFDictionary } + } + + #[doc(alias = "kCGImagePropertyHEICSDictionary")] + #[inline] + pub fn heic() -> &'static cf::String { + unsafe { kCGImagePropertyHEICSDictionary } + } + + #[doc(alias = "kCGImagePropertyExifDictionary")] + #[inline] + pub fn exif() -> &'static cf::String { + unsafe { kCGImagePropertyExifDictionary } + } + + #[doc(alias = "kCGImagePropertyPNGDictionary")] + #[inline] + pub fn png() -> &'static cf::String { + unsafe { kCGImagePropertyPNGDictionary } + } + + /// A dictionary of key-value pairs for an image that has Global Positioning System (GPS) information. + #[doc(alias = "kCGImagePropertyGPSDictionary")] + #[inline] + pub fn gps() -> &'static cf::String { + unsafe { kCGImagePropertyGPSDictionary } + } + + #[doc(alias = "kCGImagePropertyRawDictionary")] + #[inline] + pub fn raw() -> &'static cf::String { + unsafe { kCGImagePropertyRawDictionary } + } + + #[doc(alias = "kCGImagePropertyCIFFDictionary")] + #[inline] + pub fn ciff() -> &'static cf::String { + unsafe { kCGImagePropertyCIFFDictionary } + } + + #[doc(alias = "kCGImagePropertyWebPDictionary")] + pub fn webp() -> &'static cf::String { + unsafe { kCGImagePropertyWebPDictionary } + } + + #[link(name = "ImageIO", kind = "framework")] + extern "C" { + static kCGImagePropertyTIFFDictionary: &'static cf::String; + static kCGImagePropertyGIFDictionary: &'static cf::String; + static kCGImagePropertyHEIFDictionary: &'static cf::String; + static kCGImagePropertyHEICSDictionary: &'static cf::String; + static kCGImagePropertyExifDictionary: &'static cf::String; + static kCGImagePropertyPNGDictionary: &'static cf::String; + static kCGImagePropertyGPSDictionary: &'static cf::String; + static kCGImagePropertyRawDictionary: &'static cf::String; + static kCGImagePropertyCIFFDictionary: &'static cf::String; + // ... + + static kCGImagePropertyWebPDictionary: &'static cf::String; + } +} + +pub mod webp_keys { + use crate::cf; + + /// The number of times to play the sequence. + #[doc(alias = "kCGImagePropertyWebPLoopCount")] + #[inline] + pub fn loop_count() -> &'static cf::String { + unsafe { kCGImagePropertyWebPLoopCount } + } + + /// The number of seconds to wait before displaying the next image in the sequence. + /// + /// The value of this key is a cf::Number with a floating-point value. The value of this key is never less than + /// 100 millseconds, and the system adjusts values less than that amount to 100 milliseconds, as needed. + /// See kCGImagePropertyGIFUnclampedDelayTime. + #[doc(alias = "kCGImagePropertyWebPDelayTime")] + #[inline] + pub fn deplay_time() -> &'static cf::String { + unsafe { kCGImagePropertyWebPDelayTime } + } + + /// The unadjusted number of seconds to wait before displaying the next image in the sequence. + /// + /// The value of this key is a cf::Number with a floating-point value. + #[doc(alias = "kCGImagePropertyWebPUnclampedDelayTime")] + #[inline] + pub fn unclamped_delay_time() -> &'static cf::String { + unsafe { kCGImagePropertyWebPUnclampedDelayTime } + } + + /// An array of dictionaries that contain timing information for the image sequence. + /// + /// The value of this property is a cf::Array. Each cf::Dictionary in the array contains timing information about + /// an image in the sequence. + #[doc(alias = "kCGImagePropertyWebPFrameInfoArray")] + #[inline] + pub fn frame_info_array() -> &'static cf::String { + unsafe { kCGImagePropertyWebPFrameInfoArray } + } + + /// The width of the main image, in pixels. + #[doc(alias = "kCGImagePropertyWebPCanvasPixelWidth")] + #[inline] + pub fn canvas_pixel_width() -> &'static cf::String { + unsafe { kCGImagePropertyWebPCanvasPixelWidth } + } + + /// The height of the main image, in pixels. + #[doc(alias = "kCGImagePropertyWebPCanvasPixelHeight")] + #[inline] + pub fn canvas_pixel_height() -> &'static cf::String { + unsafe { kCGImagePropertyWebPCanvasPixelHeight } + } + + #[link(name = "ImageIO", kind = "framework")] + extern "C" { + static kCGImagePropertyWebPLoopCount: &'static cf::String; + static kCGImagePropertyWebPDelayTime: &'static cf::String; + static kCGImagePropertyWebPUnclampedDelayTime: &'static cf::String; + static kCGImagePropertyWebPFrameInfoArray: &'static cf::String; + static kCGImagePropertyWebPCanvasPixelWidth: &'static cf::String; + static kCGImagePropertyWebPCanvasPixelHeight: &'static cf::String; + } +} + +pub mod gif_keys { + use crate::cf; + + /// The number of times to repeat an animated sequence. + #[doc(alias = "kCGImagePropertyGIFLoopCount")] + #[inline] + pub fn loop_count() -> &'static cf::String { + unsafe { kCGImagePropertyGIFLoopCount } + } + + /// The number of seconds to wait before displaying the next image in an animated sequence, + /// clamped to a minimum of 100 milliseconds. + #[doc(alias = "kCGImagePropertyGIFDelayTime")] + #[inline] + pub fn delay_time() -> &'static cf::String { + unsafe { kCGImagePropertyGIFDelayTime } + } + + /// The image color map. + #[doc(alias = "kCGImagePropertyGIFImageColorMap")] + #[inline] + pub fn image_color_map() -> &'static cf::String { + unsafe { kCGImagePropertyGIFImageColorMap } + } + + /// A Boolean value that indicates whether the GIF has a global color map. + /// + /// The value of this key is a cf::Boolean. + #[doc(alias = "kCGImagePropertyGIFHasGlobalColorMap")] + #[inline] + pub fn has_global_color_map() -> &'static cf::String { + unsafe { kCGImagePropertyGIFHasGlobalColorMap } + } + + /// The number of seconds to wait before displaying the next image in an animated sequence. + #[doc(alias = "kCGImagePropertyGIFUnclampedDelayTime")] + #[inline] + pub fn unclamped_delay_time() -> &'static cf::String { + unsafe { kCGImagePropertyGIFUnclampedDelayTime } + } + + /// The width of the main image, in pixels. + #[doc(alias = "kCGImagePropertyGIFCanvasPixelWidth")] + #[inline] + pub fn canvas_pixel_width() -> &'static cf::String { + unsafe { kCGImagePropertyGIFCanvasPixelWidth } + } + + /// The height of the main image, in pixels. + #[doc(alias = "kCGImagePropertyGIFCanvasPixelHeight")] + #[inline] + pub fn canvas_pixel_height() -> &'static cf::String { + unsafe { kCGImagePropertyGIFCanvasPixelHeight } + } + + /// An array of dictionaries that contain timing information for the image sequence. + /// + /// The value of this property is a cf::Array. Each cf::Dictionary in the array contains timing information + /// about an image in the sequence. + #[doc(alias = "kCGImagePropertyGIFFrameInfoArray")] + #[inline] + pub fn frame_info_array() -> &'static cf::String { + unsafe { kCGImagePropertyGIFFrameInfoArray } + } + + #[link(name = "ImageIO", kind = "framework")] + extern "C" { + static kCGImagePropertyGIFLoopCount: &'static cf::String; + static kCGImagePropertyGIFDelayTime: &'static cf::String; + static kCGImagePropertyGIFImageColorMap: &'static cf::String; + static kCGImagePropertyGIFHasGlobalColorMap: &'static cf::String; + static kCGImagePropertyGIFUnclampedDelayTime: &'static cf::String; + static kCGImagePropertyGIFCanvasPixelWidth: &'static cf::String; + static kCGImagePropertyGIFCanvasPixelHeight: &'static cf::String; + static kCGImagePropertyGIFFrameInfoArray: &'static cf::String; + } +}