use super::*; use std::{ str, }; const HEADER_BASE64_JPEG: &'static [u8] = b"/9j/"; const HEADER_BASE64_PNG: &'static [u8] = b"iVBO"; const HEADER_BASE64_GIF: &'static [u8] = b"R0lG"; const EXT_JPEG: &'static str = "jpg"; const EXT_PNG: &'static str = "png"; const EXT_GIF: &'static str = "gif"; /// An image type header #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub enum ImageType { Png, Jpeg, Gif, } impl Default for ImageType { fn default() -> Self { Self::Jpeg } } impl ImageType { /// From base64 byte slice /// /// # Notes /// /// To parse from `str`, use the `FromStr` trait instead. pub fn from_base64(from: T) -> Result where T: AsRef<[u8]> { let from = from.as_ref(); if from.len() > 4 { Ok(match &from[..4] { HEADER_BASE64_GIF => Self::Gif, HEADER_BASE64_PNG => Self::Png, HEADER_BASE64_JPEG => Self::Jpeg, _ => return Err(error::Error::UnknownFormat), }) } else { Err(error::Error::InvalidFormat) } } /// Get the extension for this image type pub fn ext(&self) -> &str { match self { Self::Jpeg => EXT_JPEG, Self::Png => EXT_PNG, Self::Gif => EXT_GIF, } } } impl str::FromStr for ImageType { type Err = error::Error; /// Determine image type from base64 fn from_str(from: &str) -> Result { let from = from.as_bytes(); Self::from_base64(from) } } /// Calculate the required data size from base64 input size pub const fn data_size(base64: usize) -> usize { ((4 * base64 / 3) + 3) & !3 } #[inline] fn find(haystack: &[u8], needle: &[u8]) -> Option { haystack.windows(needle.len()).position(|window| window == needle) } #[inline] fn find_back(haystack: &[u8], needle: &[u8]) -> Option { haystack.windows(needle.len()).rev().position(|window| window == needle).and_then(|v| Some(haystack.len() - v)) } const MARKER_BASE64_BEGIN: &[u8] = b"base64,"; const MARKER_BASE64_END: &[u8] = b"' />"; const MARKER_TAGS_END: &[u8] = br"

) -> Result, error::DecodeError> { let from = from.as_ref(); if let Some(start) = find(from, MARKER_BASE64_BEGIN) { let start = start + MARKER_BASE64_BEGIN.len(); if let Some(end) = find_back(&from[start..], MARKER_BASE64_END) {//find_back(from, MARKER_BASE64_END) { let end = end - MARKER_BASE64_END.len(); Ok(Range { start, end: end + start, }) } else { Err(error::DecodeError::Bounds(error::Bound::End)) } } else { Err(error::DecodeError::Bounds(error::Bound::Start)) } } /// Find the tag bounds in this array // We should pass this a slice from `base64bounds.end..` pub(super) fn find_tag_bounds(from: impl AsRef<[u8]>) -> Result, error::DecodeError> { let from = from.as_ref(); if let Some(start) = find(from, MARKER_TAGS_BEGIN) { let start = start + MARKER_TAGS_BEGIN.len(); if let Some(end) = find_back(&from[start..], MARKER_TAGS_END) {//find_back(from, MARKER_TAGS_END) { let end = end - MARKER_TAGS_END.len(); Ok(Range { start, end: end + start, }) } else { Err(error::DecodeError::Bounds(error::Bound::End)) } } else { Err(error::DecodeError::Bounds(error::Bound::Start)) } }