-
Notifications
You must be signed in to change notification settings - Fork 133
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c1c76f9
commit eae9d0c
Showing
13 changed files
with
833 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
use crate::{DP_AclState, DP_acl_state_free, DP_acl_state_new}; | ||
|
||
pub struct AclState { | ||
acls: *mut DP_AclState, | ||
} | ||
|
||
impl AclState { | ||
pub fn new() -> Self { | ||
let acls = unsafe { DP_acl_state_new() }; | ||
AclState { acls } | ||
} | ||
|
||
pub fn as_ptr(&mut self) -> *mut DP_AclState { | ||
self.acls | ||
} | ||
} | ||
|
||
impl Drop for AclState { | ||
fn drop(&mut self) { | ||
unsafe { DP_acl_state_free(self.acls) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
use crate::{DP_DrawContext, DP_draw_context_free, DP_draw_context_new}; | ||
|
||
pub struct DrawContext { | ||
dc: *mut DP_DrawContext, | ||
} | ||
|
||
impl DrawContext { | ||
pub fn new() -> Self { | ||
let dc = unsafe { DP_draw_context_new() }; | ||
DrawContext { dc } | ||
} | ||
|
||
pub fn as_ptr(&mut self) -> *mut DP_DrawContext { | ||
self.dc | ||
} | ||
} | ||
|
||
impl Drop for DrawContext { | ||
fn drop(&mut self) { | ||
unsafe { DP_draw_context_free(self.dc) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
use core::slice; | ||
use std::{ | ||
ffi::{c_int, CString, NulError}, | ||
io::{self}, | ||
mem::size_of, | ||
num::TryFromIntError, | ||
ptr::{self, copy_nonoverlapping}, | ||
}; | ||
|
||
use crate::{ | ||
dp_error, DP_Image, DP_Output, DP_Pixel8, DP_Quad, DP_file_output_new_from_path, DP_image_free, | ||
DP_image_height, DP_image_new, DP_image_pixels, DP_image_transform_pixels, DP_image_width, | ||
DP_image_write_jpeg, DP_image_write_png, DP_output_free, DP_MSG_TRANSFORM_REGION_MODE_BILINEAR, | ||
}; | ||
|
||
use super::DrawContext; | ||
|
||
pub struct Image { | ||
image: *mut DP_Image, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct ImageError { | ||
pub message: String, | ||
} | ||
|
||
impl ImageError { | ||
fn from_dp_error() -> Self { | ||
Self { | ||
message: dp_error(), | ||
} | ||
} | ||
} | ||
|
||
impl From<&str> for ImageError { | ||
fn from(value: &str) -> Self { | ||
Self { | ||
message: value.to_owned(), | ||
} | ||
} | ||
} | ||
|
||
impl From<TryFromIntError> for ImageError { | ||
fn from(value: TryFromIntError) -> Self { | ||
Self { | ||
message: value.to_string(), | ||
} | ||
} | ||
} | ||
|
||
impl From<NulError> for ImageError { | ||
fn from(value: NulError) -> Self { | ||
Self { | ||
message: value.to_string(), | ||
} | ||
} | ||
} | ||
|
||
impl Image { | ||
pub fn new(width: usize, height: usize) -> Result<Self, ImageError> { | ||
if width > 0 && height > 0 { | ||
let w = c_int::try_from(width)?; | ||
let h = c_int::try_from(height)?; | ||
let image = unsafe { DP_image_new(w, h) }; | ||
Ok(Self { image }) | ||
} else { | ||
Err(ImageError::from("Empty image")) | ||
} | ||
} | ||
|
||
pub fn new_from_pixels( | ||
width: usize, | ||
height: usize, | ||
pixels: &[u32], | ||
) -> Result<Self, ImageError> { | ||
let count = width * height; | ||
if pixels.len() >= count { | ||
let img = Self::new(width, height)?; | ||
unsafe { | ||
copy_nonoverlapping( | ||
pixels.as_ptr(), | ||
DP_image_pixels(img.image).cast::<u32>(), | ||
count, | ||
); | ||
} | ||
Ok(img) | ||
} else { | ||
Err(ImageError::from("Not enough pixels")) | ||
} | ||
} | ||
|
||
pub fn new_from_pixels_scaled( | ||
width: usize, | ||
height: usize, | ||
pixels: &[u32], | ||
scale_width: usize, | ||
scale_height: usize, | ||
dc: &mut DrawContext, | ||
) -> Result<Self, ImageError> { | ||
if width == 0 || height == 0 { | ||
return Err(ImageError::from("Empty source image")); | ||
} | ||
|
||
if scale_width == 0 || scale_height == 0 { | ||
return Err(ImageError::from("Empty target image")); | ||
} | ||
|
||
let count = width * height; | ||
if pixels.len() < count { | ||
return Err(ImageError::from("Not enough pixels")); | ||
} | ||
|
||
let right = c_int::try_from(scale_width - 1)?; | ||
let bottom = c_int::try_from(scale_height - 1)?; | ||
let dst_quad = DP_Quad { | ||
x1: 0, | ||
y1: 0, | ||
x2: right, | ||
y2: 0, | ||
x3: right, | ||
y3: bottom, | ||
x4: 0, | ||
y4: bottom, | ||
}; | ||
|
||
let image = unsafe { | ||
DP_image_transform_pixels( | ||
c_int::try_from(width)?, | ||
c_int::try_from(height)?, | ||
pixels.as_ptr().cast(), | ||
dc.as_ptr(), | ||
&dst_quad, | ||
DP_MSG_TRANSFORM_REGION_MODE_BILINEAR as i32, | ||
ptr::null_mut(), | ||
ptr::null_mut(), | ||
) | ||
}; | ||
|
||
if image.is_null() { | ||
Err(ImageError::from_dp_error()) | ||
} else { | ||
Ok(Image { image }) | ||
} | ||
} | ||
|
||
pub fn width(&self) -> usize { | ||
unsafe { DP_image_width(self.image) as usize } | ||
} | ||
|
||
pub fn height(&self) -> usize { | ||
unsafe { DP_image_height(self.image) as usize } | ||
} | ||
|
||
pub fn dump(&self, writer: &mut dyn io::Write) -> io::Result<()> { | ||
let pixels = unsafe { DP_image_pixels(self.image) }; | ||
let size = self.width() * self.height() * size_of::<u32>(); | ||
writer.write_all(unsafe { slice::from_raw_parts(pixels.cast::<u8>(), size) }) | ||
} | ||
|
||
pub fn write_png(&self, path: &str) -> Result<(), ImageError> { | ||
self.write(path, DP_image_write_png) | ||
} | ||
|
||
pub fn write_jpeg(&self, path: &str) -> Result<(), ImageError> { | ||
self.write(path, DP_image_write_jpeg) | ||
} | ||
|
||
fn write( | ||
&self, | ||
path: &str, | ||
func: unsafe extern "C" fn(*mut DP_Image, *mut DP_Output) -> bool, | ||
) -> Result<(), ImageError> { | ||
let cpath = CString::new(path)?; | ||
let output = unsafe { DP_file_output_new_from_path(cpath.as_ptr()) }; | ||
if output.is_null() { | ||
return Err(ImageError::from_dp_error()); | ||
} | ||
let result = match unsafe { func(self.image, output) } { | ||
true => Ok(()), | ||
false => Err(ImageError::from_dp_error()), | ||
}; | ||
unsafe { DP_output_free(output) }; | ||
result | ||
} | ||
|
||
pub fn fade_to_white(&mut self, src: &Image, opacity: u8) -> Result<(), ImageError> { | ||
let w = self.width(); | ||
let h = self.height(); | ||
if w != src.width() || h != src.height() { | ||
return Err(ImageError::from("Mismatched dimensions")); | ||
} | ||
|
||
let count = w * h; | ||
let src = unsafe { slice::from_raw_parts(DP_image_pixels(src.image), count) }; | ||
let dst = unsafe { slice::from_raw_parts_mut(DP_image_pixels(self.image), count) }; | ||
let opa = opacity as u32; | ||
for i in 0..count { | ||
dst[i] = Self::blend_white(&src[i], opa); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn blend_white(src: &DP_Pixel8, opa: u32) -> DP_Pixel8 { | ||
let opa1 = 255u32 - opa; | ||
let color = unsafe { src.color }; | ||
let r = Self::mul(0xffu32, opa) + Self::mul(color & 0xffu32, opa1); | ||
let g = Self::mul(0xffu32, opa) + Self::mul((color >> 8u32) & 0xffu32, opa1); | ||
let b = Self::mul(0xffu32, opa) + Self::mul((color >> 16u32) & 0xffu32, opa1); | ||
let a = color & 0xff000000u32; | ||
DP_Pixel8 { | ||
color: (r as u32) | ((g as u32) << 8u32) | ((b as u32) << 16u32) | a, | ||
} | ||
} | ||
|
||
fn mul(a: u32, b: u32) -> u8 { | ||
let c = a * b + 0x80u32; | ||
(((c >> 8u32) + c) >> 8u32) as u8 | ||
} | ||
} | ||
|
||
impl Drop for Image { | ||
fn drop(&mut self) { | ||
unsafe { DP_image_free(self.image) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,15 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
mod acl; | ||
mod draw_context; | ||
mod image; | ||
mod paint_engine; | ||
mod player; | ||
mod recorder; | ||
|
||
pub use acl::AclState; | ||
pub use draw_context::DrawContext; | ||
pub use image::{Image, ImageError}; | ||
pub use paint_engine::{PaintEngine, PaintEngineError}; | ||
pub use player::{Player, PlayerError}; | ||
pub use recorder::{Recorder, RecorderError}; |
Oops, something went wrong.