skia_safe/core/image.rs
1use crate::{
2 AlphaType, Bitmap, ColorSpace, ColorType, Data, EncodedImageFormat, IPoint, IRect, ISize,
3 ImageFilter, ImageGenerator, ImageInfo, Matrix, Paint, Picture, Pixmap, Recorder,
4 SamplingOptions, Shader, SurfaceProps, TextureCompressionType, TileMode, gpu, prelude::*,
5};
6use skia_bindings::{self as sb, SkImage, SkRefCntBase};
7use std::{fmt, ptr};
8
9pub use super::CubicResampler;
10
11#[deprecated(since = "0.62.0", note = "Use TextureCompressionType")]
12pub use crate::TextureCompressionType as CompressionType;
13
14#[deprecated(since = "0.63.0", note = "Use images::BitDepth")]
15pub use images::BitDepth;
16
17pub mod images {
18 use std::{mem, ptr};
19
20 use skia_bindings as sb;
21
22 #[allow(unused)] // doc only
23 use crate::ColorType;
24 use crate::{
25 AlphaType, Bitmap, ColorSpace, Data, IPoint, IRect, ISize, Image, ImageFilter,
26 ImageGenerator, ImageInfo, Matrix, Paint, Picture, SurfaceProps, TextureCompressionType,
27 prelude::*,
28 };
29
30 /// Creates a CPU-backed [`Image`] from `bitmap`, sharing or copying `bitmap` pixels. If the bitmap
31 /// is marked immutable, and its pixel memory is shareable, it may be shared
32 /// instead of copied.
33 ///
34 /// [`Image`] is returned if bitmap is valid. Valid [`Bitmap`] parameters include:
35 /// dimensions are greater than zero;
36 /// each dimension fits in 29 bits;
37 /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
38 /// row bytes are large enough to hold one row of pixels;
39 /// pixel address is not `None`.
40 ///
41 /// * `bitmap` - [`ImageInfo`], row bytes, and pixels
42 ///
43 /// Returns: created [`Image`], or `None`
44 pub fn raster_from_bitmap(bitmap: &Bitmap) -> Option<Image> {
45 Image::from_ptr(unsafe { sb::C_SkImages_RasterFromBitmap(bitmap.native()) })
46 }
47
48 /// Creates a CPU-backed [`Image`] from compressed data.
49 ///
50 /// This method will decompress the compressed data and create an image wrapping
51 /// it. Any mipmap levels present in the compressed data are discarded.
52 ///
53 /// * `data` - compressed data to store in [`Image`]
54 /// * `dimension` - width and height of full [`Image`]
55 /// * `ty` - type of compression used
56 ///
57 /// Returns: created [`Image`], or `None`
58 pub fn raster_from_compressed_texture_data(
59 data: impl Into<Data>,
60 dimensions: impl Into<ISize>,
61 ty: TextureCompressionType,
62 ) -> Option<Image> {
63 let dimensions = dimensions.into();
64 Image::from_ptr(unsafe {
65 sb::C_SkImages_RasterFromCompressedTextureData(
66 data.into().into_ptr(),
67 dimensions.width,
68 dimensions.height,
69 ty,
70 )
71 })
72 }
73
74 /// Return a [`Image`] using the encoded data, but attempts to defer decoding until the
75 /// image is actually used/drawn. This deferral allows the system to cache the result, either on the
76 /// CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may
77 /// be purged, causing the next draw of the image to have to re-decode.
78 ///
79 /// If `alpha_type` is `None`, the image's alpha type will be chosen automatically based on the
80 /// image format. Transparent images will default to [`AlphaType::Premul`]. If `alpha_type` contains
81 /// [`AlphaType::Premul`] or [`AlphaType::Unpremul`], that alpha type will be used. Forcing opaque
82 /// (passing [`AlphaType::Opaque`]) is not allowed, and will return `None`.
83 ///
84 /// If the encoded format is not supported, `None` is returned.
85 ///
86 /// * `encoded` - the encoded data
87 ///
88 /// Returns: created [`Image`], or `None`
89 ///
90 /// example: <https://fiddle.skia.org/c/@Image_DeferredFromEncodedData>
91 pub fn deferred_from_encoded_data(
92 data: impl Into<Data>,
93 alpha_type: impl Into<Option<AlphaType>>,
94 ) -> Option<Image> {
95 Image::from_ptr(unsafe {
96 sb::C_SkImages_DeferredFromEncodedData(
97 data.into().into_ptr(),
98 alpha_type
99 .into()
100 .map(|at| &at as *const _)
101 .unwrap_or(ptr::null()),
102 )
103 })
104 }
105
106 /// Creates [`Image`] from data returned by `image_generator`. The image data will not be created
107 /// (on either the CPU or GPU) until the image is actually drawn.
108 /// Generated data is owned by [`Image`] and may not be shared or accessed.
109 ///
110 /// [`Image`] is returned if generator data is valid. Valid data parameters vary by type of data
111 /// and platform.
112 ///
113 /// `image_generator` may wrap [`Picture`] data, codec data, or custom data.
114 ///
115 /// * `image_generator` - stock or custom routines to retrieve [`Image`]
116 ///
117 /// Returns: created [`Image`], or `None`
118 pub fn deferred_from_generator(mut image_generator: ImageGenerator) -> Option<Image> {
119 let image = Image::from_ptr(unsafe {
120 sb::C_SkImages_DeferredFromGenerator(image_generator.native_mut())
121 });
122 mem::forget(image_generator);
123 image
124 }
125
126 pub use skia_bindings::SkImages_BitDepth as BitDepth;
127 variant_name!(BitDepth::F16);
128
129 /// Creates [`Image`] from picture. Returned [`Image`] width and height are set by dimensions.
130 /// [`Image`] draws picture with matrix and paint, set to `bit_depth` and `color_space`.
131 ///
132 /// The Picture data is not turned into an image (CPU or GPU) until it is drawn.
133 ///
134 /// If matrix is `None`, draws with identity [`Matrix`]. If paint is `None`, draws
135 /// with default [`Paint`]. `color_space` may be `None`.
136 ///
137 /// * `picture` - stream of drawing commands
138 /// * `dimensions` - width and height
139 /// * `matrix` - [`Matrix`] to rotate, scale, translate, and so on; may be `None`
140 /// * `paint` - [`Paint`] to apply transparency, filtering, and so on; may be `None`
141 /// * `bit_depth` - 8-bit integer or 16-bit float: per component
142 /// * `color_space` - range of colors; may be `None`
143 /// * `props` - props to use when rasterizing the picture
144 ///
145 /// Returns: created [`Image`], or `None`
146 pub fn deferred_from_picture(
147 picture: impl Into<Picture>,
148 dimensions: impl Into<ISize>,
149 matrix: Option<&Matrix>,
150 paint: Option<&Paint>,
151 bit_depth: BitDepth,
152 color_space: impl Into<Option<ColorSpace>>,
153 props: impl Into<Option<SurfaceProps>>,
154 ) -> Option<Image> {
155 Image::from_ptr(unsafe {
156 sb::C_SkImages_DeferredFromPicture(
157 picture.into().into_ptr(),
158 dimensions.into().native(),
159 matrix.native_ptr_or_null(),
160 paint.native_ptr_or_null(),
161 bit_depth,
162 color_space.into().into_ptr_or_null(),
163 props.into().unwrap_or_default().native(),
164 )
165 })
166 }
167
168 // TODO: RasterFromPixmapCopy
169 // TODO: RasterFromPixmap
170
171 /// Creates CPU-backed [`Image`] from pixel data described by info.
172 /// The pixels data will *not* be copied.
173 ///
174 /// [`Image`] is returned if [`ImageInfo`] is valid. Valid [`ImageInfo`] parameters include:
175 /// dimensions are greater than zero;
176 /// each dimension fits in 29 bits;
177 /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
178 /// `row_bytes` are large enough to hold one row of pixels;
179 /// pixels is not `None`, and contains enough data for [`Image`].
180 ///
181 /// * `info` - contains width, height, [`AlphaType`], [`ColorType`], [`ColorSpace`]
182 /// * `pixels` - address or pixel storage
183 /// * `row_bytes` - size of pixel row or larger
184 ///
185 /// Returns: [`Image`] sharing pixels, or `None`
186 pub fn raster_from_data(
187 info: &ImageInfo,
188 pixels: impl Into<Data>,
189 row_bytes: usize,
190 ) -> Option<Image> {
191 Image::from_ptr(unsafe {
192 sb::C_SkImages_RasterFromData(info.native(), pixels.into().into_ptr(), row_bytes)
193 })
194 }
195
196 /// Creates a filtered [`Image`] on the CPU. filter processes the src image, potentially
197 /// changing the color, position, and size. subset is the bounds of src that are processed by
198 /// filter. `clip_bounds` is the expected bounds of the filtered [`Image`]. `out_subset` is
199 /// required storage for the actual bounds of the filtered [`Image`]. `offset` is required
200 /// storage for translation of returned [`Image`].
201 ///
202 /// Returns `None` a filtered result could not be created.
203 ///
204 /// Useful for animation of [`ImageFilter`] that varies size from frame to frame. `out_subset`
205 /// describes the valid bounds of returned image. offset translates the returned [`Image`] to
206 /// keep subsequent animation frames aligned with respect to each other.
207 ///
208 /// * `src` - the image to be filtered
209 /// * `filter` - the image filter to be applied
210 /// * `subset` - bounds of [`Image`] processed by filter
211 /// * `clip_bounds` - expected bounds of filtered [`Image`]
212 ///
213 /// Returns filtered SkImage, or `None`:
214 /// * `out_subset` - storage for returned [`Image`] bounds
215 /// * `offset` - storage for returned [`Image`] translation Returns: filtered [`Image`], or
216 /// `None`
217 pub fn make_with_filter(
218 image: impl Into<Image>,
219 image_filter: &ImageFilter,
220 subset: impl AsRef<IRect>,
221 clip_bounds: impl AsRef<IRect>,
222 ) -> Option<(Image, IRect, IPoint)> {
223 let mut out_subset = IRect::default();
224 let mut offset = IPoint::default();
225
226 unsafe {
227 Image::from_ptr(sb::C_SkImages_MakeWithFilter(
228 image.into().into_ptr(),
229 image_filter.native(),
230 subset.as_ref().native(),
231 clip_bounds.as_ref().native(),
232 out_subset.native_mut(),
233 offset.native_mut(),
234 ))
235 }
236 .map(|i| (i, out_subset, offset));
237 None
238 }
239}
240
241/// CachingHint selects whether Skia may internally cache [`Bitmap`] generated by
242/// decoding [`Image`], or by copying [`Image`] from GPU to CPU. The default behavior
243/// allows caching [`Bitmap`].
244///
245/// Choose [`CachingHint::Disallow`] if [`Image`] pixels are to be used only once, or
246/// if [`Image`] pixels reside in a cache outside of Skia, or to reduce memory pressure.
247///
248/// Choosing [`CachingHint::Allow`] does not ensure that pixels will be cached.
249/// [`Image`] pixels may not be cached if memory requirements are too large or
250/// pixels are not accessible.
251pub use skia_bindings::SkImage_CachingHint as CachingHint;
252variant_name!(CachingHint::Allow);
253
254#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
255#[repr(C)]
256pub struct RequiredProperties {
257 pub mipmapped: bool,
258}
259
260native_transmutable!(sb::SkImage_RequiredProperties, RequiredProperties);
261
262/// [`Image`] describes a two dimensional array of pixels to draw. The pixels may be
263/// decoded in a raster bitmap, encoded in a [`Picture`] or compressed data stream,
264/// or located in GPU memory as a GPU texture.
265///
266/// [`Image`] cannot be modified after it is created. [`Image`] may allocate additional
267/// storage as needed; for instance, an encoded [`Image`] may decode when drawn.
268///
269/// [`Image`] width and height are greater than zero. Creating an [`Image`] with zero width
270/// or height returns [`Image`] equal to nullptr.
271///
272/// [`Image`] may be created from [`Bitmap`], [`Pixmap`], [`crate::Surface`], [`Picture`], encoded streams,
273/// GPU texture, YUV_ColorSpace data, or hardware buffer. Encoded streams supported
274/// include BMP, GIF, HEIF, ICO, JPEG, PNG, WBMP, WebP. Supported encoding details
275/// vary with platform.
276pub type Image = RCHandle<SkImage>;
277unsafe_send_sync!(Image);
278require_base_type!(SkImage, sb::SkRefCnt);
279
280impl NativeBase<SkRefCntBase> for SkImage {}
281
282impl NativeRefCountedBase for SkImage {
283 type Base = SkRefCntBase;
284}
285
286impl fmt::Debug for Image {
287 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288 let mut d = f.debug_struct("Image");
289 let d = d
290 .field("image_info", &self.image_info())
291 .field("unique_id", &self.unique_id())
292 .field("alpha_type", &self.alpha_type())
293 .field("color_type", &self.color_type())
294 .field("color_space", &self.color_space())
295 .field("is_texture_backed", &self.is_texture_backed());
296 #[cfg(feature = "gpu")]
297 let d = d.field("texture_size", &self.texture_size());
298 d.field("has_mipmaps", &self.has_mipmaps())
299 .field("is_lazy_generated", &self.is_lazy_generated())
300 .finish()
301 }
302}
303
304impl Image {
305 /// Creates [`Image`] from [`ImageInfo`], sharing pixels.
306 ///
307 /// [`Image`] is returned if [`ImageInfo`] is valid. Valid [`ImageInfo`] parameters include:
308 /// dimensions are greater than zero;
309 /// each dimension fits in 29 bits;
310 /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
311 /// rowBytes are large enough to hold one row of pixels;
312 /// pixels is not nullptr, and contains enough data for [`Image`].
313 ///
314 /// - `info` contains width, height, [`AlphaType`], [`ColorType`], [`ColorSpace`]
315 /// - `pixels` address or pixel storage
316 /// - `rowBytes` size of pixel row or larger
317 ///
318 /// Returns: [`Image`] sharing pixels, or `None`
319 #[deprecated(since = "0.63.0", note = "use images::raster_from_data()")]
320 pub fn from_raster_data(
321 info: &ImageInfo,
322 pixels: impl Into<Data>,
323 row_bytes: usize,
324 ) -> Option<Image> {
325 images::raster_from_data(info, pixels, row_bytes)
326 }
327
328 /// Creates [`Image`] from bitmap, sharing or copying bitmap pixels. If the bitmap
329 /// is marked immutable, and its pixel memory is shareable, it may be shared
330 /// instead of copied.
331 ///
332 /// [`Image`] is returned if bitmap is valid. Valid [`Bitmap`] parameters include:
333 /// dimensions are greater than zero;
334 /// each dimension fits in 29 bits;
335 /// [`ColorType`] and [`AlphaType`] are valid, and [`ColorType`] is not [`ColorType::Unknown`];
336 /// row bytes are large enough to hold one row of pixels;
337 /// pixel address is not `null`.
338 ///
339 /// - `bitmap` [`ImageInfo`], row bytes, and pixels
340 ///
341 /// Returns: created [`Image`], or `None`
342 ///
343 /// example: <https://fiddle.skia.org/c/@Image_MakeFromBitmap>
344 #[deprecated(since = "0.63.0", note = "use images::raster_from_bitmap()")]
345 pub fn from_bitmap(bitmap: &Bitmap) -> Option<Image> {
346 images::raster_from_bitmap(bitmap)
347 }
348
349 /// Creates [`Image`] from data returned by `image_generator`. Generated data is owned by [`Image`] and
350 /// may not be shared or accessed.
351 ///
352 /// [`Image`] is returned if generator data is valid. Valid data parameters vary by type of data
353 /// and platform.
354 ///
355 /// imageGenerator may wrap [`Picture`] data, codec data, or custom data.
356 ///
357 /// - `image_generator` stock or custom routines to retrieve [`Image`]
358 ///
359 /// Returns: created [`Image`], or `None`
360 #[deprecated(since = "0.63.0", note = "use images::deferred_from_generator()")]
361 pub fn from_generator(image_generator: ImageGenerator) -> Option<Image> {
362 images::deferred_from_generator(image_generator)
363 }
364
365 /// See [`Self::from_encoded_with_alpha_type()`]
366 pub fn from_encoded(data: impl Into<Data>) -> Option<Image> {
367 images::deferred_from_encoded_data(data, None)
368 }
369
370 /// Return an image backed by the encoded data, but attempt to defer decoding until the image
371 /// is actually used/drawn. This deferral allows the system to cache the result, either on the
372 /// CPU or on the GPU, depending on where the image is drawn. If memory is low, the cache may
373 /// be purged, causing the next draw of the image to have to re-decode.
374 ///
375 /// If alphaType is `None`, the image's alpha type will be chosen automatically based on the
376 /// image format. Transparent images will default to [`AlphaType::Premul`]. If alphaType contains
377 /// [`AlphaType::Premul`] or [`AlphaType::Unpremul`], that alpha type will be used. Forcing opaque
378 /// (passing [`AlphaType::Opaque`]) is not allowed, and will return nullptr.
379 ///
380 /// This is similar to `decode_to_{raster,texture}`, but this method will attempt to defer the
381 /// actual decode, while the `decode_to`... method explicitly decode and allocate the backend
382 /// when the call is made.
383 ///
384 /// If the encoded format is not supported, `None` is returned.
385 ///
386 /// - `encoded` the encoded data
387 ///
388 /// Returns: created [`Image`], or `None`
389 ///
390 /// example: <https://fiddle.skia.org/c/@Image_MakeFromEncoded>
391 pub fn from_encoded_with_alpha_type(
392 data: impl Into<Data>,
393 alpha_type: impl Into<Option<AlphaType>>,
394 ) -> Option<Image> {
395 images::deferred_from_encoded_data(data, alpha_type)
396 }
397
398 #[deprecated(since = "0.35.0", note = "Removed without replacement")]
399 pub fn decode_to_raster(_encoded: &[u8], _subset: impl Into<Option<IRect>>) -> ! {
400 panic!("Removed without replacement")
401 }
402
403 /// Creates a CPU-backed [`Image`] from compressed data.
404 ///
405 /// This method will decompress the compressed data and create an image wrapping
406 /// it. Any mipmap levels present in the compressed data are discarded.
407 ///
408 /// - `data` compressed data to store in [`Image`]
409 /// - `width` width of full [`Image`]
410 /// - `height` height of full [`Image`]
411 /// - `ty` type of compression used
412 ///
413 /// Returns: created [`Image`], or `None`
414 #[deprecated(
415 since = "0.63.0",
416 note = "use images::raster_from_compressed_texture_data()"
417 )]
418 pub fn new_raster_from_compressed(
419 data: impl Into<Data>,
420 dimensions: impl Into<ISize>,
421 ty: TextureCompressionType,
422 ) -> Option<Image> {
423 images::raster_from_compressed_texture_data(data, dimensions, ty)
424 }
425
426 /// See [`Self::from_picture_with_props()`]
427 #[deprecated(since = "0.63.0", note = "use images::deferred_from_picture()")]
428 pub fn from_picture(
429 picture: impl Into<Picture>,
430 dimensions: impl Into<ISize>,
431 matrix: Option<&Matrix>,
432 paint: Option<&Paint>,
433 bit_depth: BitDepth,
434 color_space: impl Into<Option<ColorSpace>>,
435 ) -> Option<Image> {
436 images::deferred_from_picture(
437 picture,
438 dimensions,
439 matrix,
440 paint,
441 bit_depth,
442 color_space,
443 None,
444 )
445 }
446
447 /// Creates [`Image`] from picture. Returned [`Image`] width and height are set by dimensions.
448 /// [`Image`] draws picture with matrix and paint, set to bitDepth and colorSpace.
449 ///
450 /// If matrix is `None`, draws with identity [`Matrix`]. If paint is `None`, draws
451 /// with default [`Paint`]. color_space may be `None`.
452 ///
453 /// - `picture` stream of drawing commands
454 /// - `dimensions` width and height
455 /// - `matrix` [`Matrix`] to rotate, scale, translate, and so on; may be `None`
456 /// - `paint` [`Paint`] to apply transparency, filtering, and so on; may be `None`
457 /// - `bitDepth` 8-bit integer or 16-bit float: per component
458 /// - `color_space` range of colors; may be `None`
459 /// - `props` props to use when rasterizing the picture
460 ///
461 /// Returns: created [`Image`], or `None`
462 #[deprecated(since = "0.63.0", note = "use images::deferred_from_picture()")]
463 pub fn from_picture_with_props(
464 picture: impl Into<Picture>,
465 dimensions: impl Into<ISize>,
466 matrix: Option<&Matrix>,
467 paint: Option<&Paint>,
468 bit_depth: BitDepth,
469 color_space: impl Into<Option<ColorSpace>>,
470 props: SurfaceProps,
471 ) -> Option<Image> {
472 images::deferred_from_picture(
473 picture,
474 dimensions,
475 matrix,
476 paint,
477 bit_depth,
478 color_space,
479 Some(props),
480 )
481 }
482
483 /// Creates a GPU-backed [`Image`] from compressed data.
484 ///
485 /// This method will return an [`Image`] representing the compressed data.
486 /// If the GPU doesn't support the specified compression method, the data
487 /// will be decompressed and then wrapped in a GPU-backed image.
488 ///
489 /// Note: one can query the supported compression formats via
490 /// [`gpu::RecordingContext::compressed_backend_format`].
491 ///
492 /// - `context` GPU context
493 /// - `data` compressed data to store in [`Image`]
494 /// - `width` width of full [`Image`]
495 /// - `height` height of full [`Image`]
496 /// - `ty` type of compression used
497 /// - `mipmapped` does 'data' contain data for all the mipmap levels?
498 /// - `is_protected` do the contents of 'data' require DRM protection (on Vulkan)?
499 ///
500 /// Returns: created [`Image`], or `None`
501 #[cfg(feature = "gpu")]
502 #[deprecated(
503 since = "0.63.0",
504 note = "use gpu::images::texture_from_compressed_texture_data()"
505 )]
506 pub fn new_texture_from_compressed(
507 context: &mut gpu::DirectContext,
508 data: Data,
509 dimensions: impl Into<ISize>,
510 ty: TextureCompressionType,
511 mipmapped: impl Into<Option<gpu::Mipmapped>>,
512 is_protected: impl Into<Option<gpu::Protected>>,
513 ) -> Option<Image> {
514 gpu::images::texture_from_compressed_texture_data(
515 context,
516 data,
517 dimensions,
518 ty,
519 mipmapped,
520 is_protected,
521 )
522 }
523
524 #[cfg(feature = "gpu")]
525 #[deprecated(since = "0.35.0", note = "Removed without replacement")]
526 pub fn from_compressed(
527 _context: &mut gpu::RecordingContext,
528 _data: Data,
529 _dimensions: impl Into<ISize>,
530 _ct: TextureCompressionType,
531 ) -> ! {
532 panic!("Removed without replacement.")
533 }
534
535 /// Creates [`Image`] from GPU texture associated with context. GPU texture must stay
536 /// valid and unchanged until `texture_release_proc` is called. `texture_release_proc` is
537 /// passed `release_context` when [`Image`] is deleted or no longer refers to texture.
538 ///
539 /// [`Image`] is returned if format of `backend_texture` is recognized and supported.
540 /// Recognized formats vary by GPU back-end.
541 ///
542 /// Note: When using a DDL recording context, `texture_release_proc` will be called on the
543 /// GPU thread after the DDL is played back on the direct context.
544 ///
545 /// * `context` GPU context
546 /// * `backend_texture` Texture residing on GPU
547 /// * `origin` Origin of `backend_texture`
548 /// * `color_type` Color type of the resulting image
549 /// * `alpha_type` Alpha type of the resulting image
550 /// * `color_space` This describes the color space of this image's contents, as
551 /// seen after sampling. In general, if the format of the backend
552 /// texture is SRGB, some linear `color_space` should be supplied
553 /// (e.g., [`ColorSpace::new_srgb_linear()`])). If the format of the
554 /// backend texture is linear, then the `color_space` should include
555 /// a description of the transfer function as
556 /// well (e.g., [`ColorSpace::MakeSRGB`]()).
557 /// * `texture_release_proc` Function called when texture can be released
558 /// * `release_context` State passed to `texture_release_proc`
559 ///
560 /// Returns: Created [`Image`], or `None`
561 #[cfg(feature = "gpu")]
562 pub fn from_texture(
563 context: &mut gpu::RecordingContext,
564 backend_texture: &gpu::BackendTexture,
565 origin: gpu::SurfaceOrigin,
566 color_type: ColorType,
567 alpha_type: AlphaType,
568 color_space: impl Into<Option<ColorSpace>>,
569 ) -> Option<Image> {
570 gpu::images::borrow_texture_from(
571 context,
572 backend_texture,
573 origin,
574 color_type,
575 alpha_type,
576 color_space,
577 )
578 }
579
580 #[deprecated(since = "0.27.0", note = "renamed, use new_cross_context_from_pixmap")]
581 #[cfg(feature = "gpu")]
582 pub fn from_pixmap_cross_context(
583 context: &mut gpu::DirectContext,
584 pixmap: &Pixmap,
585 build_mips: bool,
586 limit_to_max_texture_size: impl Into<Option<bool>>,
587 ) -> Option<Image> {
588 gpu::images::cross_context_texture_from_pixmap(
589 context,
590 pixmap,
591 build_mips,
592 limit_to_max_texture_size,
593 )
594 }
595
596 /// Creates [`Image`] from pixmap. [`Image`] is uploaded to GPU back-end using context.
597 ///
598 /// Created [`Image`] is available to other GPU contexts, and is available across thread
599 /// boundaries. All contexts must be in the same GPU share group, or otherwise
600 /// share resources.
601 ///
602 /// When [`Image`] is no longer referenced, context releases texture memory
603 /// asynchronously.
604 ///
605 /// [`ColorSpace`] of [`Image`] is determined by `pixmap.color_space()`.
606 ///
607 /// [`Image`] is returned referring to GPU back-end if context is not `None`,
608 /// format of data is recognized and supported, and if context supports moving
609 /// resources between contexts. Otherwise, pixmap pixel data is copied and [`Image`]
610 /// as returned in raster format if possible; `None` may be returned.
611 /// Recognized GPU formats vary by platform and GPU back-end.
612 ///
613 /// - `context` GPU context
614 /// - `pixmap` [`ImageInfo`], pixel address, and row bytes
615 /// - `build_mips` create [`Image`] as mip map if `true`
616 /// - `limit_to_max_texture_size` downscale image to GPU maximum texture size, if necessary
617 ///
618 /// Returns: created [`Image`], or `None`
619 #[cfg(feature = "gpu")]
620 #[deprecated(
621 since = "0.63.0",
622 note = "use gpu::images::cross_context_texture_from_pixmap()"
623 )]
624 pub fn new_cross_context_from_pixmap(
625 context: &mut gpu::DirectContext,
626 pixmap: &Pixmap,
627 build_mips: bool,
628 limit_to_max_texture_size: impl Into<Option<bool>>,
629 ) -> Option<Image> {
630 gpu::images::cross_context_texture_from_pixmap(
631 context,
632 pixmap,
633 build_mips,
634 limit_to_max_texture_size,
635 )
636 }
637
638 /// Creates [`Image`] from `backend_texture` associated with context. `backend_texture` and
639 /// returned [`Image`] are managed internally, and are released when no longer needed.
640 ///
641 /// [`Image`] is returned if format of `backend_texture` is recognized and supported.
642 /// Recognized formats vary by GPU back-end.
643 ///
644 /// - `context` GPU context
645 /// - `backend_texture` texture residing on GPU
646 /// - `texture_origin` origin of `backend_texture`
647 /// - `color_type` color type of the resulting image
648 /// - `alpha_type` alpha type of the resulting image
649 /// - `color_space` range of colors; may be `None`
650 ///
651 /// Returns: created [`Image`], or `None`
652 #[cfg(feature = "gpu")]
653 #[deprecated(since = "0.63.0", note = "use gpu::images::adopt_texture_from()")]
654 pub fn from_adopted_texture(
655 context: &mut gpu::RecordingContext,
656 backend_texture: &gpu::BackendTexture,
657 texture_origin: gpu::SurfaceOrigin,
658 color_type: ColorType,
659 alpha_type: impl Into<Option<AlphaType>>,
660 color_space: impl Into<Option<ColorSpace>>,
661 ) -> Option<Image> {
662 gpu::images::adopt_texture_from(
663 context,
664 backend_texture,
665 texture_origin,
666 color_type,
667 alpha_type,
668 color_space,
669 )
670 }
671
672 /// Creates an [`Image`] from `YUV[A]` planar textures. This requires that the textures stay valid
673 /// for the lifetime of the image. The `ReleaseContext` can be used to know when it is safe to
674 /// either delete or overwrite the textures. If `ReleaseProc` is provided it is also called before
675 /// return on failure.
676 ///
677 /// - `context` GPU context
678 /// - `yuva_textures` A set of textures containing YUVA data and a description of the
679 /// data and transformation to RGBA.
680 /// - `image_color_space` range of colors of the resulting image after conversion to RGB;
681 /// may be `None`
682 /// - `texture_release_proc` called when the backend textures can be released
683 /// - `release_context` state passed to `texture_release_proc`
684 ///
685 /// Returns: created [`Image`], or `None`
686 #[cfg(feature = "gpu")]
687 #[deprecated(
688 since = "0.63.0",
689 note = "use gpu::images::texture_from_yuva_textures()"
690 )]
691 pub fn from_yuva_textures(
692 context: &mut gpu::RecordingContext,
693 yuva_textures: &gpu::YUVABackendTextures,
694 image_color_space: impl Into<Option<ColorSpace>>,
695 ) -> Option<Image> {
696 gpu::images::texture_from_yuva_textures(context, yuva_textures, image_color_space)
697 }
698
699 /// Creates [`Image`] from [`crate::YUVAPixmaps`].
700 ///
701 /// The image will remain planar with each plane converted to a texture using the passed
702 /// [`gpu::RecordingContext`].
703 ///
704 /// [`crate::YUVAPixmaps`] has a [`crate::YUVAInfo`] which specifies the transformation from YUV to RGB.
705 /// The [`ColorSpace`] of the resulting RGB values is specified by `image_color_space`. This will
706 /// be the [`ColorSpace`] reported by the image and when drawn the RGB values will be converted
707 /// from this space into the destination space (if the destination is tagged).
708 ///
709 /// Currently, this is only supported using the GPU backend and will fail if context is `None`.
710 ///
711 /// [`crate::YUVAPixmaps`] does not need to remain valid after this returns.
712 ///
713 /// - `context` GPU context
714 /// - `pixmaps` The planes as pixmaps with supported [`crate::YUVAInfo`] that
715 /// specifies conversion to RGB.
716 /// - `build_mips` create internal YUVA textures as mip map if `Yes`. This is
717 /// silently ignored if the context does not support mip maps.
718 /// - `limit_to_max_texture_size` downscale image to GPU maximum texture size, if necessary
719 /// - `image_color_space` range of colors of the resulting image; may be `None`
720 ///
721 /// Returns: created [`Image`], or `None`
722 #[cfg(feature = "gpu")]
723 #[deprecated(
724 since = "0.63.0",
725 note = "use gpu::images::texture_from_yuva_pixmaps()"
726 )]
727 pub fn from_yuva_pixmaps(
728 context: &mut gpu::RecordingContext,
729 yuva_pixmaps: &crate::YUVAPixmaps,
730 build_mips: impl Into<Option<gpu::Mipmapped>>,
731 limit_to_max_texture_size: impl Into<Option<bool>>,
732 image_color_space: impl Into<Option<ColorSpace>>,
733 ) -> Option<Image> {
734 gpu::images::texture_from_yuva_pixmaps(
735 context,
736 yuva_pixmaps,
737 build_mips,
738 limit_to_max_texture_size,
739 image_color_space,
740 )
741 }
742
743 #[cfg(feature = "gpu")]
744 #[deprecated(since = "0.37.0", note = "Removed without replacement")]
745 pub fn from_nv12_textures_copy(
746 _context: &mut gpu::DirectContext,
747 _yuv_color_space: crate::YUVColorSpace,
748 _nv12_textures: &[gpu::BackendTexture; 2],
749 _image_origin: gpu::SurfaceOrigin,
750 _image_color_space: impl Into<Option<ColorSpace>>,
751 ) -> ! {
752 panic!("Removed without replacement")
753 }
754
755 /// Returns a [`ImageInfo`] describing the width, height, color type, alpha type, and color space
756 /// of the [`Image`].
757 ///
758 /// Returns: image info of [`Image`].
759 pub fn image_info(&self) -> &ImageInfo {
760 ImageInfo::from_native_ref(&self.native().fInfo)
761 }
762
763 /// Returns pixel count in each row.
764 ///
765 /// Returns: pixel width in [`Image`]
766 pub fn width(&self) -> i32 {
767 self.image_info().width()
768 }
769
770 /// Returns pixel row count.
771 ///
772 /// Returns: pixel height in [`Image`]
773 pub fn height(&self) -> i32 {
774 self.image_info().height()
775 }
776
777 /// Returns [`ISize`] `{ width(), height() }`.
778 ///
779 /// Returns: integral size of `width()` and `height()`
780 pub fn dimensions(&self) -> ISize {
781 self.image_info().dimensions()
782 }
783
784 /// Returns [`IRect`] `{ 0, 0, width(), height() }`.
785 ///
786 /// Returns: integral rectangle from origin to `width()` and `height()`
787 pub fn bounds(&self) -> IRect {
788 self.image_info().bounds()
789 }
790
791 /// Returns value unique to image. [`Image`] contents cannot change after [`Image`] is
792 /// created. Any operation to create a new [`Image`] will receive generate a new
793 /// unique number.
794 ///
795 /// Returns: unique identifier
796 pub fn unique_id(&self) -> u32 {
797 self.native().fUniqueID
798 }
799
800 /// Returns [`AlphaType`].
801 ///
802 /// [`AlphaType`] returned was a parameter to an [`Image`] constructor,
803 /// or was parsed from encoded data.
804 ///
805 /// Returns: [`AlphaType`] in [`Image`]
806 ///
807 /// example: <https://fiddle.skia.org/c/@Image_alphaType>
808 pub fn alpha_type(&self) -> AlphaType {
809 unsafe { self.native().alphaType() }
810 }
811
812 /// Returns [`ColorType`] if known; otherwise, returns [`ColorType::Unknown`].
813 ///
814 /// Returns: [`ColorType`] of [`Image`]
815 ///
816 /// example: <https://fiddle.skia.org/c/@Image_colorType>
817 pub fn color_type(&self) -> ColorType {
818 ColorType::from_native_c(unsafe { self.native().colorType() })
819 }
820
821 /// Returns a smart pointer to [`ColorSpace`], the range of colors, associated with
822 /// [`Image`]. The smart pointer tracks the number of objects sharing this
823 /// [`ColorSpace`] reference so the memory is released when the owners destruct.
824 ///
825 /// The returned [`ColorSpace`] is immutable.
826 ///
827 /// [`ColorSpace`] returned was passed to an [`Image`] constructor,
828 /// or was parsed from encoded data. [`ColorSpace`] returned may be ignored when [`Image`]
829 /// is drawn, depending on the capabilities of the [`crate::Surface`] receiving the drawing.
830 ///
831 /// Returns: [`ColorSpace`] in [`Image`], or `None`, wrapped in a smart pointer
832 ///
833 /// example: <https://fiddle.skia.org/c/@Image_refColorSpace>
834 pub fn color_space(&self) -> Option<ColorSpace> {
835 ColorSpace::from_unshared_ptr(unsafe { self.native().colorSpace() })
836 }
837
838 /// Returns `true` if [`Image`] pixels represent transparency only. If `true`, each pixel
839 /// is packed in 8 bits as defined by [`ColorType::Alpha8`].
840 ///
841 /// Returns: `true` if pixels represent a transparency mask
842 ///
843 /// example: <https://fiddle.skia.org/c/@Image_isAlphaOnly>
844 pub fn is_alpha_only(&self) -> bool {
845 unsafe { self.native().isAlphaOnly() }
846 }
847
848 /// Returns `true` if pixels ignore their alpha value and are treated as fully opaque.
849 ///
850 /// Returns: `true` if [`AlphaType`] is [`AlphaType::Opaque`]
851 pub fn is_opaque(&self) -> bool {
852 self.alpha_type().is_opaque()
853 }
854
855 /// Make a shader with the specified tiling and mipmap sampling.
856 pub fn to_shader<'a>(
857 &self,
858 tile_modes: impl Into<Option<(TileMode, TileMode)>>,
859 sampling: impl Into<SamplingOptions>,
860 local_matrix: impl Into<Option<&'a Matrix>>,
861 ) -> Option<Shader> {
862 let tile_modes = tile_modes.into();
863 let tm1 = tile_modes.map(|(tm, _)| tm).unwrap_or_default();
864 let tm2 = tile_modes.map(|(_, tm)| tm).unwrap_or_default();
865 let sampling = sampling.into();
866
867 Shader::from_ptr(unsafe {
868 sb::C_SkImage_makeShader(
869 self.native(),
870 tm1,
871 tm2,
872 sampling.native(),
873 local_matrix.into().native_ptr_or_null(),
874 )
875 })
876 }
877
878 /// `to_raw_shader` functions like `to_shader`, but for images that contain non-color data.
879 /// This includes images encoding things like normals, material properties (eg, roughness),
880 /// heightmaps, or any other purely mathematical data that happens to be stored in an image.
881 /// These types of images are useful with some programmable shaders (see: [`crate::RuntimeEffect`]).
882 ///
883 /// Raw image shaders work like regular image shaders (including filtering and tiling), with
884 /// a few major differences:
885 /// - No color space transformation is ever applied (the color space of the image is ignored).
886 /// - Images with an alpha type of `Unpremul` are *not* automatically premultiplied.
887 /// - Bicubic filtering is not supported. If [`SamplingOptions::use_cubic`] is `true`, these
888 /// factories will return `None`.
889 pub fn to_raw_shader<'a>(
890 &self,
891 tile_modes: impl Into<Option<(TileMode, TileMode)>>,
892 sampling: impl Into<SamplingOptions>,
893 local_matrix: impl Into<Option<&'a Matrix>>,
894 ) -> Option<Shader> {
895 let tile_modes = tile_modes.into();
896 let tm1 = tile_modes.map(|(tm, _)| tm).unwrap_or_default();
897 let tm2 = tile_modes.map(|(_, tm)| tm).unwrap_or_default();
898 let sampling = sampling.into();
899
900 Shader::from_ptr(unsafe {
901 sb::C_SkImage_makeRawShader(
902 self.native(),
903 tm1,
904 tm2,
905 sampling.native(),
906 local_matrix.into().native_ptr_or_null(),
907 )
908 })
909 }
910
911 /// Copies [`Image`] pixel address, row bytes, and [`ImageInfo`] to pixmap, if address
912 /// is available, and returns `true`. If pixel address is not available, return
913 /// `false` and leave pixmap unchanged.
914 ///
915 /// - `pixmap` storage for pixel state if pixels are readable; otherwise, ignored
916 ///
917 /// Returns: `true` if [`Image`] has direct access to pixels
918 ///
919 /// example: <https://fiddle.skia.org/c/@Image_peekPixels>
920 pub fn peek_pixels(&self) -> Option<Pixmap> {
921 let mut pixmap = Pixmap::default();
922 unsafe { self.native().peekPixels(pixmap.native_mut()) }.then_some(pixmap)
923 }
924
925 /// Returns `true` if the contents of [`Image`] was created on or uploaded to GPU memory,
926 /// and is available as a GPU texture.
927 ///
928 /// Returns: `true` if [`Image`] is a GPU texture
929 ///
930 /// example: <https://fiddle.skia.org/c/@Image_isTextureBacked>
931 pub fn is_texture_backed(&self) -> bool {
932 unsafe { sb::C_SkImage_isTextureBacked(self.native()) }
933 }
934
935 /// Returns an approximation of the amount of texture memory used by the image. Returns
936 /// zero if the image is not texture backed or if the texture has an external format.
937 pub fn texture_size(&self) -> usize {
938 unsafe { sb::C_SkImage_textureSize(self.native()) }
939 }
940
941 /// Returns `true` if [`Image`] can be drawn on either raster surface or GPU surface.
942 /// If recorder is None, tests if SkImage draws on raster surface;
943 /// otherwise, tests if SkImage draws on the associated GPU surface.
944 ///
945 /// [`Image`] backed by GPU texture may become invalid if associated context is
946 /// invalid. lazy image may be invalid and may not draw to raster surface or
947 /// GPU surface or both.
948 ///
949 /// - `context` GPU context
950 ///
951 /// Returns: `true` if [`Image`] can be drawn
952 ///
953 /// example: <https://fiddle.skia.org/c/@Image_isValid>
954 pub fn is_valid(&self, recorder: Option<&mut dyn Recorder>) -> bool {
955 unsafe {
956 sb::C_SkImage_isValid(
957 self.native(),
958 recorder
959 .map(|r| r.as_recorder_ref())
960 .native_ptr_or_null_mut(),
961 )
962 }
963 }
964
965 /// Create a new image by copying this image and scaling to fit the [`ImageInfo`]'s dimensions
966 /// and converting the pixels into the ImageInfo's [`crate::ColorInfo`].
967 ///
968 /// This is done retaining the domain (backend) of the image (e.g. gpu, raster).
969 ///
970 /// Returns `None` if the requested [`crate::ColorInfo`] is not supported, its dimensions are out
971 /// of range.
972 pub fn make_scaled(
973 &self,
974 info: &ImageInfo,
975 scaling: impl Into<SamplingOptions>,
976 ) -> Option<Image> {
977 Image::from_ptr(unsafe {
978 sb::C_SkImage_makeScaled(self.native(), info.native(), scaling.into().native())
979 })
980 }
981
982 /// See [`Self::flush_with_info()`]
983 #[cfg(feature = "gpu")]
984 #[deprecated(since = "0.63.0", note = "use gpu::DirectContext::flush()")]
985 pub fn flush<'a>(
986 &self,
987 context: &mut gpu::DirectContext,
988 flush_info: impl Into<Option<&'a gpu::FlushInfo>>,
989 ) -> gpu::SemaphoresSubmitted {
990 context.flush(flush_info)
991 }
992
993 /// Flushes any pending uses of texture-backed images in the GPU backend. If the image is not
994 /// texture-backed (including promise texture images) or if the [`gpu::DirectContext`] does not
995 /// have the same context ID as the context backing the image then this is a no-op.
996 ///
997 /// If the image was not used in any non-culled draws in the current queue of work for the
998 /// passed [`gpu::DirectContext`] then this is a no-op unless the [`gpu::FlushInfo`] contains semaphores or
999 /// a finish proc. Those are respected even when the image has not been used.
1000 ///
1001 /// - `context` the context on which to flush pending usages of the image.
1002 /// - `info` flush options
1003 #[cfg(feature = "gpu")]
1004 #[deprecated(since = "0.46.0", note = "use gpu::DirectContext::flush()")]
1005 pub fn flush_with_info(
1006 &self,
1007 context: &mut gpu::DirectContext,
1008 flush_info: &gpu::FlushInfo,
1009 ) -> gpu::SemaphoresSubmitted {
1010 context.flush(flush_info)
1011 }
1012
1013 /// Version of `flush()` that uses a default [`gpu::FlushInfo`]. Also submits the flushed work to the
1014 /// GPU.
1015 #[cfg(feature = "gpu")]
1016 #[deprecated(since = "0.63.0", note = "use gpu::DirectContext::flush_and_submit()")]
1017 pub fn flush_and_submit(&self, context: &mut gpu::DirectContext) {
1018 context.flush_and_submit();
1019 }
1020
1021 /// Retrieves the back-end texture. If [`Image`] has no back-end texture, `None`is returned.
1022 ///
1023 /// If `flush_pending_gr_context_io` is `true`, completes deferred I/O operations.
1024 ///
1025 /// If origin in not `None`, copies location of content drawn into [`Image`].
1026 ///
1027 /// - `flush_pending_gr_context_io` flag to flush outstanding requests
1028 ///
1029 /// Returns: back-end API texture handle; invalid on failure
1030 #[cfg(feature = "gpu")]
1031 #[deprecated(
1032 since = "0.63.0",
1033 note = "use gpu::images::get_backend_texture_from_image()"
1034 )]
1035 pub fn backend_texture(
1036 &self,
1037 flush_pending_gr_context_io: bool,
1038 ) -> Option<(gpu::BackendTexture, gpu::SurfaceOrigin)> {
1039 gpu::images::get_backend_texture_from_image(self, flush_pending_gr_context_io)
1040 }
1041
1042 /// Copies [`crate::Rect`] of pixels from [`Image`] to `dst_pixels`. Copy starts at offset (`src_x`, `src_y`),
1043 /// and does not exceed [`Image`] (width(), height()).
1044 ///
1045 /// Graphite has deprecated this API in favor of the equivalent asynchronous API on
1046 /// `skgpu::graphite::Context` (with an optional explicit synchronization).
1047 ///
1048 /// `dst_info` specifies width, height, [`ColorType`], [`AlphaType`], and [`ColorSpace`] of
1049 /// destination. `dst_row_bytes` specifies the gap from one destination row to the next.
1050 /// Returns `true` if pixels are copied. Returns `false` if:
1051 /// - `dst_info`.`addr()` equals `None`
1052 /// - `dst_row_bytes` is less than `dst_info.min_row_bytes()`
1053 /// - [`crate::PixelRef`] is `None`
1054 ///
1055 /// Pixels are copied only if pixel conversion is possible. If [`Image`] [`ColorType`] is
1056 /// [`ColorType::Gray8`], or [`ColorType::Alpha8`]; `dst_info.color_type()` must match.
1057 /// If [`Image`] [`ColorType`] is [`ColorType::Gray8`], `dst_info`.`color_space()` must match.
1058 /// If [`Image`] [`AlphaType`] is [`AlphaType::Opaque`], `dst_info`.`alpha_type()` must
1059 /// match. If [`Image`] [`ColorSpace`] is `None`, `dst_info.color_space()` must match. Returns
1060 /// `false` if pixel conversion is not possible.
1061 ///
1062 /// `src_x` and `src_y` may be negative to copy only top or left of source. Returns
1063 /// `false` if `width()` or `height()` is zero or negative.
1064 /// Returns `false` if abs(`src_x`) >= Image width(), or if abs(`src_y`) >= Image height().
1065 ///
1066 /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1067 /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1068 ///
1069 /// - `context` the [`gpu::DirectContext`] in play, if it exists
1070 /// - `dst_info` destination width, height, [`ColorType`], [`AlphaType`], [`ColorSpace`]
1071 /// - `dst_pixels` destination pixel storage
1072 /// - `dst_row_bytes` destination row length
1073 /// - `src_x` column index whose absolute value is less than `width()`
1074 /// - `src_y` row index whose absolute value is less than `height()`
1075 /// - `caching_hint` whether the pixels should be cached locally
1076 ///
1077 /// Returns: `true` if pixels are copied to `dst_pixels`
1078 #[cfg(feature = "gpu")]
1079 pub fn read_pixels_with_context<'a, P>(
1080 &self,
1081 context: impl Into<Option<&'a mut gpu::DirectContext>>,
1082 dst_info: &ImageInfo,
1083 pixels: &mut [P],
1084 dst_row_bytes: usize,
1085 src: impl Into<IPoint>,
1086 caching_hint: CachingHint,
1087 ) -> bool {
1088 if !dst_info.valid_pixels(dst_row_bytes, pixels) {
1089 return false;
1090 }
1091
1092 let src = src.into();
1093
1094 unsafe {
1095 self.native().readPixels(
1096 context.into().native_ptr_or_null_mut(),
1097 dst_info.native(),
1098 pixels.as_mut_ptr() as _,
1099 dst_row_bytes,
1100 src.x,
1101 src.y,
1102 caching_hint,
1103 )
1104 }
1105 }
1106
1107 /// Copies a [`crate::Rect`] of pixels from [`Image`] to dst. Copy starts at (`src_x`, `src_y`), and
1108 /// does not exceed [`Image`] (width(), height()).
1109 ///
1110 /// Graphite has deprecated this API in favor of the equivalent asynchronous API on
1111 /// `skgpu::graphite::Context` (with an optional explicit synchronization).
1112 ///
1113 /// dst specifies width, height, [`ColorType`], [`AlphaType`], [`ColorSpace`], pixel storage,
1114 /// and row bytes of destination. dst.`row_bytes()` specifics the gap from one destination
1115 /// row to the next. Returns `true` if pixels are copied. Returns `false` if:
1116 /// - dst pixel storage equals `None`
1117 /// - dst.`row_bytes` is less than [`ImageInfo::min_row_bytes`]
1118 /// - [`crate::PixelRef`] is `None`
1119 ///
1120 /// Pixels are copied only if pixel conversion is possible. If [`Image`] [`ColorType`] is
1121 /// [`ColorType::Gray8`], or [`ColorType::Alpha8`]; dst.`color_type()` must match.
1122 /// If [`Image`] [`ColorType`] is [`ColorType::Gray8`], dst.`color_space()` must match.
1123 /// If [`Image`] [`AlphaType`] is [`AlphaType::Opaque`], dst.`alpha_type()` must
1124 /// match. If [`Image`] [`ColorSpace`] is `None`, dst.`color_space()` must match. Returns
1125 /// `false` if pixel conversion is not possible.
1126 ///
1127 /// `src_x` and `src_y` may be negative to copy only top or left of source. Returns
1128 /// `false` if `width()` or `height()` is zero or negative.
1129 /// Returns `false` if abs(`src_x`) >= Image width(), or if abs(`src_y`) >= Image height().
1130 ///
1131 /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1132 /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1133 ///
1134 /// - `context` the [`gpu::DirectContext`] in play, if it exists
1135 /// - `dst` destination [`Pixmap`]:[`ImageInfo`], pixels, row bytes
1136 /// - `src_x` column index whose absolute value is less than `width()`
1137 /// - `src_y` row index whose absolute value is less than `height()`
1138 /// - `caching_hint` whether the pixels should be cached `locally_z`
1139 ///
1140 /// Returns: `true` if pixels are copied to dst
1141 #[cfg(feature = "gpu")]
1142 pub fn read_pixels_to_pixmap_with_context<'a>(
1143 &self,
1144 context: impl Into<Option<&'a mut gpu::DirectContext>>,
1145 dst: &Pixmap,
1146 src: impl Into<IPoint>,
1147 caching_hint: CachingHint,
1148 ) -> bool {
1149 let src = src.into();
1150
1151 unsafe {
1152 self.native().readPixels1(
1153 context.into().native_ptr_or_null_mut(),
1154 dst.native(),
1155 src.x,
1156 src.y,
1157 caching_hint,
1158 )
1159 }
1160 }
1161
1162 // _not_ deprecated, because we support separate functions in `gpu` feature builds.
1163 /// See [`Self::read_pixels_with_context()`]
1164 pub fn read_pixels<P>(
1165 &self,
1166 dst_info: &ImageInfo,
1167 pixels: &mut [P],
1168 dst_row_bytes: usize,
1169 src: impl Into<IPoint>,
1170 caching_hint: CachingHint,
1171 ) -> bool {
1172 if !dst_info.valid_pixels(dst_row_bytes, pixels) {
1173 return false;
1174 }
1175
1176 let src = src.into();
1177
1178 unsafe {
1179 self.native().readPixels(
1180 ptr::null_mut(),
1181 dst_info.native(),
1182 pixels.as_mut_ptr() as _,
1183 dst_row_bytes,
1184 src.x,
1185 src.y,
1186 caching_hint,
1187 )
1188 }
1189 }
1190
1191 /// See [`Self::read_pixels_to_pixmap_with_context()`]
1192 #[cfg(feature = "gpu")]
1193 #[allow(clippy::missing_safety_doc)]
1194 pub unsafe fn read_pixels_to_pixmap(
1195 &self,
1196 dst: &Pixmap,
1197 src: impl Into<IPoint>,
1198 caching_hint: CachingHint,
1199 ) -> bool {
1200 let src = src.into();
1201
1202 unsafe {
1203 self.native()
1204 .readPixels1(ptr::null_mut(), dst.native(), src.x, src.y, caching_hint)
1205 }
1206 }
1207
1208 // TODO:
1209 // AsyncReadResult,
1210 // ReadPixelsContext,
1211 // ReadPixelsCallback,
1212 // RescaleGamma,
1213 // RescaleMode,
1214 // asyncRescaleAndReadPixels,
1215 // asyncRescaleAndReadPixelsYUV420,
1216 // asyncRescaleAndReadPixelsYUVA420
1217
1218 /// Copies [`Image`] to dst, scaling pixels to fit `dst.width()` and `dst.height()`, and
1219 /// converting pixels to match `dst.color_type()` and `dst.alpha_type()`. Returns `true` if
1220 /// pixels are copied. Returns `false` if `dst.addr()` is `None`, or `dst.row_bytes()` is
1221 /// less than dst [`ImageInfo::min_row_bytes`].
1222 ///
1223 /// Pixels are copied only if pixel conversion is possible. If [`Image`] [`ColorType`] is
1224 /// [`ColorType::Gray8`], or [`ColorType::Alpha8`]; `dst.color_type()` must match.
1225 /// If [`Image`] [`ColorType`] is [`ColorType::Gray8`], `dst.color_space()` must match.
1226 /// If [`Image`] [`AlphaType`] is [`AlphaType::Opaque`], `dst.alpha_type()` must
1227 /// match. If [`Image`] [`ColorSpace`] is `None`, `dst.color_space()` must match. Returns
1228 /// `false` if pixel conversion is not possible.
1229 ///
1230 /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1231 /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1232 ///
1233 /// - `dst` destination [`Pixmap`]:[`ImageInfo`], pixels, row bytes
1234 ///
1235 /// Returns: `true` if pixels are scaled to fit dst
1236 #[must_use]
1237 pub fn scale_pixels(
1238 &self,
1239 dst: &Pixmap,
1240 sampling: impl Into<SamplingOptions>,
1241 caching_hint: impl Into<Option<CachingHint>>,
1242 ) -> bool {
1243 unsafe {
1244 self.native().scalePixels(
1245 dst.native(),
1246 sampling.into().native(),
1247 caching_hint.into().unwrap_or(CachingHint::Allow),
1248 )
1249 }
1250 }
1251
1252 /// Encodes [`Image`] pixels, returning result as [`Data`].
1253 ///
1254 /// Returns `None` if encoding fails, or if `encoded_image_format` is not supported.
1255 ///
1256 /// [`Image`] encoding in a format requires both building with one or more of:
1257 /// SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP; and platform support
1258 /// for the encoded format.
1259 ///
1260 /// If SK_BUILD_FOR_MAC or SK_BUILD_FOR_IOS is defined, `encoded_image_format` can
1261 /// additionally be one of: [`EncodedImageFormat::ICO`], [`EncodedImageFormat::BMP`],
1262 /// [`EncodedImageFormat::GIF`].
1263 ///
1264 /// quality is a platform and format specific metric trading off size and encoding
1265 /// error. When used, quality equaling 100 encodes with the least error. quality may
1266 /// be ignored by the encoder.
1267 ///
1268 /// * `context` - the [`gpu::DirectContext`] in play, if it exists; can be `None`
1269 /// * `encoded_image_format` - one of: [`EncodedImageFormat::JPEG`], [`EncodedImageFormat::PNG`],
1270 /// [`EncodedImageFormat::WEBP`]
1271 /// * `quality` - encoder specific metric with 100 equaling best
1272 ///
1273 /// Returns: encoded [`Image`], or `None`
1274 ///
1275 /// example: <https://fiddle.skia.org/c/@Image_encodeToData>
1276 #[cfg(feature = "gpu")]
1277 #[deprecated(since = "0.63.0", note = "Use encode")]
1278 pub fn encode_to_data_with_context(
1279 &self,
1280 context: impl Into<Option<gpu::DirectContext>>,
1281 image_format: EncodedImageFormat,
1282 quality: impl Into<Option<u32>>,
1283 ) -> Option<Data> {
1284 let mut context = context.into();
1285 self.encode(context.as_mut(), image_format, quality)
1286 }
1287
1288 /// See [`Self::encode_to_data_with_quality`]
1289 #[deprecated(
1290 since = "0.63.0",
1291 note = "Support for encoding GPU backed images without a context was removed, use `encode_to_data_with_context` instead"
1292 )]
1293 pub fn encode_to_data(&self, image_format: EncodedImageFormat) -> Option<Data> {
1294 self.encode(None, image_format, 100)
1295 }
1296
1297 /// Encodes [`Image`] pixels, returning result as [`Data`].
1298 ///
1299 /// Returns `None` if encoding fails, or if `encoded_image_format` is not supported.
1300 ///
1301 /// [`Image`] encoding in a format requires both building with one or more of:
1302 /// SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP; and platform support
1303 /// for the encoded format.
1304 ///
1305 /// If SK_BUILD_FOR_MAC or SK_BUILD_FOR_IOS is defined, `encoded_image_format` can
1306 /// additionally be one of: [`EncodedImageFormat::ICO`], [`EncodedImageFormat::BMP`],
1307 /// [`EncodedImageFormat::GIF`].
1308 ///
1309 /// quality is a platform and format specific metric trading off size and encoding
1310 /// error. When used, quality equaling 100 encodes with the least error. quality may
1311 /// be ignored by the encoder.
1312 ///
1313 /// - `encoded_image_format` one of: [`EncodedImageFormat::JPEG`], [`EncodedImageFormat::PNG`],
1314 /// [`EncodedImageFormat::WEBP`]
1315 /// - `quality` encoder specific metric with 100 equaling best
1316 ///
1317 /// Returns: encoded [`Image`], or `None`
1318 ///
1319 /// example: <https://fiddle.skia.org/c/@Image_encodeToData>
1320 #[deprecated(
1321 since = "0.63.0",
1322 note = "Support for encoding GPU backed images without a context was removed, use `encode_to_data_with_context` instead"
1323 )]
1324 pub fn encode_to_data_with_quality(
1325 &self,
1326 image_format: EncodedImageFormat,
1327 quality: u32,
1328 ) -> Option<Data> {
1329 self.encode(None, image_format, quality)
1330 }
1331
1332 /// Returns encoded [`Image`] pixels as [`Data`], if [`Image`] was created from supported
1333 /// encoded stream format. Platform support for formats vary and may require building
1334 /// with one or more of: SK_ENCODE_JPEG, SK_ENCODE_PNG, SK_ENCODE_WEBP.
1335 ///
1336 /// Returns `None` if [`Image`] contents are not encoded.
1337 ///
1338 /// Returns: encoded [`Image`], or `None`
1339 ///
1340 /// example: <https://fiddle.skia.org/c/@Image_refEncodedData>
1341 pub fn encoded_data(&self) -> Option<Data> {
1342 Data::from_ptr_const(unsafe { sb::C_SkImage_refEncodedData(self.native()) })
1343 }
1344
1345 /// Returns subset of this image.
1346 ///
1347 /// Returns `None` if any of the following are true:
1348 /// - Subset is empty
1349 /// - Subset is not contained inside the image's bounds
1350 /// - Pixels in the image could not be read or copied
1351 /// - This image is texture-backed and the provided context is null or does not match
1352 /// the source image's context.
1353 ///
1354 /// If the source image was texture-backed, the resulting image will be texture-backed also.
1355 /// Otherwise, the returned image will be raster-backed.
1356 ///
1357 /// * `recorder` - the recorder of the source image (`None` is ok if the
1358 /// source image was texture-backed).
1359 /// * `subset` - bounds of returned [`Image`]
1360 /// * `required_properties` - properties the returned [`Image`] must possess (e.g. mipmaps)
1361 ///
1362 /// Returns: the subsetted image, or `None`
1363 pub fn make_subset(
1364 &self,
1365 recorder: Option<&mut dyn Recorder>,
1366 subset: impl AsRef<IRect>,
1367 required_properties: RequiredProperties,
1368 ) -> Option<Image> {
1369 Image::from_ptr(unsafe {
1370 sb::C_SkImage_makeSubset(
1371 self.native(),
1372 recorder
1373 .map(|r| r.as_recorder_ref())
1374 .native_ptr_or_null_mut(),
1375 subset.as_ref().native(),
1376 required_properties.native(),
1377 )
1378 })
1379 }
1380
1381 /// Returns `true` if the image has mipmap levels.
1382 pub fn has_mipmaps(&self) -> bool {
1383 unsafe { self.native().hasMipmaps() }
1384 }
1385
1386 /// Returns an image with the same "base" pixels as the this image, but with mipmap levels
1387 /// automatically generated and attached.
1388 pub fn with_default_mipmaps(&self) -> Option<Image> {
1389 Image::from_ptr(unsafe { sb::C_SkImage_withDefaultMipmaps(self.native()) })
1390 }
1391
1392 /// See [`Self::new_texture_image_budgeted`]
1393 #[cfg(feature = "gpu")]
1394 pub fn new_texture_image(
1395 &self,
1396 context: &mut gpu::DirectContext,
1397 mipmapped: gpu::Mipmapped,
1398 ) -> Option<Image> {
1399 self.new_texture_image_budgeted(context, mipmapped, gpu::Budgeted::Yes)
1400 }
1401
1402 /// Returns [`Image`] backed by GPU texture associated with context. Returned [`Image`] is
1403 /// compatible with [`crate::Surface`] created with `dst_color_space`. The returned [`Image`] respects
1404 /// mipmapped setting; if mipmapped equals [`gpu::Mipmapped::Yes`], the backing texture
1405 /// allocates mip map levels.
1406 ///
1407 /// The mipmapped parameter is effectively treated as `No` if MIP maps are not supported by the
1408 /// GPU.
1409 ///
1410 /// Returns original [`Image`] if the image is already texture-backed, the context matches, and
1411 /// mipmapped is compatible with the backing GPU texture. [`crate::Budgeted`] is ignored in this case.
1412 ///
1413 /// Returns `None` if context is `None`, or if [`Image`] was created with another
1414 /// [`gpu::DirectContext`].
1415 ///
1416 /// - `direct_context` the [`gpu::DirectContext`] in play, if it exists
1417 /// - `mipmapped` whether created [`Image`] texture must allocate mip map levels
1418 /// - `budgeted` whether to count a newly created texture for the returned image
1419 /// counts against the context's budget.
1420 ///
1421 /// Returns: created [`Image`], or `None`
1422 #[cfg(feature = "gpu")]
1423 pub fn new_texture_image_budgeted(
1424 &self,
1425 direct_context: &mut gpu::DirectContext,
1426 mipmapped: gpu::Mipmapped,
1427 budgeted: gpu::Budgeted,
1428 ) -> Option<Image> {
1429 gpu::images::texture_from_image(direct_context, self, mipmapped, budgeted)
1430 }
1431
1432 /// Returns raster image or lazy image. Copies [`Image`] backed by GPU texture into
1433 /// CPU memory if needed. Returns original [`Image`] if decoded in raster bitmap,
1434 /// or if encoded in a stream.
1435 ///
1436 /// Returns `None` if backed by GPU texture and copy fails.
1437 ///
1438 /// Returns: raster image, lazy image, or `None`
1439 ///
1440 /// example: <https://fiddle.skia.org/c/@Image_makeNonTextureImage>
1441 #[deprecated(since = "0.64.0", note = "use make_non_texture_image()")]
1442 pub fn to_non_texture_image(&self) -> Option<Image> {
1443 Image::from_ptr(unsafe {
1444 sb::C_SkImage_makeNonTextureImage(self.native(), ptr::null_mut())
1445 })
1446 }
1447
1448 /// Returns raster image or lazy image. Copies [`Image`] backed by GPU texture into
1449 /// CPU memory if needed. Returns original [`Image`] if decoded in raster bitmap,
1450 /// or if encoded in a stream.
1451 ///
1452 /// Returns `None` if backed by GPU texture and copy fails.
1453 ///
1454 /// Returns: raster image, lazy image, or `None`
1455 ///
1456 /// example: <https://fiddle.skia.org/c/@Image_makeNonTextureImage>
1457 pub fn make_non_texture_image<'a>(
1458 &self,
1459 context: impl Into<Option<&'a mut gpu::DirectContext>>,
1460 ) -> Option<Image> {
1461 Image::from_ptr(unsafe {
1462 sb::C_SkImage_makeNonTextureImage(
1463 self.native(),
1464 context.into().native_ptr_or_null_mut(),
1465 )
1466 })
1467 }
1468
1469 /// Returns raster image. Copies [`Image`] backed by GPU texture into CPU memory,
1470 /// or decodes [`Image`] from lazy image. Returns original [`Image`] if decoded in
1471 /// raster bitmap.
1472 ///
1473 /// Returns `None` if copy, decode, or pixel read fails.
1474 ///
1475 /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1476 /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1477 ///
1478 /// Returns: raster image, or `None`
1479 ///
1480 /// example: <https://fiddle.skia.org/c/@Image_makeRasterImage>
1481 #[deprecated(since = "0.64.0", note = "use make_raster_image()")]
1482 pub fn to_raster_image(&self, caching_hint: impl Into<Option<CachingHint>>) -> Option<Image> {
1483 let caching_hint = caching_hint.into().unwrap_or(CachingHint::Disallow);
1484 Image::from_ptr(unsafe {
1485 sb::C_SkImage_makeRasterImage(self.native(), ptr::null_mut(), caching_hint)
1486 })
1487 }
1488
1489 /// Returns raster image. Copies [`Image`] backed by GPU texture into CPU memory,
1490 /// or decodes [`Image`] from lazy image. Returns original [`Image`] if decoded in
1491 /// raster bitmap.
1492 ///
1493 /// Returns `None` if copy, decode, or pixel read fails.
1494 ///
1495 /// If `caching_hint` is [`CachingHint::Allow`], pixels may be retained locally.
1496 /// If `caching_hint` is [`CachingHint::Disallow`], pixels are not added to the local cache.
1497 ///
1498 /// Returns: raster image, or `None`
1499 ///
1500 /// example: <https://fiddle.skia.org/c/@Image_makeRasterImage>
1501 pub fn make_raster_image<'a>(
1502 &self,
1503 context: impl Into<Option<&'a mut gpu::DirectContext>>,
1504 caching_hint: impl Into<Option<CachingHint>>,
1505 ) -> Option<Image> {
1506 let caching_hint = caching_hint.into().unwrap_or(CachingHint::Disallow);
1507 Image::from_ptr(unsafe {
1508 sb::C_SkImage_makeRasterImage(
1509 self.native(),
1510 context.into().native_ptr_or_null_mut(),
1511 caching_hint,
1512 )
1513 })
1514 }
1515
1516 /// Creates filtered [`Image`]. filter processes original [`Image`], potentially changing
1517 /// color, position, and size. subset is the bounds of original [`Image`] processed
1518 /// by filter. `clip_bounds` is the expected bounds of the filtered [`Image`]. `out_subset`
1519 /// is required storage for the actual bounds of the filtered [`Image`]. offset is
1520 /// required storage for translation of returned [`Image`].
1521 ///
1522 /// Returns `None` if [`Image`] could not be created or if the recording context provided doesn't
1523 /// match the GPU context in which the image was created. If `None` is returned, `out_subset`
1524 /// and offset are undefined.
1525 ///
1526 /// Useful for animation of [`ImageFilter`] that varies size from frame to frame.
1527 /// Returned [`Image`] is created larger than required by filter so that GPU texture
1528 /// can be reused with different sized effects. `out_subset` describes the valid bounds
1529 /// of GPU texture returned. offset translates the returned [`Image`] to keep subsequent
1530 /// animation frames aligned with respect to each other.
1531 ///
1532 /// - `context` the [`gpu::RecordingContext`] in play - if it exists
1533 /// - `filter` how [`Image`] is sampled when transformed
1534 /// - `subset` bounds of [`Image`] processed by filter
1535 /// - `clip_bounds` expected bounds of filtered [`Image`]
1536 /// - `out_subset` storage for returned [`Image`] bounds
1537 /// - `offset` storage for returned [`Image`] translation
1538 ///
1539 /// Returns: filtered [`Image`], or `None`
1540 #[deprecated(since = "0.67.0", note = "use images::make_with_filter()")]
1541 pub fn new_with_filter(
1542 &self,
1543 _context: Option<&mut gpu::RecordingContext>,
1544 filter: &ImageFilter,
1545 clip_bounds: impl Into<IRect>,
1546 subset: impl Into<IRect>,
1547 ) -> Option<(Image, IRect, IPoint)> {
1548 images::make_with_filter(self, filter, subset.into(), clip_bounds.into())
1549 }
1550
1551 // TODO: MakeBackendTextureFromSkImage()
1552
1553 /// Returns `true` if [`Image`] is backed by an image-generator or other service that creates
1554 /// and caches its pixels or texture on-demand.
1555 ///
1556 /// Returns: `true` if [`Image`] is created as needed
1557 ///
1558 /// example: <https://fiddle.skia.org/c/@Image_isLazyGenerated_a>
1559 /// example: <https://fiddle.skia.org/c/@Image_isLazyGenerated_b>
1560 pub fn is_lazy_generated(&self) -> bool {
1561 unsafe { sb::C_SkImage_isLazyGenerated(self.native()) }
1562 }
1563
1564 /// Creates [`Image`] in target [`ColorSpace`].
1565 /// Returns `None` if [`Image`] could not be created.
1566 ///
1567 /// Returns original [`Image`] if it is in target [`ColorSpace`].
1568 /// Otherwise, converts pixels from [`Image`] [`ColorSpace`] to target [`ColorSpace`].
1569 /// If [`Image`] `color_space()` returns `None`, [`Image`] [`ColorSpace`] is assumed to be `s_rgb`.
1570 ///
1571 /// If this image is graphite-backed, the recorder parameter is required.
1572 ///
1573 /// * `target_color_space` - [`ColorSpace`] describing color range of returned [`Image`]
1574 /// * `recorder` - The Recorder in which to create the new image
1575 /// * `required_properties` - properties the returned [`Image`] must possess (e.g. mipmaps)
1576 ///
1577 /// Returns: created [`Image`] in target [`ColorSpace`]
1578 pub fn make_color_space(
1579 &self,
1580 recorder: Option<&mut dyn Recorder>,
1581 color_space: impl Into<Option<ColorSpace>>,
1582 required_properties: RequiredProperties,
1583 ) -> Option<Image> {
1584 Image::from_ptr(unsafe {
1585 sb::C_SkImage_makeColorSpace(
1586 self.native(),
1587 recorder
1588 .map(|r| r.as_recorder_ref())
1589 .native_ptr_or_null_mut(),
1590 color_space.into().into_ptr_or_null(),
1591 required_properties.native(),
1592 )
1593 })
1594 }
1595
1596 /// Creates a new [`Image`] identical to this one, but with a different [`ColorSpace`].
1597 /// This does not convert the underlying pixel data, so the resulting image will draw
1598 /// differently.
1599 pub fn reinterpret_color_space(&self, new_color_space: impl Into<ColorSpace>) -> Option<Image> {
1600 Image::from_ptr(unsafe {
1601 sb::C_SkImage_reinterpretColorSpace(self.native(), new_color_space.into().into_ptr())
1602 })
1603 }
1604}