1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use super::image::*;
16 use super::types::*;
17 
18 use crate::decoder::Category;
19 use crate::image::*;
20 use crate::internal_utils::pixels::*;
21 use crate::internal_utils::*;
22 use crate::reformat::rgb;
23 use crate::*;
24 
25 /// cbindgen:rename-all=CamelCase
26 #[repr(C)]
27 pub struct avifRGBImage {
28     pub width: u32,
29     pub height: u32,
30     pub depth: u32,
31     pub format: rgb::Format,
32     pub chroma_upsampling: rgb::ChromaUpsampling,
33     pub chroma_downsampling: rgb::ChromaDownsampling,
34     pub ignore_alpha: bool,
35     pub alpha_premultiplied: bool,
36     pub is_float: bool,
37     pub max_threads: i32,
38     pub pixels: *mut u8,
39     pub row_bytes: u32,
40 }
41 
42 impl From<rgb::Image> for avifRGBImage {
from(mut rgb: rgb::Image) -> avifRGBImage43     fn from(mut rgb: rgb::Image) -> avifRGBImage {
44         avifRGBImage {
45             width: rgb.width,
46             height: rgb.height,
47             depth: rgb.depth as u32,
48             format: rgb.format,
49             chroma_upsampling: rgb.chroma_upsampling,
50             chroma_downsampling: rgb.chroma_downsampling,
51             ignore_alpha: false,
52             alpha_premultiplied: rgb.premultiply_alpha,
53             is_float: rgb.is_float,
54             max_threads: rgb.max_threads,
55             pixels: rgb.pixels(),
56             row_bytes: rgb.row_bytes,
57         }
58     }
59 }
60 
61 impl From<&avifRGBImage> for rgb::Image {
from(rgb: &avifRGBImage) -> rgb::Image62     fn from(rgb: &avifRGBImage) -> rgb::Image {
63         let dst = rgb::Image {
64             width: rgb.width,
65             height: rgb.height,
66             depth: rgb.depth as u8,
67             format: rgb.format,
68             chroma_upsampling: rgb.chroma_upsampling,
69             chroma_downsampling: rgb.chroma_downsampling,
70             premultiply_alpha: rgb.alpha_premultiplied,
71             is_float: rgb.is_float,
72             max_threads: rgb.max_threads,
73             pixels: Pixels::from_raw_pointer(rgb.pixels, rgb.depth, rgb.height, rgb.row_bytes).ok(),
74             row_bytes: rgb.row_bytes,
75         };
76         let format = match (rgb.format, rgb.ignore_alpha) {
77             (rgb::Format::Rgb, _) => rgb::Format::Rgb,
78             (rgb::Format::Rgba, true) => rgb::Format::Rgb,
79             (rgb::Format::Rgba, false) => rgb::Format::Rgba,
80             (rgb::Format::Argb, true) => rgb::Format::Rgb,
81             (rgb::Format::Argb, false) => rgb::Format::Argb,
82             (rgb::Format::Bgr, _) => rgb::Format::Bgr,
83             (rgb::Format::Bgra, true) => rgb::Format::Bgr,
84             (rgb::Format::Bgra, false) => rgb::Format::Bgra,
85             (rgb::Format::Abgr, true) => rgb::Format::Bgr,
86             (rgb::Format::Abgr, false) => rgb::Format::Abgr,
87             (rgb::Format::Rgb565, _) => rgb::Format::Rgb565,
88             (rgb::Format::Rgba1010102, _) => rgb::Format::Rgba1010102,
89         };
90         dst.shuffle_channels_to(format).unwrap()
91     }
92 }
93 
94 impl From<&avifImage> for image::Image {
95     // Only copies fields necessary for reformatting.
from(image: &avifImage) -> image::Image96     fn from(image: &avifImage) -> image::Image {
97         image::Image {
98             width: image.width,
99             height: image.height,
100             depth: image.depth as u8,
101             yuv_format: image.yuvFormat,
102             yuv_range: image.yuvRange,
103             alpha_present: !image.alphaPlane.is_null(),
104             alpha_premultiplied: image.alphaPremultiplied == AVIF_TRUE,
105             planes: [
106                 Pixels::from_raw_pointer(
107                     image.yuvPlanes[0],
108                     image.depth,
109                     image.height,
110                     image.yuvRowBytes[0],
111                 )
112                 .ok(),
113                 Pixels::from_raw_pointer(
114                     image.yuvPlanes[1],
115                     image.depth,
116                     image.height,
117                     image.yuvRowBytes[1],
118                 )
119                 .ok(),
120                 Pixels::from_raw_pointer(
121                     image.yuvPlanes[2],
122                     image.depth,
123                     image.height,
124                     image.yuvRowBytes[2],
125                 )
126                 .ok(),
127                 Pixels::from_raw_pointer(
128                     image.alphaPlane,
129                     image.depth,
130                     image.height,
131                     image.alphaRowBytes,
132                 )
133                 .ok(),
134             ],
135             row_bytes: [
136                 image.yuvRowBytes[0],
137                 image.yuvRowBytes[1],
138                 image.yuvRowBytes[2],
139                 image.alphaRowBytes,
140             ],
141             color_primaries: image.colorPrimaries,
142             transfer_characteristics: image.transferCharacteristics,
143             matrix_coefficients: image.matrixCoefficients,
144             ..Default::default()
145         }
146     }
147 }
148 
149 #[no_mangle]
crabby_avifRGBImageSetDefaults( rgb: *mut avifRGBImage, image: *const avifImage, )150 pub unsafe extern "C" fn crabby_avifRGBImageSetDefaults(
151     rgb: *mut avifRGBImage,
152     image: *const avifImage,
153 ) {
154     let rgb = unsafe { &mut (*rgb) };
155     let image: image::Image = unsafe { &(*image) }.into();
156     *rgb = rgb::Image::create_from_yuv(&image).into();
157 }
158 
159 #[no_mangle]
crabby_avifImageYUVToRGB( image: *const avifImage, rgb: *mut avifRGBImage, ) -> avifResult160 pub unsafe extern "C" fn crabby_avifImageYUVToRGB(
161     image: *const avifImage,
162     rgb: *mut avifRGBImage,
163 ) -> avifResult {
164     unsafe {
165         if (*image).yuvPlanes[0].is_null() {
166             return avifResult::Ok;
167         }
168     }
169     let mut rgb: rgb::Image = unsafe { &(*rgb) }.into();
170     let image: image::Image = unsafe { &(*image) }.into();
171     to_avifResult(&rgb.convert_from_yuv(&image))
172 }
173 
CopyPlanes(dst: &mut avifImage, src: &Image) -> AvifResult<()>174 fn CopyPlanes(dst: &mut avifImage, src: &Image) -> AvifResult<()> {
175     for plane in ALL_PLANES {
176         if !src.has_plane(plane) {
177             continue;
178         }
179         let plane_data = src.plane_data(plane).unwrap();
180         if src.depth == 8 {
181             let dst_planes = [
182                 dst.yuvPlanes[0],
183                 dst.yuvPlanes[1],
184                 dst.yuvPlanes[2],
185                 dst.alphaPlane,
186             ];
187             let dst_row_bytes = [
188                 dst.yuvRowBytes[0],
189                 dst.yuvRowBytes[1],
190                 dst.yuvRowBytes[2],
191                 dst.alphaRowBytes,
192             ];
193             for y in 0..plane_data.height {
194                 let src_slice = &src.row(plane, y).unwrap()[..plane_data.width as usize];
195                 let dst_slice = unsafe {
196                     std::slice::from_raw_parts_mut(
197                         dst_planes[plane.to_usize()]
198                             .offset(isize_from_u32(y * dst_row_bytes[plane.to_usize()])?),
199                         usize_from_u32(plane_data.width)?,
200                     )
201                 };
202                 dst_slice.copy_from_slice(src_slice);
203             }
204         } else {
205             let dst_planes = [
206                 dst.yuvPlanes[0] as *mut u16,
207                 dst.yuvPlanes[1] as *mut u16,
208                 dst.yuvPlanes[2] as *mut u16,
209                 dst.alphaPlane as *mut u16,
210             ];
211             let dst_row_bytes = [
212                 dst.yuvRowBytes[0] / 2,
213                 dst.yuvRowBytes[1] / 2,
214                 dst.yuvRowBytes[2] / 2,
215                 dst.alphaRowBytes / 2,
216             ];
217             for y in 0..plane_data.height {
218                 let src_slice = &src.row16(plane, y).unwrap()[..plane_data.width as usize];
219                 let dst_slice = unsafe {
220                     std::slice::from_raw_parts_mut(
221                         dst_planes[plane.to_usize()]
222                             .offset(isize_from_u32(y * dst_row_bytes[plane.to_usize()])?),
223                         usize_from_u32(plane_data.width)?,
224                     )
225                 };
226                 dst_slice.copy_from_slice(src_slice);
227             }
228         }
229     }
230     Ok(())
231 }
232 
233 #[no_mangle]
crabby_avifImageScale( image: *mut avifImage, dstWidth: u32, dstHeight: u32, _diag: *mut avifDiagnostics, ) -> avifResult234 pub unsafe extern "C" fn crabby_avifImageScale(
235     image: *mut avifImage,
236     dstWidth: u32,
237     dstHeight: u32,
238     _diag: *mut avifDiagnostics,
239 ) -> avifResult {
240     // To avoid buffer reallocations, we only support scaling to a smaller size.
241     let dst_image = unsafe { &mut (*image) };
242     if dstWidth > dst_image.width || dstHeight > dst_image.height {
243         return avifResult::NotImplemented;
244     }
245 
246     let mut rust_image: image::Image = unsafe { &(*image) }.into();
247     let res = rust_image.scale(dstWidth, dstHeight, Category::Color);
248     if res.is_err() {
249         return to_avifResult(&res);
250     }
251     // The scale function is designed to work only for one category at a time.
252     // Restore the width and height to the original values before scaling the
253     // alpha plane.
254     rust_image.width = unsafe { (*image).width };
255     rust_image.height = unsafe { (*image).height };
256     let res = rust_image.scale(dstWidth, dstHeight, Category::Alpha);
257     if res.is_err() {
258         return to_avifResult(&res);
259     }
260 
261     dst_image.width = rust_image.width;
262     dst_image.height = rust_image.height;
263     to_avifResult(&CopyPlanes(dst_image, &rust_image))
264 }
265