justpdf_core/stream/
dct.rs1use crate::error::{JustPdfError, Result};
2
3pub fn decode(data: &[u8]) -> Result<DecodedImage> {
6 let mut decoder = jpeg_decoder::Decoder::new(data);
7 let pixels = decoder.decode().map_err(|e| JustPdfError::StreamDecode {
8 filter: "DCTDecode".into(),
9 detail: format!("JPEG decode error: {e}"),
10 })?;
11
12 let info = decoder.info().ok_or_else(|| JustPdfError::StreamDecode {
13 filter: "DCTDecode".into(),
14 detail: "no JPEG image info".into(),
15 })?;
16
17 let color_type = match info.pixel_format {
18 jpeg_decoder::PixelFormat::L8 => ColorType::Gray,
19 jpeg_decoder::PixelFormat::RGB24 => ColorType::Rgb,
20 jpeg_decoder::PixelFormat::CMYK32 => ColorType::Cmyk,
21 jpeg_decoder::PixelFormat::L16 => ColorType::Gray,
22 };
23
24 Ok(DecodedImage {
25 width: info.width as u32,
26 height: info.height as u32,
27 color_type,
28 data: pixels,
29 })
30}
31
32pub fn jpeg_dimensions(data: &[u8]) -> Result<(u32, u32)> {
34 let mut decoder = jpeg_decoder::Decoder::new(data);
35 decoder
36 .read_info()
37 .map_err(|e| JustPdfError::StreamDecode {
38 filter: "DCTDecode".into(),
39 detail: format!("JPEG header error: {e}"),
40 })?;
41 let info = decoder.info().ok_or_else(|| JustPdfError::StreamDecode {
42 filter: "DCTDecode".into(),
43 detail: "no JPEG image info".into(),
44 })?;
45 Ok((info.width as u32, info.height as u32))
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum ColorType {
51 Gray,
52 Rgb,
53 Cmyk,
54}
55
56impl ColorType {
57 pub fn components(&self) -> usize {
58 match self {
59 Self::Gray => 1,
60 Self::Rgb => 3,
61 Self::Cmyk => 4,
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
68pub struct DecodedImage {
69 pub width: u32,
70 pub height: u32,
71 pub color_type: ColorType,
72 pub data: Vec<u8>,
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_corrupted_jpeg() {
81 let result = decode(b"\x00\x01\x02\x03");
82 assert!(result.is_err());
83 }
84
85 }