1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use std::fmt::{Debug, Error, Formatter};
use std::ops::{Deref, DerefMut};

#[cfg(feature = "img")]
use image::*;
use libwebp_sys::{WebPFree, WebPPicture, WebPPictureFree};

/// This struct represents a safe wrapper around memory owned by libwebp.
/// Its data contents can be accessed through the Deref and DerefMut traits.
pub struct WebPMemory(pub(crate) *mut u8, pub(crate) usize);

impl Debug for WebPMemory {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        f.debug_struct("WebpMemory").finish()
    }
}

impl Drop for WebPMemory {
    fn drop(&mut self) {
        unsafe { WebPFree(self.0 as _) }
    }
}

impl Deref for WebPMemory {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        unsafe { std::slice::from_raw_parts(self.0, self.1) }
    }
}

impl DerefMut for WebPMemory {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { std::slice::from_raw_parts_mut(self.0, self.1) }
    }
}

#[derive(Debug)]
pub(crate) struct ManageedPicture(pub(crate) WebPPicture);

impl Drop for ManageedPicture {
    fn drop(&mut self) {
        unsafe { WebPPictureFree(&mut self.0 as _) }
    }
}

impl Deref for ManageedPicture {
    type Target = WebPPicture;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for ManageedPicture {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

/// This struct represents a decoded image.
/// Its data contents can be accessed through the Deref and DerefMut traits.
/// It is also possible to create an image::DynamicImage from this struct.
pub struct WebPImage {
    data: WebPMemory,
    layout: PixelLayout,
    width: u32,
    height: u32,
}

impl WebPImage {
    pub(crate) fn new(data: WebPMemory, layout: PixelLayout, width: u32, height: u32) -> Self {
        Self {
            data,
            layout,
            width,
            height,
        }
    }

    /// Creates a DynamicImage from this WebPImage.
    #[cfg(feature = "img")]
    pub fn to_image(&self) -> DynamicImage {
        if self.layout.is_alpha() {
            let image = ImageBuffer::from_raw(self.width, self.height, self.data.to_owned())
                .expect("ImageBuffer couldn't be created");

            DynamicImage::ImageRgba8(image)
        } else {
            let image = ImageBuffer::from_raw(self.width, self.height, self.data.to_owned())
                .expect("ImageBuffer couldn't be created");

            DynamicImage::ImageRgb8(image)
        }
    }

    /// Returns the width of the image in pixels.
    pub fn width(&self) -> u32 {
        self.width
    }

    /// Returns the height of the image in pixels.
    pub fn height(&self) -> u32 {
        self.height
    }

    pub fn is_alpha(&self) -> bool {
        self.layout.is_alpha()
    }
}

impl Deref for WebPImage {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        self.data.deref()
    }
}

impl DerefMut for WebPImage {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.data.deref_mut()
    }
}

/// Describes the pixel layout (the order of the color channels) of an image.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PixelLayout {
    Rgb,
    Rgba,
}

impl PixelLayout {
    /// Returns true if the pixel contains an alpha channel.
    pub fn is_alpha(self) -> bool {
        self == PixelLayout::Rgba
    }
}