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}