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}