skia_safe/encode_/
jpeg_encoder.rs

1use crate::{
2    interop::RustWStream, prelude::*, ColorSpace, Data, EncodedOrigin, Pixmap, YUVAPixmaps,
3};
4use skia_bindings::{SkJpegEncoder_AlphaOption, SkJpegEncoder_Downsample};
5use std::io;
6
7pub type AlphaOption = SkJpegEncoder_AlphaOption;
8variant_name!(AlphaOption::BlendOnBlack);
9
10#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
11pub enum Downsample {
12    BothDirections,
13    Horizontal,
14    No,
15}
16
17impl Downsample {
18    fn native(&self) -> SkJpegEncoder_Downsample {
19        match self {
20            Downsample::BothDirections => SkJpegEncoder_Downsample::k420,
21            Downsample::Horizontal => SkJpegEncoder_Downsample::k422,
22            Downsample::No => SkJpegEncoder_Downsample::k444,
23        }
24    }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Options {
29    pub quality: u32,
30    pub downsample: Downsample,
31    pub alpha_option: AlphaOption,
32    pub xmp_metadata: Option<String>,
33    pub origin: Option<EncodedOrigin>,
34}
35
36impl Default for Options {
37    fn default() -> Self {
38        Self {
39            quality: 100,
40            downsample: Downsample::BothDirections,
41            alpha_option: AlphaOption::Ignore,
42            xmp_metadata: None,
43            origin: None,
44        }
45    }
46}
47
48pub fn encode<W: io::Write>(pixmap: &Pixmap, writer: &mut W, options: &Options) -> bool {
49    let xml_metadata = options.xmp_metadata.as_ref().map(Data::new_str);
50    let mut stream = RustWStream::new(writer);
51
52    unsafe {
53        skia_bindings::C_SkJpegEncoder_Encode(
54            stream.stream_mut(),
55            pixmap.native(),
56            options.quality as _,
57            options.downsample.native(),
58            options.alpha_option,
59            xml_metadata.as_ref().native_ptr_or_null(),
60            options.origin.as_ref().native_ptr_or_null(),
61        )
62    }
63}
64
65pub fn encode_yuva_pixmaps<W: io::Write>(
66    writer: &mut W,
67    src: &YUVAPixmaps,
68    src_color_space: Option<&ColorSpace>,
69    options: &Options,
70) -> bool {
71    let xmp_metadata = options.xmp_metadata.as_ref().map(Data::new_str);
72    let mut stream = RustWStream::new(writer);
73
74    unsafe {
75        skia_bindings::C_SkJpegEncoder_EncodeYUVAPixmaps(
76            stream.stream_mut(),
77            src.native(),
78            src_color_space.native_ptr_or_null(),
79            options.quality as _,
80            options.downsample.native(),
81            options.alpha_option,
82            xmp_metadata.as_ref().native_ptr_or_null(),
83            options.origin.as_ref().native_ptr_or_null(),
84        )
85    }
86}
87
88pub fn encode_pixmap(src: &Pixmap, options: &Options) -> Option<crate::Data> {
89    let xmp_metadata = options.xmp_metadata.as_ref().map(Data::new_str);
90
91    Data::from_ptr(unsafe {
92        skia_bindings::C_SkJpegEncoder_EncodePixmap(
93            src.native(),
94            options.quality as _,
95            options.downsample.native(),
96            options.alpha_option,
97            xmp_metadata.as_ref().native_ptr_or_null(),
98            options.origin.as_ref().native_ptr_or_null(),
99        )
100    })
101}
102
103pub fn encode_image<'a>(
104    context: impl Into<Option<&'a mut crate::gpu::DirectContext>>,
105    img: &crate::Image,
106    options: &Options,
107) -> Option<crate::Data> {
108    let xmp_metadata = options.xmp_metadata.as_ref().map(Data::new_str);
109
110    Data::from_ptr(unsafe {
111        skia_bindings::C_SkJpegEncoder_EncodeImage(
112            context.into().native_ptr_or_null_mut(),
113            img.native(),
114            options.quality as _,
115            options.downsample.native(),
116            options.alpha_option,
117            xmp_metadata.as_ref().native_ptr_or_null(),
118            options.origin.as_ref().native_ptr_or_null(),
119        )
120    })
121}
122
123// TODO: Make (Pixmap + SkYUVAPixmaps)