Auto merge of #80 - snapview:master, r=jdm

Introduces CGWindowList API for window capturing and improves `CGImage` and `CGContext`

Initially I just wanted to rewrite https://github.com/servo/core-graphics-rs/pull/52 as it seems that the author is not interested in changing his pull request. So I just implemented `CGImage` bindings, but today another pull request has been merged (https://github.com/servo/core-graphics-rs/pull/79) which does exactly the same.

This pull request still improves some things in regards to `CGImage`, the most important ones are:
* Now `CGImage` uses `CGImageRelease` instead of `CFRelease` (it's a much safer to use `CGImageRelease` here, as it does not crash if you pass a `NULL` image reference to it).
* Now you can retrieve bytes from `CGImage` (uses data provider and copies the bytes from it).

Also several improvements in `CGContext`:
* Added a function `create_image()`, which allows you to create an image out of existing `CGContext`.
* Now it is possible to specify a data pointer passed as a first parameter to the `CGBitmapContextCreate()` upon `CGContext` creation -- very important thing when you deal with images as it allows you to specify your own buffer instead of allocating and copying an additional one from the context (tested it on my machine, it gave me 18.46% of performance boost).

And of course this pull requests adds `CGWindowListCreateImage()` and related things, so now window capturing is possible.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/core-graphics-rs/80)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo
2017-04-24 09:49:03 -05:00
committed by GitHub
6 changed files with 93 additions and 12 deletions
+16 -5
View File
@@ -10,12 +10,12 @@
use base::CGFloat;
use color_space::{CGColorSpace, CGColorSpaceRef};
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use image::{CGImage,CGImageRef};
use libc::{c_void, size_t};
use std::mem;
use std::ptr;
use std::slice;
use geometry::CGRect;
use image::{CGImage, CGImageRef};
#[repr(C)]
pub enum CGTextDrawingMode {
@@ -88,7 +88,8 @@ impl TCFType<CGContextRef> for CGContext {
}
impl CGContext {
pub fn create_bitmap_context(width: size_t,
pub fn create_bitmap_context(data: Option<*mut c_void>,
width: size_t,
height: size_t,
bits_per_component: size_t,
bytes_per_row: size_t,
@@ -96,7 +97,7 @@ impl CGContext {
bitmap_info: u32)
-> CGContext {
unsafe {
let result = CGBitmapContextCreate(ptr::null_mut(),
let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()),
width,
height,
bits_per_component,
@@ -199,11 +200,20 @@ impl CGContext {
}
}
pub fn draw_image(&self, rect: CGRect, image: CGImage) {
pub fn draw_image(&self, rect: CGRect, image: &CGImage) {
unsafe {
CGContextDrawImage(self.as_concrete_TypeRef(), rect, image.as_concrete_TypeRef());
}
}
pub fn create_image(&self) -> Option<CGImage> {
let image = unsafe { CGBitmapContextCreateImage(self.as_concrete_TypeRef()) };
if image != ptr::null() {
Some(unsafe { CGImage::wrap_under_create_rule(image) })
} else {
None
}
}
}
#[link(name = "ApplicationServices", kind = "framework")]
@@ -220,6 +230,7 @@ extern {
fn CGBitmapContextGetWidth(context: CGContextRef) -> size_t;
fn CGBitmapContextGetHeight(context: CGContextRef) -> size_t;
fn CGBitmapContextGetBytesPerRow(context: CGContextRef) -> size_t;
fn CGBitmapContextCreateImage(context: CGContextRef) -> CGImageRef;
fn CGContextGetTypeID() -> CFTypeID;
fn CGContextSetAllowsFontSmoothing(c: CGContextRef, allowsFontSmoothing: bool);
fn CGContextSetShouldSmoothFonts(c: CGContextRef, shouldSmoothFonts: bool);
@@ -241,6 +252,6 @@ extern {
alpha: CGFloat);
fn CGContextFillRect(context: CGContextRef,
rect: CGRect);
fn CGContextDrawImage(context: CGContextRef, rect: CGRect, image: CGImageRef);
fn CGContextDrawImage(c: CGContextRef, rect: CGRect, image: CGImageRef);
}
+7 -1
View File
@@ -8,6 +8,7 @@
// except according to those terms.
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use core_foundation::data::{CFData, CFDataRef};
use libc::{c_void, size_t, off_t};
use std::mem;
@@ -86,11 +87,16 @@ impl CGDataProvider {
TCFType::wrap_under_create_rule(result)
}
}
/// Creates a copy of the data from the underlying `CFDataProviderRef`.
pub fn copy_data(&self) -> CFData {
unsafe { CFData::wrap_under_create_rule(CGDataProviderCopyData(self.obj)) }
}
}
#[link(name = "ApplicationServices", kind = "framework")]
extern {
//fn CGDataProviderCopyData
fn CGDataProviderCopyData(provider: CGDataProviderRef) -> CFDataRef;
//fn CGDataProviderCreateDirect
//fn CGDataProviderCreateSequential
//fn CGDataProviderCreateWithCFData
+17
View File
@@ -15,6 +15,8 @@ use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};
use image::CGImageRef;
pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID = libc::uint32_t;
@@ -30,6 +32,14 @@ pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2;
pub const kCGWindowListOptionIncludingWindow: CGWindowListOption = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: CGWindowListOption = 1 << 4;
pub type CGWindowImageOption = libc::uint32_t;
pub const kCGWindowImageDefault: CGWindowImageOption = 0;
pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0;
pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1;
pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2;
pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3;
pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4;
pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent };
pub use core_foundation::array::{ CFArray, CFArrayRef };
@@ -38,6 +48,9 @@ pub use core_foundation::base::{ CFIndex, CFRelease, CFTypeRef };
#[link(name = "ApplicationServices", kind = "framework")]
extern {
pub static CGRectNull: CGRect;
pub static CGRectInfinite: CGRect;
pub fn CGMainDisplayID() -> CGDirectDisplayID;
pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
@@ -73,5 +86,9 @@ extern {
// Window Services Reference
pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;
pub fn CGWindowListCreateImage(screenBounds: CGRect,
listOptions: CGWindowListOption,
windowId: CGWindowID,
imageOptions: CGWindowImageOption) -> CGImageRef;
}
+19 -1
View File
@@ -8,6 +8,8 @@
// except according to those terms.
use base::CGFloat;
use core_foundation::base::TCFType;
use core_foundation::dictionary::CFDictionary;
pub const CG_ZERO_POINT: CGPoint = CGPoint {
x: 0.0,
@@ -70,15 +72,31 @@ impl CGRect {
ffi::CGRectInset(*self, size.width, size.height)
}
}
#[inline]
pub fn from_dict_representation(dict: &CFDictionary) -> Option<CGRect> {
let mut rect = CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(0., 0.));
let result = unsafe {
ffi::CGRectMakeWithDictionaryRepresentation(dict.as_concrete_TypeRef(), &mut rect)
};
if result == 0 {
None
} else {
Some(rect)
}
}
}
mod ffi {
use base::CGFloat;
use base::{CGFloat, boolean_t};
use geometry::CGRect;
use core_foundation::dictionary::CFDictionaryRef;
#[link(name = "ApplicationServices", kind = "framework")]
extern {
pub fn CGRectInset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect;
pub fn CGRectMakeWithDictionaryRepresentation(dict: CFDictionaryRef,
rect: *mut CGRect) -> boolean_t;
}
}
+31 -3
View File
@@ -1,6 +1,9 @@
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use core_foundation::base::{CFRetain, CFTypeID, CFTypeRef, TCFType};
use core_foundation::data::CFData;
use color_space::{CGColorSpace, CGColorSpaceRef};
use libc::{size_t};
use data_provider::{CGDataProvider, CGDataProviderRef};
use libc::size_t;
use std::ops::Deref;
use std::mem;
#[repr(C)]
@@ -36,7 +39,7 @@ pub struct CGImage {
impl Drop for CGImage {
fn drop(&mut self) {
unsafe {
CFRelease(self.as_CFTypeRef())
CGImageRelease(self.as_concrete_TypeRef())
}
}
}
@@ -49,6 +52,8 @@ impl Clone for CGImage {
}
}
// TODO: Replace all this stuff by simply using:
// impl_TCFType!(CGImage, CGImageRef, CGImageGetTypeID);
impl TCFType<CGImageRef> for CGImage {
#[inline]
fn as_concrete_TypeRef(&self) -> CGImageRef {
@@ -119,6 +124,24 @@ impl CGImage {
TCFType::wrap_under_get_rule(CGImageGetColorSpace(self.as_concrete_TypeRef()))
}
}
/// Returns the raw image bytes wrapped in `CFData`. Note, the returned `CFData` owns the
/// underlying buffer.
pub fn data(&self) -> CFData {
let data_provider = unsafe {
CGDataProvider::wrap_under_get_rule(CGImageGetDataProvider(self.as_concrete_TypeRef()))
};
data_provider.copy_data()
}
}
impl Deref for CGImage {
type Target = CGImageRef;
#[inline]
fn deref(&self) -> &CGImageRef {
&self.obj
}
}
#[link(name = "ApplicationServices", kind = "framework")]
@@ -130,4 +153,9 @@ extern {
fn CGImageGetBitsPerPixel(image: CGImageRef) -> size_t;
fn CGImageGetBytesPerRow(image: CGImageRef) -> size_t;
fn CGImageGetColorSpace(image: CGImageRef) -> CGColorSpaceRef;
fn CGImageGetDataProvider(image: CGImageRef) -> CGDataProviderRef;
fn CGImageRelease(image: CGImageRef);
//fn CGImageGetAlphaInfo(image: CGImageRef) -> CGImageAlphaInfo;
//fn CGImageCreateCopyWithColorSpace(image: CGImageRef, space: CGColorSpaceRef) -> CGImageRef
}
+3 -2
View File
@@ -8,6 +8,7 @@
// except according to those terms.
extern crate libc;
#[macro_use]
extern crate core_foundation;
#[macro_use]
@@ -19,8 +20,8 @@ pub mod context;
pub mod data_provider;
pub mod display;
pub mod event;
pub mod event_source;
pub mod event_source;
pub mod font;
pub mod geometry;
pub mod image;
pub mod private;
pub mod image;