1type Error = Box<dyn std::error::Error>;
8use crate::color::RGBA;
9use crate::error::ImgError;
10use crate::error::ImgErrorKind;
11use crate::metadata::DataMap;
12use crate::util::ImageFormat;
13use crate::util::format_check;
14use crate::warning::ImgWarnings;
15use bin_rs::reader::*;
16use std::collections::HashMap;
17#[cfg(not(target_family = "wasm"))]
18use std::io::BufRead;
19#[cfg(not(target_family = "wasm"))]
20use std::io::BufReader;
21use std::io::Seek;
22use std::io::SeekFrom;
23use std::io::Write;
24#[cfg(not(target_family = "wasm"))]
25use std::path::Path;
26
27#[derive(Debug)]
31pub enum DrawNextOptions {
32 Continue,
33 NextImage,
34 ClearNext,
35 WaitTime(usize),
36 None,
37}
38
39pub type Response = Result<Option<CallbackResponse>, Error>;
40
41pub trait DrawCallback: Sync + Send {
43 fn init(
45 &mut self,
46 width: usize,
47 height: usize,
48 option: Option<InitOptions>,
49 ) -> Result<Option<CallbackResponse>, Error>;
50 fn draw(
52 &mut self,
53 start_x: usize,
54 start_y: usize,
55 width: usize,
56 height: usize,
57 data: &[u8],
58 option: Option<DrawOptions>,
59 ) -> Result<Option<CallbackResponse>, Error>;
60 fn terminate(
61 &mut self,
62 _term: Option<TerminateOptions>,
63 ) -> Result<Option<CallbackResponse>, Error>;
64 fn next(&mut self, _next: Option<NextOptions>) -> Result<Option<CallbackResponse>, Error>;
66 fn verbose(
68 &mut self,
69 _verbose: &str,
70 _: Option<VerboseOptions>,
71 ) -> Result<Option<CallbackResponse>, Error>;
72 fn set_metadata(
74 &mut self,
75 key: &str,
76 value: DataMap,
77 ) -> Result<Option<CallbackResponse>, Error>;
78}
79
80pub trait PickCallback: Sync + Send {
82 fn encode_start(
84 &mut self,
85 option: Option<EncoderOptions>,
86 ) -> Result<Option<ImageProfiles>, Error>;
87 fn encode_pick(
89 &mut self,
90 start_x: usize,
91 start_y: usize,
92 width: usize,
93 height: usize,
94 option: Option<PickOptions>,
95 ) -> Result<Option<Vec<u8>>, Error>;
96 fn encode_end(&mut self, _: Option<EndOptions>) -> Result<(), Error>;
98 fn metadata(&mut self) -> Result<Option<HashMap<String, DataMap>>, Error>;
100}
101
102#[derive(Debug)]
104pub struct EncoderOptions {}
105
106#[derive(Debug)]
108pub struct PickOptions {}
109
110#[derive(Debug)]
112pub struct EndOptions {}
113
114#[allow(unused)]
115#[derive(Debug)]
117pub struct InitOptions {
118 pub loop_count: u32,
120 pub background: Option<RGBA>,
122 pub animation: bool,
124}
125
126impl InitOptions {
127 pub fn new() -> Option<Self> {
129 Some(Self {
130 loop_count: 1,
131 background: None,
132 animation: false,
133 })
134 }
135}
136
137#[derive(Debug)]
139pub struct DrawOptions {}
140
141#[derive(Debug)]
143pub struct TerminateOptions {}
144
145#[derive(Debug)]
147pub struct VerboseOptions {}
148
149#[derive(Debug)]
151pub enum NextOption {
152 Continue,
154 Next,
156 Dispose,
158 ClearAbort,
160 Terminate,
162}
163
164#[derive(Debug)]
166pub enum NextDispose {
167 None,
169 Override,
171 Background,
173 Previous,
175}
176
177#[derive(Debug)]
183pub enum NextBlend {
184 Source,
185 Override,
186}
187
188#[allow(unused)]
189#[derive(Debug)]
191pub struct ImageRect {
192 pub start_x: i32,
193 pub start_y: i32,
194 pub width: usize,
195 pub height: usize,
196}
197
198#[allow(unused)]
199#[derive(Debug)]
201pub struct NextOptions {
202 pub flag: NextOption,
204 pub await_time: u64,
206 pub image_rect: Option<ImageRect>,
208 pub dispose_option: Option<NextDispose>,
210 pub blend: Option<NextBlend>,
212}
213
214impl NextOptions {
215 pub fn new() -> Self {
217 NextOptions {
218 flag: NextOption::Continue,
219 await_time: 0,
220 image_rect: None,
221 dispose_option: None,
222 blend: None,
223 }
224 }
225
226 pub fn wait(ms_time: u64) -> Self {
228 NextOptions {
229 flag: NextOption::Continue,
230 await_time: ms_time,
231 image_rect: None,
232 dispose_option: None,
233 blend: None,
234 }
235 }
236}
237
238#[derive(std::cmp::PartialEq, Debug)]
240pub enum ResponseCommand {
241 Abort,
242 Continue,
243}
244
245#[derive(Debug)]
247pub struct CallbackResponse {
248 pub response: ResponseCommand,
249}
250
251impl CallbackResponse {
252 pub fn abort() -> Self {
254 Self {
255 response: ResponseCommand::Abort,
256 }
257 }
258
259 pub fn cont() -> Self {
261 Self {
262 response: ResponseCommand::Continue,
263 }
264 }
265}
266
267#[derive(Debug)]
269pub struct ImageProfiles {
270 pub width: usize,
272 pub height: usize,
274 pub background: Option<RGBA>,
276 pub metadata: Option<HashMap<String, DataMap>>,
281}
282
283pub(crate) const ENCODE_ANIMATION_FRAMES_KEY: &str = "wml2.animation.frames";
284pub(crate) const ENCODE_ANIMATION_LOOP_COUNT_KEY: &str = "wml2.animation.loop_count";
285
286pub(crate) fn encode_animation_frame_key(index: usize, field: &str) -> String {
287 format!("wml2.animation.frame.{index}.{field}")
288}
289
290fn encode_animation_dispose(dispose: &Option<NextDispose>) -> u64 {
291 match dispose {
292 Some(NextDispose::Background) => 1,
293 Some(NextDispose::Previous) => 2,
294 _ => 0,
295 }
296}
297
298fn encode_animation_blend(blend: &Option<NextBlend>) -> u64 {
299 match blend {
300 Some(NextBlend::Source) => 1,
301 _ => 0,
302 }
303}
304
305fn append_animation_metadata(
306 metadata: &mut HashMap<String, DataMap>,
307 animation: &[AnimationLayer],
308 loop_count: u32,
309) {
310 metadata.insert(
311 ENCODE_ANIMATION_FRAMES_KEY.to_string(),
312 DataMap::UInt(animation.len() as u64),
313 );
314 metadata.insert(
315 ENCODE_ANIMATION_LOOP_COUNT_KEY.to_string(),
316 DataMap::UInt(loop_count as u64),
317 );
318
319 for (index, layer) in animation.iter().enumerate() {
320 metadata.insert(
321 encode_animation_frame_key(index, "width"),
322 DataMap::UInt(layer.width as u64),
323 );
324 metadata.insert(
325 encode_animation_frame_key(index, "height"),
326 DataMap::UInt(layer.height as u64),
327 );
328 metadata.insert(
329 encode_animation_frame_key(index, "start_x"),
330 DataMap::SInt(layer.start_x as i64),
331 );
332 metadata.insert(
333 encode_animation_frame_key(index, "start_y"),
334 DataMap::SInt(layer.start_y as i64),
335 );
336 metadata.insert(
337 encode_animation_frame_key(index, "delay_ms"),
338 DataMap::UInt(layer.control.await_time),
339 );
340 metadata.insert(
341 encode_animation_frame_key(index, "dispose"),
342 DataMap::UInt(encode_animation_dispose(&layer.control.dispose_option)),
343 );
344 metadata.insert(
345 encode_animation_frame_key(index, "blend"),
346 DataMap::UInt(encode_animation_blend(&layer.control.blend)),
347 );
348 metadata.insert(
349 encode_animation_frame_key(index, "buffer"),
350 DataMap::Raw(layer.buffer.clone()),
351 );
352 }
353}
354
355pub struct AnimationLayer {
357 pub width: usize,
359 pub height: usize,
361 pub start_x: i32,
363 pub start_y: i32,
365 pub buffer: Vec<u8>,
367 pub control: NextOptions,
369}
370
371#[allow(unused)]
372pub struct ImageBuffer {
374 pub width: usize,
376 pub height: usize,
378 pub background_color: Option<RGBA>,
380 pub buffer: Option<Vec<u8>>,
382 pub animation: Option<Vec<AnimationLayer>>,
384 pub current: Option<usize>,
386 pub loop_count: Option<u32>,
388 pub first_wait_time: Option<u64>,
390 fnverbose: fn(&str) -> Result<Option<CallbackResponse>, Error>,
391 pub metadata: Option<HashMap<String, DataMap>>,
393}
394
395fn default_verbose(_: &str) -> Result<Option<CallbackResponse>, Error> {
396 Ok(None)
397}
398
399fn checked_rgba_len(width: usize, height: usize, context: &str) -> Result<usize, Error> {
400 width
401 .checked_mul(height)
402 .and_then(|pixels| pixels.checked_mul(4))
403 .ok_or_else(|| {
404 Box::new(ImgError::new_const(
405 ImgErrorKind::InvalidParameter,
406 format!("{context} buffer size overflow"),
407 )) as Error
408 })
409}
410
411impl ImageBuffer {
412 pub fn new() -> Self {
414 Self {
415 width: 0,
416 height: 0,
417 background_color: None,
418 buffer: None,
419 animation: None,
420 current: None,
421 loop_count: None,
422 first_wait_time: None,
423 fnverbose: default_verbose,
424 metadata: None,
425 }
426 }
427
428 pub fn from_buffer(width: usize, height: usize, buf: Vec<u8>) -> Self {
430 Self {
431 width,
432 height,
433 background_color: None,
434 buffer: Some(buf),
435 animation: None,
436 current: None,
437 loop_count: None,
438 first_wait_time: None,
439 fnverbose: default_verbose,
440 metadata: None,
441 }
442 }
443
444 pub fn set_animation(&mut self, flag: bool) {
446 if flag {
447 self.animation = Some(Vec::new())
448 } else {
449 self.animation = None
450 }
451 }
452
453 pub fn set_verbose(&mut self, verbose: fn(&str) -> Result<Option<CallbackResponse>, Error>) {
455 self.fnverbose = verbose;
456 }
457}
458
459impl DrawCallback for ImageBuffer {
460 fn init(
462 &mut self,
463 width: usize,
464 height: usize,
465 option: Option<InitOptions>,
466 ) -> Result<Option<CallbackResponse>, Error> {
467 let buffersize = checked_rgba_len(width, height, "image")?;
468 self.width = width;
469 self.height = height;
470 if let Some(option) = option {
471 self.background_color = option.background;
472 if option.animation {
473 self.set_animation(true);
474 }
475 self.loop_count = Some(option.loop_count);
476 }
477 if let Some(background) = &self.background_color {
478 self.buffer = Some(
479 (0..buffersize)
480 .map(|i| match i % 4 {
481 0 => background.red,
482 1 => background.green,
483 2 => background.blue,
484 _ => background.alpha,
485 })
486 .collect(),
487 );
488 } else {
489 self.buffer = Some((0..buffersize).map(|_| 0).collect());
490 }
491
492 Ok(None)
493 }
494
495 fn draw(
497 &mut self,
498 start_x: usize,
499 start_y: usize,
500 width: usize,
501 height: usize,
502 data: &[u8],
503 _: Option<DrawOptions>,
504 ) -> Result<Option<CallbackResponse>, Error> {
505 if self.buffer.is_none() {
506 return Err(Box::new(ImgError::new_const(
507 ImgErrorKind::NotInitializedImageBuffer,
508 "in draw".to_string(),
509 )));
510 }
511 let buffer;
512 let (w, h, raws);
513 if self.current.is_none() {
514 if start_x >= self.width || start_y >= self.height {
515 return Ok(None);
516 }
517 let requested_end_x = start_x.checked_add(width).ok_or_else(|| {
518 Box::new(ImgError::new_const(
519 ImgErrorKind::OutboundIndex,
520 "draw rectangle x overflow".to_string(),
521 )) as Error
522 })?;
523 let requested_end_y = start_y.checked_add(height).ok_or_else(|| {
524 Box::new(ImgError::new_const(
525 ImgErrorKind::OutboundIndex,
526 "draw rectangle y overflow".to_string(),
527 )) as Error
528 })?;
529 w = self.width.min(requested_end_x) - start_x;
530 h = self.height.min(requested_end_y) - start_y;
531 raws = self.width;
532 buffer = self.buffer.as_deref_mut().ok_or_else(|| {
533 Box::new(ImgError::new_const(
534 ImgErrorKind::NotInitializedImageBuffer,
535 "buffer is not initialized".to_string(),
536 )) as Error
537 })?;
538 } else if let Some(animation) = &mut self.animation {
539 let current = self.current.ok_or_else(|| {
540 Box::new(ImgError::new_const(
541 ImgErrorKind::IllegalData,
542 "animation frame is not selected".to_string(),
543 )) as Error
544 })?;
545 if start_x >= animation[current].width || start_y >= animation[current].height {
546 return Ok(None);
547 }
548 let requested_end_x = start_x.checked_add(width).ok_or_else(|| {
549 Box::new(ImgError::new_const(
550 ImgErrorKind::OutboundIndex,
551 "draw rectangle x overflow".to_string(),
552 )) as Error
553 })?;
554 let requested_end_y = start_y.checked_add(height).ok_or_else(|| {
555 Box::new(ImgError::new_const(
556 ImgErrorKind::OutboundIndex,
557 "draw rectangle y overflow".to_string(),
558 )) as Error
559 })?;
560 w = animation[current].width.min(requested_end_x) - start_x;
561 h = animation[current].height.min(requested_end_y) - start_y;
562 raws = animation[current].width;
563 buffer = &mut animation[current].buffer;
564 } else {
565 return Err(Box::new(ImgError::new_const(
566 ImgErrorKind::NotInitializedImageBuffer,
567 "in animation".to_string(),
568 )));
569 }
570
571 for y in 0..h {
572 let scanline_src = y * width * 4;
573 let scanline_dest = (start_y + y) * raws * 4;
574 for x in 0..w {
575 let offset_src = scanline_src + x * 4;
576 let offset_dest = scanline_dest + (x + start_x) * 4;
577 if offset_src + 3 >= data.len() {
578 return Err(Box::new(ImgError::new_const(
579 ImgErrorKind::OutboundIndex,
580 "decoder buffer in draw".to_string(),
581 )));
582 }
583 if offset_dest + 3 >= buffer.len() {
584 return Err(Box::new(ImgError::new_const(
585 ImgErrorKind::OutboundIndex,
586 "image buffer in draw".to_string(),
587 )));
588 }
589 buffer[offset_dest] = data[offset_src];
590 buffer[offset_dest + 1] = data[offset_src + 1];
591 buffer[offset_dest + 2] = data[offset_src + 2];
592 buffer[offset_dest + 3] = data[offset_src + 3];
593 }
594 }
595 Ok(None)
596 }
597
598 fn terminate(
600 &mut self,
601 _: Option<TerminateOptions>,
602 ) -> Result<Option<CallbackResponse>, Error> {
603 Ok(None)
604 }
605
606 fn next(&mut self, opt: Option<NextOptions>) -> Result<Option<CallbackResponse>, Error> {
608 if self.animation.is_some() {
609 if let Some(opt) = opt {
610 if self.current.is_none() {
611 self.current = Some(0);
612 self.first_wait_time = Some(opt.await_time);
613 } else {
614 self.current = Some(
615 self.current.ok_or_else(|| {
616 Box::new(ImgError::new_const(
617 ImgErrorKind::IllegalData,
618 "animation frame is not selected".to_string(),
619 )) as Error
620 })? + 1,
621 );
622 }
623 let (width, height, start_x, start_y);
624 if let Some(ref rect) = opt.image_rect {
625 width = rect.width;
626 height = rect.height;
627 start_x = rect.start_x;
628 start_y = rect.start_y;
629 } else {
630 width = self.width;
631 height = self.height;
632 start_x = 0;
633 start_y = 0;
634 }
635 let buffersize = checked_rgba_len(width, height, "animation frame")?;
636 let buffer: Vec<u8> = (0..buffersize).map(|_| 0).collect();
637 let layer = AnimationLayer {
638 width,
639 height,
640 start_x,
641 start_y,
642 buffer,
643 control: opt,
644 };
645
646 if let Some(animation) = self.animation.as_mut() {
647 animation.push(layer);
648 } else {
649 return Err(Box::new(ImgError::new_const(
650 ImgErrorKind::NotInitializedImageBuffer,
651 "animation buffer is not initialized".to_string(),
652 )));
653 }
654
655 return Ok(Some(CallbackResponse::cont()));
656 }
657 }
658 Ok(Some(CallbackResponse::abort()))
659 }
660
661 fn verbose(
663 &mut self,
664 str: &str,
665 _: Option<VerboseOptions>,
666 ) -> Result<Option<CallbackResponse>, Error> {
667 (self.fnverbose)(str)
668 }
669
670 fn set_metadata(
672 &mut self,
673 key: &str,
674 value: DataMap,
675 ) -> Result<Option<CallbackResponse>, Error> {
676 let hashmap = if let Some(ref mut hashmap) = self.metadata {
677 hashmap
678 } else {
679 self.metadata = Some(HashMap::new());
680 self.metadata.as_mut().ok_or_else(|| {
681 Box::new(ImgError::new_const(
682 ImgErrorKind::IllegalData,
683 "metadata store is not initialized".to_string(),
684 )) as Error
685 })?
686 };
687 hashmap.insert(key.to_string(), value);
688
689 Ok(None)
690 }
691}
692
693impl PickCallback for ImageBuffer {
694 fn encode_start(&mut self, _: Option<EncoderOptions>) -> Result<Option<ImageProfiles>, Error> {
696 let mut metadata = self.metadata.clone();
697 if let Some(animation) = &self.animation {
698 if !animation.is_empty() {
699 let hashmap = if let Some(ref mut metadata) = metadata {
700 metadata
701 } else {
702 metadata = Some(HashMap::new());
703 metadata.as_mut().ok_or_else(|| {
704 Box::new(ImgError::new_const(
705 ImgErrorKind::IllegalData,
706 "metadata store is not initialized".to_string(),
707 )) as Error
708 })?
709 };
710 append_animation_metadata(hashmap, animation, self.loop_count.unwrap_or(0));
711 }
712 }
713 let init = ImageProfiles {
714 width: self.width,
715 height: self.height,
716 background: self.background_color.clone(),
717 metadata,
718 };
719 Ok(Some(init))
720 }
721
722 fn encode_pick(
724 &mut self,
725 start_x: usize,
726 start_y: usize,
727 width: usize,
728 height: usize,
729 _: Option<PickOptions>,
730 ) -> Result<Option<Vec<u8>>, Error> {
731 if self.buffer.is_none() {
732 return Err(Box::new(ImgError::new_const(
733 ImgErrorKind::NotInitializedImageBuffer,
734 "in pick".to_string(),
735 )));
736 }
737 let buffersize = checked_rgba_len(width, height, "pick")?;
738 let mut data = Vec::with_capacity(buffersize);
739 let buffer = self.buffer.as_ref().ok_or_else(|| {
740 Box::new(ImgError::new_const(
741 ImgErrorKind::NotInitializedImageBuffer,
742 "in pick".to_string(),
743 )) as Error
744 })?;
745
746 if start_x >= self.width || start_y >= self.height {
747 return Ok(None);
748 }
749 let requested_end_x = start_x.checked_add(width).ok_or_else(|| {
750 Box::new(ImgError::new_const(
751 ImgErrorKind::OutboundIndex,
752 "pick rectangle x overflow".to_string(),
753 )) as Error
754 })?;
755 let requested_end_y = start_y.checked_add(height).ok_or_else(|| {
756 Box::new(ImgError::new_const(
757 ImgErrorKind::OutboundIndex,
758 "pick rectangle y overflow".to_string(),
759 )) as Error
760 })?;
761 let w = self.width.min(requested_end_x) - start_x;
762 let h = self.height.min(requested_end_y) - start_y;
763
764 for y in 0..h {
765 let scanline_src = (start_y + y) * self.width * 4;
766 for x in 0..w {
767 let offset_src = scanline_src + (start_x + x) * 4;
768 if offset_src + 3 >= buffer.len() {
769 return Err(Box::new(ImgError::new_const(
770 ImgErrorKind::OutboundIndex,
771 "Image buffer in pick".to_string(),
772 )));
773 }
774 data.push(buffer[offset_src]);
775 data.push(buffer[offset_src + 1]);
776 data.push(buffer[offset_src + 2]);
777 data.push(buffer[offset_src + 3]);
778 }
779 for _ in w..width {
780 data.push(0x00);
782 data.push(0x00);
783 data.push(0x00);
784 data.push(0x00);
785 }
786 }
787 for _ in h..height {
788 for _ in 0..width {
790 data.push(0x00);
791 data.push(0x00);
792 data.push(0x00);
793 data.push(0x00);
794 }
795 }
796
797 Ok(Some(data))
798 }
799
800 fn encode_end(&mut self, _: Option<EndOptions>) -> Result<(), Error> {
802 Ok(())
803 }
804
805 fn metadata(&mut self) -> Result<Option<HashMap<String, DataMap>>, Error> {
807 if let Some(hashmap) = &self.metadata {
808 Ok(Some(hashmap.clone()))
809 } else {
810 Ok(None)
811 }
812 }
813}
814
815pub struct DecodeOptions<'a> {
817 pub debug_flag: usize,
819 pub drawer: &'a mut dyn DrawCallback,
821}
822
823pub struct EncodeOptions<'a> {
825 pub debug_flag: usize,
827 pub drawer: &'a mut dyn PickCallback,
829 pub options: Option<HashMap<String, DataMap>>,
835}
836
837pub fn image_from(buffer: &[u8]) -> Result<ImageBuffer, Error> {
852 image_load(buffer)
853}
854
855#[cfg(not(target_family = "wasm"))]
867pub fn image_from_file(filename: String) -> Result<ImageBuffer, Error> {
868 let f = std::fs::File::open(filename)?;
869 let reader = BufReader::new(f);
870 let mut image = ImageBuffer::new();
871 let mut option = DecodeOptions {
872 debug_flag: 0x00,
873 drawer: &mut image,
874 };
875 let _ = image_reader(reader, &mut option)?;
876 Ok(image)
877}
878
879#[cfg(not(target_family = "wasm"))]
891pub fn image_to_file(
892 filename: String,
893 image: &mut dyn PickCallback,
894 format: ImageFormat,
895) -> Result<(), Error> {
896 let f = std::fs::File::create(filename)?;
897 let mut option = EncodeOptions {
898 debug_flag: 0x00,
899 drawer: image,
900 options: None,
901 };
902 image_writer(f, &mut option, format)?;
903 Ok(())
904}
905
906#[cfg(not(target_family = "wasm"))]
907fn format_from_output_path(output_file: &str) -> Result<ImageFormat, Error> {
908 let extension = Path::new(output_file)
909 .extension()
910 .and_then(|extension| extension.to_str())
911 .map(|extension| extension.to_ascii_lowercase());
912
913 match extension.as_deref() {
914 Some("gif") => Ok(ImageFormat::Gif),
915 Some("png") | Some("apng") => Ok(ImageFormat::Png),
916 Some("jpg") | Some("jpeg") => Ok(ImageFormat::Jpeg),
917 Some("bmp") => Ok(ImageFormat::Bmp),
918 Some("tif") | Some("tiff") => Ok(ImageFormat::Tiff),
919 Some("webp") => Ok(ImageFormat::Webp),
920 Some(extension) => Err(Box::new(ImgError::new_const(
921 ImgErrorKind::NoSupportFormat,
922 format!("unsupported output extension: {extension}"),
923 ))),
924 None => Err(Box::new(ImgError::new_const(
925 ImgErrorKind::InvalidParameter,
926 "output file has no extension".to_string(),
927 ))),
928 }
929}
930
931#[cfg(not(target_family = "wasm"))]
958pub fn convert(
959 input_file: String,
960 output_file: String,
961 options: Option<HashMap<String, DataMap>>,
962) -> Result<(), Error> {
963 let format = format_from_output_path(&output_file)?;
964 let f = std::fs::File::create(&output_file)?;
965 let mut image = image_from_file(input_file)?;
966 let mut encode = EncodeOptions {
967 debug_flag: 0,
968 drawer: &mut image,
969 options,
970 };
971
972 image_writer(f, &mut encode, format)?;
973 Ok(())
974}
975
976pub fn image_load(buffer: &[u8]) -> Result<ImageBuffer, Error> {
991 let mut ib = ImageBuffer::new();
992 let mut option = DecodeOptions {
993 debug_flag: 0,
994 drawer: &mut ib,
995 };
996 let mut reader = BytesReader::new(buffer);
997
998 image_decoder(&mut reader, &mut option)?;
999 Ok(ib)
1000}
1001
1002pub fn image_loader(
1022 buffer: &[u8],
1023 option: &mut DecodeOptions,
1024) -> Result<Option<ImgWarnings>, Error> {
1025 let mut reader = BytesReader::new(buffer);
1026
1027 let r = image_decoder(&mut reader, option)?;
1028 Ok(r)
1029}
1030
1031#[cfg(not(target_family = "wasm"))]
1052pub fn image_reader<R: BufRead + Seek>(
1053 reader: R,
1054 option: &mut DecodeOptions,
1055) -> Result<Option<ImgWarnings>, Error> {
1056 let mut reader = StreamReader::new(reader);
1057
1058 let r = image_decoder(&mut reader, option)?;
1059 Ok(r)
1060}
1061
1062pub fn image_writer<W: Write>(
1080 mut writer: W,
1081 option: &mut EncodeOptions,
1082 format: ImageFormat,
1083) -> Result<Option<ImgWarnings>, Error> {
1084 let buffer = image_encoder(option, format)?;
1085 writer.write_all(&buffer)?;
1086 writer.flush()?;
1087 Ok(None)
1088}
1089
1090pub fn image_decoder<B: BinaryReader>(
1112 reader: &mut B,
1113 option: &mut DecodeOptions,
1114) -> Result<Option<ImgWarnings>, Error> {
1115 let current = reader.offset()?;
1116 let end = reader.seek(SeekFrom::End(0))?;
1117 reader.seek(SeekFrom::Start(current))?;
1118 let sample_len = usize::try_from((end - current).min(128)).map_err(|_| {
1119 Box::new(ImgError::new_const(
1120 ImgErrorKind::InvalidParameter,
1121 "input sample size overflow".to_string(),
1122 )) as Error
1123 })?;
1124 let buffer = reader.read_bytes_no_move(sample_len)?;
1125 let format = format_check(&buffer);
1126
1127 use crate::util::ImageFormat::*;
1128 match format {
1129 #[cfg(feature = "jpeg")]
1130 Jpeg => {
1131 return crate::jpeg::decoder::decode(reader, option);
1132 }
1133 #[cfg(feature = "bmp")]
1134 Bmp => {
1135 return crate::bmp::decoder::decode(reader, option);
1136 }
1137 #[cfg(feature = "ico")]
1138 Ico => {
1139 return crate::ico::decoder::decode(reader, option);
1140 }
1141 #[cfg(feature = "gif")]
1142 Gif => {
1143 return crate::gif::decoder::decode(reader, option);
1144 }
1145 #[cfg(feature = "png")]
1146 Png => {
1147 return crate::png::decoder::decode(reader, option);
1148 }
1149 #[cfg(feature = "webp")]
1150 Webp => {
1151 return crate::webp::decoder::decode(reader, option);
1152 }
1153 #[cfg(feature = "tiff")]
1154 Tiff => {
1155 return crate::tiff::decoder::decode(reader, option);
1156 }
1157 #[cfg(all(feature = "mag", not(feature = "noretoro")))]
1158 Mag => {
1159 return crate::mag::decoder::decode(reader, option);
1160 }
1161 #[cfg(all(feature = "maki", not(feature = "noretoro")))]
1162 Maki => {
1163 return crate::maki::decoder::decode(reader, option);
1164 }
1165 #[cfg(all(feature = "pi", not(feature = "noretoro")))]
1166 Pi => {
1167 return crate::pi::decoder::decode(reader, option);
1168 }
1169 #[cfg(all(feature = "pic", not(feature = "noretoro")))]
1170 Pic => {
1171 return crate::pic::decoder::decode(reader, option);
1172 }
1173 #[cfg(all(feature = "vsp", not(feature = "noretoro")))]
1174 Vsp => {
1175 return crate::vsp::decoder::decode(reader, option);
1176 }
1177 _ => {}
1178 }
1179
1180 #[cfg(all(feature = "pcd", not(feature = "noretoro")))]
1181 {
1182 let current = reader.seek(std::io::SeekFrom::Current(0))?;
1183 let pcd = (|| -> Result<bool, Error> {
1184 reader.seek(std::io::SeekFrom::Start(0x800))?;
1185 let mut id = [0u8; 7];
1186 reader.read_exact(&mut id)?;
1187 Ok(&id == b"PCD_IPI")
1188 })();
1189 reader.seek(std::io::SeekFrom::Start(current))?;
1190 if matches!(pcd, Ok(true)) {
1191 return crate::pcd::decoder::decode(reader, option);
1192 }
1193 }
1194
1195 Err(Box::new(ImgError::new_const(
1196 ImgErrorKind::NoSupportFormat,
1197 "This buffer can not decode".to_string(),
1198 )))
1199}
1200
1201pub fn image_encoder(option: &mut EncodeOptions, format: ImageFormat) -> Result<Vec<u8>, Error> {
1218 use crate::util::ImageFormat::*;
1219
1220 match format {
1221 #[cfg(feature = "gif")]
1222 Gif => {
1223 return crate::gif::encoder::encode(option);
1224 }
1225 #[cfg(feature = "bmp")]
1226 Bmp => {
1227 return crate::bmp::encoder::encode(option);
1228 }
1229 #[cfg(feature = "jpeg")]
1230 Jpeg => {
1231 return crate::jpeg::encoder::encode(option);
1232 }
1233 #[cfg(feature = "png")]
1234 Png => {
1235 return crate::png::encoder::encode(option);
1236 }
1237 #[cfg(feature = "tiff")]
1238 Tiff => {
1239 return crate::tiff::encoder::encode(option);
1240 }
1241 #[cfg(feature = "webp")]
1242 Webp => {
1243 return crate::webp::encoder::encode(option);
1244 }
1245 _ => Err(Box::new(ImgError::new_const(
1246 ImgErrorKind::NoSupportFormat,
1247 "This encoder no impl".to_string(),
1248 ))),
1249 }
1250}
1251
1252pub fn image_to(
1270 image: &mut ImageBuffer,
1271 format: ImageFormat,
1272 options: Option<HashMap<String, DataMap>>,
1273) -> Result<Vec<u8>, Error> {
1274 let mut option = EncodeOptions {
1275 debug_flag: 0,
1276 drawer: image,
1277 options,
1278 };
1279 image_encoder(&mut option, format)
1280}