Skip to main content

pdf_min/
image.rs

1//!# Test example
2//!
3//! ```
4//!      use pdf_min::{Writer, html, writer::Fetcher, image::{ImageSpec,Image}};
5//!      struct MyFetcher;
6//!      impl Fetcher for MyFetcher {
7//!         fn image(&mut self, w: &mut Writer, _name: &str) -> Image {         
8//!             let mut data = Vec::new();
9//!             for i in 0..3 * 16 * 16 {
10//!                 data.push( i as u8 );  // Red
11//!                 data.push( (i + 85 ) as u8 ); // Green
12//!                 data.push( (i + 170 ) as u8 ); // Blue
13//!             }
14//!             let ims = ImageSpec{ data: &data, width:16, height:16,
15//!                 bits_per_component:8, color_space: b"/DeviceRGB", other: b"" };
16//!             Image::new( &ims, &mut w.b )
17//!         }
18//!      }
19//!      let mut w = Writer::default();
20//!      w.b.nocomp = true;
21//!      w.font_size = 20;
22//!      w.fetcher = Some(Box::new(MyFetcher));
23//!   
24//!      // Draw text with image
25//!      html( &mut w, b"<p><b>Bold Text Before Image</b> <img width=32 src=myimg> Text after image" );
26//!      let bytes = w.finish();
27//!   
28//!      use std::fs::File;
29//!      use std::io::prelude::*;
30//!   
31//!      let mut file = File::create("image_test.pdf").unwrap();
32//!      file.write_all(bytes).unwrap();
33//! ```
34//!
35//!# JPG Test example
36//! ```
37//!    // Setup the PDF Writer
38//!    let mut doc = pdf_min::Writer::default();
39//!    doc.b.nocomp = true;
40//!
41//!    // Read jpg from file
42//!    let file_bytes = std::fs::read("one.jpg").unwrap();
43//!
44//!    // Use jpeg_decoder::Decoder to get jpg info ( color space, bits_per_component, width, height ).
45//!    let mut decoder = jpeg_decoder::Decoder::new(std::io::Cursor::new(&file_bytes));
46//!    decoder.read_info().unwrap();
47//!    let info = decoder.info().unwrap();
48//!
49//!    use jpeg_decoder::{PixelFormat};
50//!    
51//!    let color_space: &[u8] = match info.pixel_format {
52//!        PixelFormat::RGB24 => b"/DeviceRGB",
53//!        PixelFormat::CMYK32 => b"/DeviceCMYK",
54//!        PixelFormat::L8 | PixelFormat::L16 => b"/DeviceGray",
55//!    };
56//!
57//!    let bits_per_component = match info.pixel_format {
58//!        PixelFormat::L16 => 16,
59//!        _ => 8
60//!    };
61//!
62//!    // Use img_parts::jpeg::Jpeg to make DCT (Discrete Cosine Transform) compressed data.
63//!    let cdata =
64//!    {
65//!        let mut cdata = Vec::new();
66//!        let jpeg = img_parts::jpeg::Jpeg::from_bytes(file_bytes.into()).unwrap();
67//!        jpeg.encoder().write_to(&mut cdata).unwrap();
68//!        cdata
69//!    };
70//!
71//!    // Make the ImageSpec.
72//!    use pdf_min::{Px, image::{ImageSpec, Image}};
73//!    let ims = ImageSpec {
74//!        data: &cdata,
75//!        width: info.width as Px,
76//!        height: info.height as Px,
77//!        color_space,
78//!        bits_per_component,
79//!        other: b"/Filter/DCT",
80//!    };
81//!    
82//!    // Make the Image from the ImageSpec.
83//!    let im = Image::new(&ims, &mut doc.b);
84//!
85//!    // Draw the image on the current page.
86//!    im.draw(&mut doc.p, 20.0, 40.0, 0.20);
87//!
88//!    // Save the pdf as a file.
89//!    let bytes = doc.finish();
90//!    let mut file = std::fs::File::create("jpg_image_test.pdf").unwrap();
91//!    use std::io::Write;
92//!    file.write_all(bytes).unwrap();
93//! ```
94
95use crate::BasicPdfWriter;
96use crate::page::Page;
97use crate::*;
98use format_bytes::write_bytes as wb;
99
100/// PDF image specification - byte data and attributes that describe how image is encoded.
101pub struct ImageSpec<'a> {
102    /// Image data - length is width * height * (bits_per_component/8) * 3 (for RGB).
103    pub data: &'a [u8],
104    /// Width
105    pub width: Px,
106    /// Height
107    pub height: Px,
108    /// Bits per component, usually 8
109    pub bits_per_component: u8,
110    /// Color space, such as b"/DeviceGray", b"/DeviceRGB", b"/DeviceCMYK"
111    pub color_space: &'a [u8],
112    /// Any other attributes, e.g. b"/Filter/DCT" for a jpeg
113    pub other: &'a [u8],
114}
115
116/// PDF image - obj id, width and height
117pub struct Image {
118    /// PDF obj id
119    pub obj: usize,
120    /// Width
121    pub width: Px,
122    /// Height
123    pub height: Px,
124}
125
126impl Image {
127    /// Writes the specified image attributes and data to the PDF, returns Image with obj id, width and height.
128    pub fn new(s: &ImageSpec, w: &mut BasicPdfWriter) -> Image {
129        let obj = w.begin();
130        let _ = wb!(
131            &mut w.b,
132            b"<</Type/XObject/Subtype/Image/Width {}/Height {}/ColorSpace{}/BitsPerComponent {}/Length {}{}>>stream\n",
133            s.width, s.height, s.color_space, s.bits_per_component, s.data.len(), s.other
134        );
135        w.b.extend_from_slice(s.data);
136        w.b.extend_from_slice(b"\nendstream");
137        w.end();
138        Image {
139            obj,
140            width: s.width,
141            height: s.height,
142        }
143    }
144
145    /// Draw image on page.
146    pub fn draw(&self, page: &mut Page, x: f32, y: f32, scale: f32) {
147        let w = (self.width as f32) * scale;
148        let h = (self.height as f32) * scale;
149        page.xobjs.insert(self.obj);
150        let _ = wb!(
151            &mut page.os,
152            b"\nq {} 0 0 {} {} {} cm /X{} Do Q",
153            w,
154            h,
155            x,
156            y,
157            self.obj
158        );
159    }
160}