• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::image::*;
19 use crate::internal_utils::pixels::*;
20 use crate::internal_utils::*;
21 use crate::reformat::rgb;
22 use crate::*;
23 
24 /// cbindgen:rename-all=CamelCase
25 #[repr(C)]
26 pub struct avifRGBImage {
27     pub width: u32,
28     pub height: u32,
29     pub depth: u32,
30     pub format: rgb::Format,
31     pub chroma_upsampling: rgb::ChromaUpsampling,
32     pub chroma_downsampling: rgb::ChromaDownsampling,
33     pub ignore_alpha: bool,
34     pub alpha_premultiplied: bool,
35     pub is_float: bool,
36     pub max_threads: i32,
37     pub pixels: *mut u8,
38     pub row_bytes: u32,
39 }
40 
41 impl From<rgb::Image> for avifRGBImage {
from(mut rgb: rgb::Image) -> avifRGBImage42     fn from(mut rgb: rgb::Image) -> avifRGBImage {
43         avifRGBImage {
44             width: rgb.width,
45             height: rgb.height,
46             depth: rgb.depth as u32,
47             format: rgb.format,
48             chroma_upsampling: rgb.chroma_upsampling,
49             chroma_downsampling: rgb.chroma_downsampling,
50             ignore_alpha: false,
51             alpha_premultiplied: rgb.premultiply_alpha,
52             is_float: rgb.is_float,
53             max_threads: rgb.max_threads,
54             pixels: rgb.pixels(),
55             row_bytes: rgb.row_bytes,
56         }
57     }
58 }
59 
60 impl From<&avifRGBImage> for rgb::Image {
from(rgb: &avifRGBImage) -> rgb::Image61     fn from(rgb: &avifRGBImage) -> rgb::Image {
62         let dst = rgb::Image {
63             width: rgb.width,
64             height: rgb.height,
65             depth: rgb.depth as u8,
66             format: rgb.format,
67             chroma_upsampling: rgb.chroma_upsampling,
68             chroma_downsampling: rgb.chroma_downsampling,
69             premultiply_alpha: rgb.alpha_premultiplied,
70             is_float: rgb.is_float,
71             max_threads: rgb.max_threads,
72             pixels: Pixels::from_raw_pointer(rgb.pixels, rgb.depth, rgb.height, rgb.row_bytes).ok(),
73             row_bytes: rgb.row_bytes,
74         };
75         let format = match (rgb.format, rgb.ignore_alpha) {
76             (rgb::Format::Rgb, _) => rgb::Format::Rgb,
77             (rgb::Format::Rgba, true) => rgb::Format::Rgb,
78             (rgb::Format::Rgba, false) => rgb::Format::Rgba,
79             (rgb::Format::Argb, true) => rgb::Format::Rgb,
80             (rgb::Format::Argb, false) => rgb::Format::Argb,
81             (rgb::Format::Bgr, _) => rgb::Format::Bgr,
82             (rgb::Format::Bgra, true) => rgb::Format::Bgr,
83             (rgb::Format::Bgra, false) => rgb::Format::Bgra,
84             (rgb::Format::Abgr, true) => rgb::Format::Bgr,
85             (rgb::Format::Abgr, false) => rgb::Format::Abgr,
86             (rgb::Format::Rgb565, _) => rgb::Format::Rgb565,
87             (rgb::Format::Rgba1010102, _) => rgb::Format::Rgba1010102,
88         };
89         dst.shuffle_channels_to(format).unwrap()
90     }
91 }
92 
93 impl From<&avifImage> for image::Image {
94     // Only copies fields necessary for reformatting.
from(image: &avifImage) -> image::Image95     fn from(image: &avifImage) -> image::Image {
96         image::Image {
97             width: image.width,
98             height: image.height,
99             depth: image.depth as u8,
100             yuv_format: image.yuvFormat,
101             yuv_range: image.yuvRange,
102             alpha_present: !image.alphaPlane.is_null(),
103             alpha_premultiplied: image.alphaPremultiplied == AVIF_TRUE,
104             planes: [
105                 Pixels::from_raw_pointer(
106                     image.yuvPlanes[0],
107                     image.depth,
108                     image.height,
109                     image.yuvRowBytes[0],
110                 )
111                 .ok(),
112                 Pixels::from_raw_pointer(
113                     image.yuvPlanes[1],
114                     image.depth,
115                     image.height,
116                     image.yuvRowBytes[1],
117                 )
118                 .ok(),
119                 Pixels::from_raw_pointer(
120                     image.yuvPlanes[2],
121                     image.depth,
122                     image.height,
123                     image.yuvRowBytes[2],
124                 )
125                 .ok(),
126                 Pixels::from_raw_pointer(
127                     image.alphaPlane,
128                     image.depth,
129                     image.height,
130                     image.alphaRowBytes,
131                 )
132                 .ok(),
133             ],
134             row_bytes: [
135                 image.yuvRowBytes[0],
136                 image.yuvRowBytes[1],
137                 image.yuvRowBytes[2],
138                 image.alphaRowBytes,
139             ],
140             color_primaries: image.colorPrimaries,
141             transfer_characteristics: image.transferCharacteristics,
142             matrix_coefficients: image.matrixCoefficients,
143             ..Default::default()
144         }
145     }
146 }
147 
148 #[no_mangle]
crabby_avifRGBImageSetDefaults( rgb: *mut avifRGBImage, image: *const avifImage, )149 pub unsafe extern "C" fn crabby_avifRGBImageSetDefaults(
150     rgb: *mut avifRGBImage,
151     image: *const avifImage,
152 ) {
153     let rgb = unsafe { &mut (*rgb) };
154     let image: image::Image = unsafe { &(*image) }.into();
155     *rgb = rgb::Image::create_from_yuv(&image).into();
156 }
157 
158 #[no_mangle]
crabby_avifImageYUVToRGB( image: *const avifImage, rgb: *mut avifRGBImage, ) -> avifResult159 pub unsafe extern "C" fn crabby_avifImageYUVToRGB(
160     image: *const avifImage,
161     rgb: *mut avifRGBImage,
162 ) -> avifResult {
163     unsafe {
164         if (*image).yuvPlanes[0].is_null() {
165             return avifResult::Ok;
166         }
167     }
168     let mut rgb: rgb::Image = unsafe { &(*rgb) }.into();
169     let image: image::Image = unsafe { &(*image) }.into();
170     to_avifResult(&rgb.convert_from_yuv(&image))
171 }
172 
CopyPlanes(dst: &mut avifImage, src: &Image) -> AvifResult<()>173 fn CopyPlanes(dst: &mut avifImage, src: &Image) -> AvifResult<()> {
174     for plane in ALL_PLANES {
175         if !src.has_plane(plane) {
176             continue;
177         }
178         let plane_data = src.plane_data(plane).unwrap();
179         if src.depth == 8 {
180             let dst_planes = [
181                 dst.yuvPlanes[0],
182                 dst.yuvPlanes[1],
183                 dst.yuvPlanes[2],
184                 dst.alphaPlane,
185             ];
186             let dst_row_bytes = [
187                 dst.yuvRowBytes[0],
188                 dst.yuvRowBytes[1],
189                 dst.yuvRowBytes[2],
190                 dst.alphaRowBytes,
191             ];
192             for y in 0..plane_data.height {
193                 let src_slice = &src.row(plane, y).unwrap()[..plane_data.width as usize];
194                 let dst_slice = unsafe {
195                     std::slice::from_raw_parts_mut(
196                         dst_planes[plane.as_usize()]
197                             .offset(isize_from_u32(y * dst_row_bytes[plane.as_usize()])?),
198                         usize_from_u32(plane_data.width)?,
199                     )
200                 };
201                 dst_slice.copy_from_slice(src_slice);
202             }
203         } else {
204             // When scaling a P010 image, the scaling code converts the image into Yuv420 with
205             // an explicit V plane. So if the V plane is missing in |dst|, we will have to allocate
206             // it here. It is safe to do so since it will be free'd with the other plane buffers
207             // when the image object is destroyed.
208             if plane == Plane::V && dst.yuvPlanes[2].is_null() {
209                 let plane_size = usize_from_u32(plane_data.width * plane_data.height * 2)?;
210                 dst.yuvPlanes[2] = unsafe { crabby_avifAlloc(plane_size) } as *mut _;
211                 dst.yuvRowBytes[2] = plane_data.width * 2;
212             }
213             let dst_planes = [
214                 dst.yuvPlanes[0] as *mut u16,
215                 dst.yuvPlanes[1] as *mut u16,
216                 dst.yuvPlanes[2] as *mut u16,
217                 dst.alphaPlane as *mut u16,
218             ];
219             let dst_row_bytes = [
220                 dst.yuvRowBytes[0] / 2,
221                 dst.yuvRowBytes[1] / 2,
222                 dst.yuvRowBytes[2] / 2,
223                 dst.alphaRowBytes / 2,
224             ];
225             for y in 0..plane_data.height {
226                 let src_slice = &src.row16(plane, y).unwrap()[..plane_data.width as usize];
227                 let dst_slice = unsafe {
228                     std::slice::from_raw_parts_mut(
229                         dst_planes[plane.as_usize()]
230                             .offset(isize_from_u32(y * dst_row_bytes[plane.as_usize()])?),
231                         usize_from_u32(plane_data.width)?,
232                     )
233                 };
234                 dst_slice.copy_from_slice(src_slice);
235             }
236         }
237     }
238     Ok(())
239 }
240 
241 #[no_mangle]
crabby_avifImageScale( image: *mut avifImage, dstWidth: u32, dstHeight: u32, _diag: *mut avifDiagnostics, ) -> avifResult242 pub unsafe extern "C" fn crabby_avifImageScale(
243     image: *mut avifImage,
244     dstWidth: u32,
245     dstHeight: u32,
246     _diag: *mut avifDiagnostics,
247 ) -> avifResult {
248     // To avoid buffer reallocations, we only support scaling to a smaller size.
249     let dst_image = unsafe { &mut (*image) };
250     if dstWidth > dst_image.width || dstHeight > dst_image.height {
251         return avifResult::NotImplemented;
252     }
253 
254     let mut rust_image: image::Image = unsafe { &(*image) }.into();
255     let res = rust_image.scale(dstWidth, dstHeight, Category::Color);
256     if res.is_err() {
257         return to_avifResult(&res);
258     }
259     // The scale function is designed to work only for one category at a time.
260     // Restore the width and height to the original values before scaling the
261     // alpha plane.
262     rust_image.width = unsafe { (*image).width };
263     rust_image.height = unsafe { (*image).height };
264     let res = rust_image.scale(dstWidth, dstHeight, Category::Alpha);
265     if res.is_err() {
266         return to_avifResult(&res);
267     }
268 
269     dst_image.width = rust_image.width;
270     dst_image.height = rust_image.height;
271     dst_image.depth = rust_image.depth as _;
272     dst_image.yuvFormat = rust_image.yuv_format;
273     to_avifResult(&CopyPlanes(dst_image, &rust_image))
274 }
275