Skip to main content

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}