1#![no_std]
14#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
15
16extern crate alloc;
17#[cfg(feature = "std")]
18extern crate std;
19
20mod bits;
21use alloc::{vec, vec::Vec};
22use bits::Bitfield;
23
24mod byte_tables;
25use byte_tables::{low_bits, reverse_bytes};
26
27mod ext;
28pub use ext::DisplayExt;
29
30#[cfg(feature = "async")]
31pub use ext::AsyncDisplayExt;
32
33mod subimage;
34
35use breadx::protocol::xproto::{
36 Drawable, Gcontext, GetImageReply, ImageFormat, ImageOrder, PutImageRequest, Setup,
37};
38use core::{
39 convert::{TryFrom, TryInto},
40 fmt,
41 num::TryFromIntError,
42};
43
44#[cfg(feature = "std")]
45use std::error::Error;
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
119#[repr(u8)]
120pub enum BitsPerPixel {
121 One = 1,
123 Four = 4,
125 Eight = 8,
127 Sixteen = 16,
129 ThirtyTwo = 32,
131}
132
133impl BitsPerPixel {
134 pub fn roundup_from_depth(depth: u8) -> BitsPerPixel {
135 match depth {
136 i if i <= 1 => BitsPerPixel::One,
137 i if i <= 4 => BitsPerPixel::Four,
138 i if i <= 8 => BitsPerPixel::Eight,
139 i if i <= 16 => BitsPerPixel::Sixteen,
140 _ => BitsPerPixel::ThirtyTwo,
141 }
142 }
143}
144
145impl TryFrom<u8> for BitsPerPixel {
146 type Error = InvalidNumber;
147
148 fn try_from(value: u8) -> Result<Self, Self::Error> {
149 match value {
150 1 => Ok(BitsPerPixel::One),
151 4 => Ok(BitsPerPixel::Four),
152 8 => Ok(BitsPerPixel::Eight),
153 16 => Ok(BitsPerPixel::Sixteen),
154 32 => Ok(BitsPerPixel::ThirtyTwo),
155 value => Err(InvalidNumber::out_of_range(value, &[1, 4, 8, 16, 32])),
156 }
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
162#[repr(u8)]
163pub enum Quantum {
164 Eight = 8,
166 Sixteen = 16,
168 ThirtyTwo = 32,
170}
171
172impl TryFrom<u8> for Quantum {
173 type Error = InvalidNumber;
174
175 fn try_from(value: u8) -> Result<Self, Self::Error> {
176 match value {
177 8 => Ok(Quantum::Eight),
178 16 => Ok(Quantum::Sixteen),
179 32 => Ok(Quantum::ThirtyTwo),
180 value => Err(InvalidNumber::out_of_range(value, &[8, 16, 32])),
181 }
182 }
183}
184
185#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
187pub enum Format {
188 Xy {
194 format: XyFormatType,
199 quantum: Quantum,
206 bit_order: ImageOrder,
211 left_pad: u8,
213 },
214 Z {
219 depth: u8,
221 bits_per_pixel: BitsPerPixel,
226 },
227}
228
229#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
231pub enum XyFormatType {
232 Bitmap,
234 Pixmap {
236 depth: u8,
238 },
239}
240
241impl Format {
242 pub fn depth(&self) -> u8 {
243 match self {
244 Format::Xy {
245 format: XyFormatType::Pixmap { depth },
246 ..
247 } => *depth,
248 Format::Xy { .. } => 1,
249 Format::Z { depth, .. } => *depth,
250 }
251 }
252
253 pub fn format(&self) -> ImageFormat {
254 match self {
255 Format::Xy {
256 format: XyFormatType::Bitmap,
257 ..
258 } => ImageFormat::XY_BITMAP,
259 Format::Xy {
260 format: XyFormatType::Pixmap { .. },
261 ..
262 } => ImageFormat::XY_PIXMAP,
263 Format::Z { .. } => ImageFormat::Z_PIXMAP,
264 }
265 }
266}
267
268pub fn storage_bytes(
270 width: u16,
271 height: u16,
272 depth: u8,
273 bits_per_pixel: Option<BitsPerPixel>,
274 format: ImageFormat,
275 scanline_pad: u8,
276) -> usize {
277 let bytes_per_line = match format {
278 ImageFormat::Z_PIXMAP => {
279 let bpp =
280 bits_per_pixel.unwrap_or_else(|| BitsPerPixel::roundup_from_depth(depth)) as usize;
281 pad_to(pad_to(bpp * width as usize, 8) / 8, scanline_pad.into())
282 }
283 ImageFormat::XY_PIXMAP | ImageFormat::XY_BITMAP => {
284 pad_to(width.into(), scanline_pad.into())
285 }
286 _ => panic!("Unsupported image format: {:?}", format),
287 };
288
289 let plane_len = bytes_per_line * height as usize;
290
291 if matches!(format, ImageFormat::Z_PIXMAP) {
292 plane_len
293 } else {
294 plane_len * depth as usize
295 }
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
299pub struct Image<Storage: ?Sized> {
300 width: u16,
302 height: u16,
304 image_format: Format,
306 byte_order: ImageOrder,
311 scanline_pad: u8,
313 storage: Storage,
315}
316
317impl<Storage: ?Sized> AsRef<Storage> for Image<Storage> {
318 fn as_ref(&self) -> &Storage {
319 &self.storage
320 }
321}
322
323impl<Storage: ?Sized> AsMut<Storage> for Image<Storage> {
324 fn as_mut(&mut self) -> &mut Storage {
325 &mut self.storage
326 }
327}
328
329impl<Storage: AsRef<[u8]>> Image<Storage> {
330 pub fn new(
332 storage: Storage,
333 width: u16,
334 height: u16,
335 format: Format,
336 byte_order: ImageOrder,
337 scanline_pad: u8,
338 ) -> Self {
339 Self {
340 width,
341 height,
342 scanline_pad,
343 image_format: format,
344 byte_order,
345 storage,
346 }
347 }
348
349 pub fn with_display(
351 storage: Storage,
352 width: u16,
353 height: u16,
354 image_format: ImageFormat,
355 depth: u8,
356 setup: &Setup,
357 ) -> breadx::Result<Self> {
358 let byte_order = setup.image_byte_order;
359 let (format, scanline_pad) = match image_format {
360 ImageFormat::XY_BITMAP | ImageFormat::XY_PIXMAP => (
361 Format::Xy {
362 format: match image_format {
363 ImageFormat::XY_BITMAP => XyFormatType::Bitmap,
364 ImageFormat::XY_PIXMAP => XyFormatType::Pixmap { depth },
365 _ => unreachable!(),
366 },
367 quantum: setup
368 .bitmap_format_scanline_unit
369 .try_into()
370 .expect("invalid quantum"),
371 bit_order: byte_order,
372 left_pad: 0,
373 },
374 setup.bitmap_format_scanline_pad,
375 ),
376 ImageFormat::Z_PIXMAP => {
377 let (bpp, scanline_pad) = setup
378 .pixmap_formats
379 .iter()
380 .find(|format| format.depth == depth)
381 .map(|format| {
382 (
383 format.bits_per_pixel.try_into().expect("invalid bpp"),
384 format.scanline_pad,
385 )
386 })
387 .unwrap_or_else(|| {
388 let bpp = BitsPerPixel::roundup_from_depth(depth);
389 (bpp, setup.bitmap_format_scanline_pad)
390 });
391
392 (
393 Format::Z {
394 depth,
395 bits_per_pixel: bpp,
396 },
397 scanline_pad,
398 )
399 }
400 _ => panic!("Unsupported image format"),
401 };
402
403 Ok(Self::new(
404 storage,
405 width,
406 height,
407 format,
408 byte_order,
409 scanline_pad,
410 ))
411 }
412
413 pub fn into_storage(self) -> Storage {
415 self.storage
416 }
417
418 pub fn map_storage<R, F>(self, f: F) -> Image<R>
422 where
423 F: FnOnce(Storage) -> R,
424 {
425 let Self {
426 width,
427 height,
428 image_format,
429 byte_order,
430 scanline_pad,
431 storage,
432 } = self;
433
434 Image {
435 width,
436 height,
437 image_format,
438 byte_order,
439 scanline_pad,
440 storage: f(storage),
441 }
442 }
443}
444
445impl<Storage: ?Sized> Image<Storage> {
446 fn bits_per_scanline(&self) -> usize {
448 let unpadded_scanline = match self.image_format {
449 Format::Xy { ref left_pad, .. } => self.width as usize + *left_pad as usize,
450 Format::Z {
451 ref bits_per_pixel, ..
452 } => self.width as usize * *bits_per_pixel as usize,
453 };
454
455 let scanline_pad = self.scanline_pad as usize;
457 pad_to(unpadded_scanline, scanline_pad)
458 }
459
460 fn bytes_per_scanline(&self) -> usize {
461 self.bits_per_scanline() / 8
462 }
463
464 fn plane_size(&self) -> usize {
466 self.bits_per_scanline() * self.height as usize
467 }
468
469 pub fn depth(&self) -> u8 {
471 match self.image_format {
472 Format::Xy {
473 format: XyFormatType::Pixmap { depth },
474 ..
475 } => depth,
476 Format::Z { depth, .. } => depth,
477 Format::Xy {
478 format: XyFormatType::Bitmap,
479 ..
480 } => 1,
481 }
482 }
483
484 fn quantum(&self) -> usize {
485 match self.image_format {
486 Format::Xy { quantum, .. } => quantum as usize,
487 _ => 8,
488 }
489 }
490
491 fn left_pad(&self) -> usize {
492 match self.image_format {
493 Format::Xy { left_pad, .. } => left_pad as usize,
494 _ => 0,
495 }
496 }
497
498 fn quantum_xy_index(&self, x: usize, y: usize) -> usize {
500 let quantum = self.quantum();
501 let left_pad = self.left_pad();
502
503 (y * self.bytes_per_scanline()) + ((x + left_pad) / quantum) * (quantum / 8)
504 }
505
506 fn bits_per_pixel(&self) -> usize {
507 match self.image_format {
508 Format::Z { bits_per_pixel, .. } => bits_per_pixel as usize,
509 _ => unreachable!(),
510 }
511 }
512
513 fn z_index(&self, x: usize, y: usize) -> usize {
514 let bits_per_pixel = self.bits_per_pixel();
515
516 (y * self.bytes_per_scanline()) + ((x * bits_per_pixel) / 8)
517 }
518
519 fn normalize_bits_xy(&self, bits: &mut [u8]) {
521 let (bitmap_format, quantum) = match self.image_format {
522 Format::Xy {
523 ref bit_order,
524 ref quantum,
525 ..
526 } => (*bit_order, *quantum),
527 Format::Z { .. } => (
528 self.byte_order,
529 Quantum::try_from(self.scanline_pad).unwrap(),
530 ),
531 };
532
533 if matches!(
534 (self.byte_order, bitmap_format),
535 (ImageOrder::LSB_FIRST, ImageOrder::LSB_FIRST)
536 ) {
537 return;
539 }
540
541 if self.byte_order != bitmap_format {
542 match quantum {
543 Quantum::Sixteen => {
544 debug_assert_eq!(bits.len(), 2);
546 bits.swap(0, 1);
547 }
548 Quantum::ThirtyTwo => {
549 bits.swap(0, 3);
551 bits.swap(1, 2);
552 }
553 _ => {}
554 }
555 }
556
557 if matches!(bitmap_format, ImageOrder::MSB_FIRST) {
558 let quantum = quantum as usize;
559 reverse_bytes(&mut bits[0..quantum / 8])
560 }
561 }
562
563 fn normalize_bits_z(&self, bits: &mut [u8]) {
564 if matches!(self.byte_order, ImageOrder::LSB_FIRST) {
565 return;
566 }
567
568 match self.bits_per_pixel() {
569 4 => {
570 bits[0] = ((bits[0] >> 4) & 0x0F) | ((bits[0] << 4) & 0xF0);
572 }
573 8 => {}
574 16 => {
575 bits.swap(0, 1);
577 }
578 32 => {
579 bits.swap(0, 3);
581 bits.swap(1, 2);
582 }
583 bpp => tracing::error!("invalid bits per pixel: {}", bpp),
584 }
585 }
586
587 pub fn storage(&self) -> &Storage {
588 &self.storage
589 }
590
591 pub fn storage_mut(&mut self) -> &mut Storage {
592 &mut self.storage
593 }
594
595 pub fn width(&self) -> usize {
596 self.width.into()
597 }
598
599 pub fn height(&self) -> usize {
600 self.height.into()
601 }
602
603 pub fn format(&self) -> &Format {
604 &self.image_format
605 }
606}
607
608impl<Storage: AsRef<[u8]> + ?Sized> Image<Storage> {
609 pub fn borrow(&self) -> Image<&[u8]> {
610 Image {
611 width: self.width,
612 height: self.height,
613 image_format: self.image_format,
614 byte_order: self.byte_order,
615 scanline_pad: self.scanline_pad,
616 storage: self.storage.as_ref(),
617 }
618 }
619
620 fn planes(&self) -> impl Iterator<Item = &[u8]> + '_ {
622 self.storage
623 .as_ref()
624 .chunks(self.plane_size())
625 .take(self.depth().into())
626 }
627
628 fn pixel_xy(&self, x: usize, y: usize) -> u32 {
631 let bit_index = (x + self.left_pad()) % self.quantum();
632 let quantum_bytes = self.quantum() / 8;
633 let addr = self.quantum_xy_index(x, y);
634 let mut result = 0;
635
636 for plane in self.planes() {
638 let mut pixel = [0u8; 4];
640 let data_slice = &plane[addr..addr + quantum_bytes];
641 pixel[..quantum_bytes].copy_from_slice(data_slice);
642
643 self.normalize_bits_xy(&mut pixel[..quantum_bytes]);
645
646 let bit = u32::from(pixel[bit_index / 8]) >> (bit_index % 8);
648 result = result << 1 | (bit & 1);
649 }
650
651 result
652 }
653
654 fn pixel_z(&self, x: usize, y: usize) -> u32 {
657 let mut pixel = [0u8; 4];
658 let addr = self.z_index(x, y);
659 let quantum_bytes = (self.bits_per_pixel() + 7) / 8;
660
661 let data = &self.storage.as_ref()[addr..addr + quantum_bytes];
663 pixel[..quantum_bytes].copy_from_slice(data);
664 self.normalize_bits_z(&mut pixel[..quantum_bytes]);
665
666 let mut res = u32::from_le_bytes(pixel);
668
669 if self.bits_per_pixel() == 4 {
671 if x & 1 == 0 {
672 res &= 0x0F;
673 } else {
674 res >>= 4;
675 }
676 }
677
678 if self.bits_per_pixel() != self.depth() as usize {
679 res = low_bits(res, self.depth() as usize);
681 }
682
683 res
684 }
685
686 pub fn pixel(&self, x: usize, y: usize) -> u32 {
688 match self.image_format {
690 Format::Xy { .. } | Format::Z { depth: 1, .. } => self.pixel_xy(x, y),
691 Format::Z { .. } => self.pixel_z(x, y),
692 }
693 }
694
695 pub fn put_image_request(
697 &self,
698 drawable: impl Into<Drawable>,
699 gc: impl Into<Gcontext>,
700 dst_x: i16,
701 dst_y: i16,
702 ) -> PutImageRequest<'_> {
703 let drawable = drawable.into();
704 let gc = gc.into();
705 let mut total_len = self.bytes_per_scanline() * self.height();
706 if matches!(self.format(), Format::Xy { .. }) {
707 total_len *= self.depth() as usize;
708 }
709
710 PutImageRequest {
711 format: self.image_format.format(),
712 drawable,
713 gc,
714 width: self.width,
715 height: self.height,
716 dst_x,
717 dst_y,
718 left_pad: match self.image_format {
719 Format::Xy { ref left_pad, .. } => *left_pad,
720 _ => 0,
721 },
722 depth: self.depth(),
723 data: self.storage.as_ref()[..total_len].into(),
724 }
725 }
726
727 pub fn crop(&self, x: usize, y: usize, width: usize, height: usize) -> Image<Vec<u8>> {
735 let bpp = match self.image_format {
737 Format::Xy { .. } => None,
738 Format::Z {
739 ref bits_per_pixel, ..
740 } => Some(*bits_per_pixel),
741 };
742 let len = storage_bytes(
743 width as _,
744 height as _,
745 self.depth(),
746 bpp,
747 self.format().format(),
748 self.scanline_pad,
749 );
750 let storage = vec![0u8; len];
751 let mut image = Image::new(
752 storage,
753 width as _,
754 height as _,
755 self.image_format,
756 self.byte_order,
757 self.scanline_pad,
758 );
759
760 for dest_y in 0..height {
764 for dest_x in 0..width {
765 let src_x = x + dest_x;
766 let src_y = y + dest_y;
767
768 let src_pixel = self.pixel(src_x, src_y);
769 image.set_pixel(dest_x, dest_y, src_pixel);
770 }
771 }
772
773 image
775 }
776}
777
778impl<Storage: AsMut<[u8]> + ?Sized> Image<Storage> {
779 pub fn borrow_mut(&mut self) -> Image<&mut [u8]> {
780 Image {
781 storage: self.storage.as_mut(),
782 width: self.width,
783 height: self.height,
784 image_format: self.image_format,
785 byte_order: self.byte_order,
786 scanline_pad: self.scanline_pad,
787 }
788 }
789
790 fn set_pixel_xy(&mut self, x: usize, y: usize, pixel: u32) {
793 let bit_index = (x + self.left_pad()) % self.quantum();
794 let quantum_bytes = self.quantum() / 8;
795 let addr = self.quantum_xy_index(x, y);
796 let plane_size = self.plane_size();
797
798 for (i, planestart) in (0..self.depth() as usize)
799 .map(|i| i * plane_size)
800 .rev()
801 .enumerate()
802 {
803 let mut buffer = [0u8; 4];
805 let base = addr + planestart;
806 let data_slice = &mut self.storage.as_mut()[base..base + quantum_bytes];
807 buffer[..quantum_bytes].copy_from_slice(data_slice);
808
809 self.normalize_bits_xy(&mut buffer);
811
812 let mut buffer_bits = Bitfield(&mut buffer);
815 let pixel_bits = Bitfield(pixel.to_ne_bytes());
816 buffer_bits.set_bit(bit_index, pixel_bits.bit(i));
817
818 self.normalize_bits_xy(&mut buffer);
820 let data_slice = &mut self.storage.as_mut()[base..base + quantum_bytes];
821 data_slice.copy_from_slice(&buffer[..quantum_bytes]);
822 }
823 }
824
825 fn set_pixel_z(&mut self, x: usize, y: usize, pixel: u32) {
828 let addr = self.z_index(x, y);
829 let bpp = self.bits_per_pixel();
830 let quantum_bytes = (bpp + 7) / 8;
831
832 let mut buffer = [0u8; 4];
834 let data_slice = &mut self.storage.as_mut()[addr..addr + quantum_bytes];
835 buffer[..quantum_bytes].copy_from_slice(data_slice);
836
837 self.normalize_bits_z(&mut buffer[..quantum_bytes]);
839
840 let src = Bitfield(pixel.to_le_bytes());
842 let mut dest = Bitfield(&mut buffer);
843 let dest_addr = (x * bpp) % 8;
844 dest.copy_from(&src, dest_addr, 0, bpp);
845
846 self.normalize_bits_z(&mut buffer[..quantum_bytes]);
848 let data_slice = &mut self.storage.as_mut()[addr..addr + quantum_bytes];
849 data_slice.copy_from_slice(&buffer[..quantum_bytes]);
850 }
851
852 pub fn set_pixel(&mut self, x: usize, y: usize, pixel: u32) {
854 match self.image_format {
855 Format::Xy { .. } | Format::Z { depth: 1, .. } => self.set_pixel_xy(x, y, pixel),
856 Format::Z { .. } => self.set_pixel_z(x, y, pixel),
857 }
858 }
859}
860
861impl Image<Vec<u8>> {
862 pub fn from_get_image_reply(
866 reply: GetImageReply,
867 width: u16,
868 height: u16,
869 format: ImageFormat,
870 setup: &Setup,
871 ) -> breadx::Result<Self> {
872 let GetImageReply { depth, data, .. } = reply;
873
874 Self::with_display(data, width, height, format, depth, setup)
875 }
876}
877
878fn pad_to(val: usize, pad: usize) -> usize {
879 val + (pad - (val % pad)) % pad
880}
881
882#[derive(Debug, Clone, Copy)]
884pub struct InvalidNumber(Innards);
885
886#[derive(Debug, Clone, Copy)]
887enum Innards {
888 InvalidConversion(TryFromIntError),
889 NotInRange { value: u8, valid: &'static [u8] },
890}
891
892impl InvalidNumber {
893 fn out_of_range(value: u8, valid: &'static [u8]) -> InvalidNumber {
894 InvalidNumber(Innards::NotInRange { value, valid })
895 }
896}
897
898impl fmt::Display for InvalidNumber {
899 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
900 match self.0 {
901 Innards::InvalidConversion(_) => write!(f, "invalid int conversion"),
902 Innards::NotInRange { value, valid } => {
903 write!(f, "value {} not in range {:?}", value, valid)
904 }
905 }
906 }
907}
908
909#[cfg(feature = "std")]
910impl Error for InvalidNumber {}
911
912impl From<TryFromIntError> for InvalidNumber {
913 fn from(err: TryFromIntError) -> Self {
914 InvalidNumber(Innards::InvalidConversion(err))
915 }
916}
917
918#[allow(clippy::needless_range_loop)]
919#[cfg(all(test, feature = "std"))]
920mod tests {
921 use alloc::vec;
922 use breadx::protocol::xproto::{ImageFormat, ImageOrder};
923 use std::panic;
924
925 use super::{Format, Image, XyFormatType};
926
927 const TEST_WIDTH: usize = 35;
928 const TEST_HEIGHT: usize = 35;
929
930 fn test_permutation(format: Format, depth: u8, scanline_pad: u8, byte_order: ImageOrder) {
931 let mut image = [[0u32; TEST_WIDTH]; TEST_HEIGHT];
933 for y in 0..TEST_HEIGHT {
934 for x in 0..TEST_WIDTH {
935 let limit = if depth == 32 {
936 u32::MAX
937 } else {
938 2_u32.pow(depth as u32)
939 };
940 image[y][x] = fastrand::u32(..limit);
941 }
942 }
943
944 let len = crate::storage_bytes(
946 TEST_WIDTH as _,
947 TEST_HEIGHT as _,
948 depth,
949 None,
950 format.format(),
951 scanline_pad,
952 );
953 let storage = vec![0u8; len];
954 let mut ximage = Image::new(
955 storage,
956 TEST_WIDTH as _,
957 TEST_HEIGHT as _,
958 format,
959 byte_order,
960 scanline_pad,
961 );
962
963 for y in 0..TEST_HEIGHT {
965 for x in 0..TEST_WIDTH {
966 ximage.set_pixel(x, y, image[y][x]);
967 }
968 }
969
970 for y in 0..TEST_HEIGHT {
972 for x in 0..TEST_WIDTH {
973 assert_eq!(
974 image[y][x],
975 ximage.pixel(x, y),
976 "Pixel at ({}, {}) not equal for format {:?}, byte order {:?} and depth {}",
977 x,
978 y,
979 format,
980 byte_order,
981 depth
982 );
983 }
984 }
985 }
986
987 #[test]
988 fn test_get_and_set_pixel() {
989 for format in &[
990 ImageFormat::Z_PIXMAP,
991 ImageFormat::XY_PIXMAP,
992 ImageFormat::XY_BITMAP,
993 ] {
994 for depth in 1u8..=32 {
995 if *format == ImageFormat::XY_BITMAP && depth != 1 {
997 continue;
998 }
999
1000 if *format == ImageFormat::Z_PIXMAP && depth == 1 {
1002 continue;
1003 }
1004
1005 let scanline_pad = 32;
1006
1007 for byte_order in &[ImageOrder::LSB_FIRST, ImageOrder::MSB_FIRST] {
1008 for bit_order in &[ImageOrder::LSB_FIRST, ImageOrder::MSB_FIRST] {
1009 if *format == ImageFormat::Z_PIXMAP && *bit_order != ImageOrder::LSB_FIRST {
1011 continue;
1012 }
1013
1014 let format = match *format {
1016 ImageFormat::XY_BITMAP => Format::Xy {
1017 format: XyFormatType::Bitmap,
1018 quantum: crate::Quantum::ThirtyTwo,
1019 bit_order: *bit_order,
1020 left_pad: 0,
1021 },
1022 ImageFormat::XY_PIXMAP => Format::Xy {
1023 format: XyFormatType::Pixmap { depth },
1024 quantum: crate::Quantum::ThirtyTwo,
1025 bit_order: *bit_order,
1026 left_pad: 0,
1027 },
1028 ImageFormat::Z_PIXMAP => Format::Z {
1029 depth: depth as _,
1030 bits_per_pixel: crate::BitsPerPixel::roundup_from_depth(depth as _),
1031 },
1032 _ => unreachable!(),
1033 };
1034
1035 if let Err(e) = panic::catch_unwind(|| {
1036 test_permutation(format, depth, scanline_pad, *byte_order);
1037 }) {
1038 std::eprintln!(
1039 "panic occurred with format {:?} and byte order {:?}",
1040 format,
1041 byte_order
1042 );
1043 panic::resume_unwind(e);
1044 }
1045 }
1046 }
1047 }
1048 }
1049 }
1050}
1051
1052pub mod prelude {
1053 #[cfg(feature = "async")]
1054 pub use crate::AsyncDisplayExt;
1055 pub use crate::DisplayExt;
1056}