skia_safe/core/
image.rs

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