skia_safe/encode_/
jpeg_encoder.rs

1use crate::{interop::RustWStream, prelude::*, Data, EncodedOrigin, Pixmap};
2use skia_bindings::{SkJpegEncoder_AlphaOption, SkJpegEncoder_Downsample};
3use std::io;
4
5pub type AlphaOption = SkJpegEncoder_AlphaOption;
6variant_name!(AlphaOption::BlendOnBlack);
7
8#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
9pub enum Downsample {
10    BothDirections,
11    Horizontal,
12    No,
13}
14
15impl Downsample {
16    fn native(&self) -> SkJpegEncoder_Downsample {
17        match self {
18            Downsample::BothDirections => SkJpegEncoder_Downsample::k420,
19            Downsample::Horizontal => SkJpegEncoder_Downsample::k422,
20            Downsample::No => SkJpegEncoder_Downsample::k444,
21        }
22    }
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct Options {
27    pub quality: u32,
28    pub downsample: Downsample,
29    pub alpha_option: AlphaOption,
30    pub xmp_metadata: Option<String>,
31    pub origin: Option<EncodedOrigin>,
32    // TODO: ICCProfile
33    // TODO: ICCProfileDescription
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
65// TODO: encode YUVAPixmaps
66
67pub fn encode_image<'a>(
68    context: impl Into<Option<&'a mut crate::gpu::DirectContext>>,
69    img: &crate::Image,
70    options: &Options,
71) -> Option<crate::Data> {
72    let xmp_metadata = options.xmp_metadata.as_ref().map(Data::new_str);
73
74    Data::from_ptr(unsafe {
75        skia_bindings::C_SkJpegEncoder_EncodeImage(
76            context.into().native_ptr_or_null_mut(),
77            img.native(),
78            options.quality as _,
79            options.downsample.native(),
80            options.alpha_option,
81            xmp_metadata.as_ref().native_ptr_or_null(),
82            options.origin.as_ref().native_ptr_or_null(),
83        )
84    })
85}
86
87// TODO: Make (Pixmap + SkYUVAPixmaps)