Skip to content

Commit b856368

Browse files
committed
feat(render): output the image as BMP format
1 parent dc87509 commit b856368

File tree

6 files changed

+112
-32
lines changed

6 files changed

+112
-32
lines changed

Cargo.lock

Lines changed: 80 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ authors = ["Luca Corrieri"]
55
edition = "2018"
66

77
[dependencies]
8+
image = { version = "0.23.14", default-features = false, features = ["bmp"] }
89
rand = "0.8.4"

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ Simple path tracer made in Rust based on Peter Shirley's book
55

66
To-do:
77
- [x] _Ray Tracing in One Weekend_ (actually in more than one weekend...)
8-
- [ ] Refactor the code
8+
- [x] Refactor the code
99
- [ ] Command line arguments
1010
- [ ] Progress bar
1111
- [ ] Parallelism (multithreading)
12+
- [x] Save to a better image format (BMP)
1213

1314
## Usage
1415

1516
```shell
16-
$ cargo run --release > image.ppm
17+
$ cargo run --release
1718
```
19+
20+
The resulting image is in `./image.bmp`.

src/color.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
use crate::vec3::Vec3;
2-
use std::io::Write;
2+
use image::{Rgb, RgbImage};
33

44
/// Alias of Vec3 representing a color
55
pub type Color = Vec3;
66

77
impl Color {
8-
pub fn write(&self, stream: &mut impl Write, samples_per_pixel: i32) -> std::io::Result<()> {
8+
pub fn write(&self, img: &mut RgbImage, x: u32, y: u32, samples_per_pixel: i32) {
99
// Divide the color by the number of samples
1010
let scale = 1.0 / samples_per_pixel as f64;
1111
let r = (self.x() * scale).sqrt();
1212
let g = (self.y() * scale).sqrt();
1313
let b = (self.z() * scale).sqrt();
1414

15-
writeln!(
16-
stream,
17-
"{} {} {}",
18-
(255.99 * r.clamp(0.0, 0.999)) as i32,
19-
(255.99 * g.clamp(0.0, 0.999)) as i32,
20-
(255.99 * b.clamp(0.0, 0.999)) as i32
21-
)
15+
img.put_pixel(
16+
x,
17+
y,
18+
Rgb([
19+
(255.99 * r.clamp(0.0, 0.999)) as u8,
20+
(255.99 * g.clamp(0.0, 0.999)) as u8,
21+
(255.99 * b.clamp(0.0, 0.999)) as u8,
22+
]),
23+
);
2224
}
2325
}

src/image.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use crate::hittable::Hittable;
55
use crate::random::canonical_random;
66
use crate::ray::Ray;
77
use crate::vec3::Vec3;
8-
use std::io::Write;
8+
9+
use image::DynamicImage;
910

1011
/// Represent an image to be rendered
1112
pub struct Image {
12-
image_width: i32,
13-
image_height: i32,
13+
image_width: u32,
14+
image_height: u32,
1415
world: HittableList,
1516
camera: Camera,
1617
}
@@ -20,7 +21,7 @@ impl Image {
2021
/// with its camera
2122
pub fn new(
2223
aspect_ratio: f64,
23-
image_width: i32,
24+
image_width: u32,
2425
world: HittableList,
2526
lookfrom: Vec3,
2627
lookat: Vec3,
@@ -29,7 +30,7 @@ impl Image {
2930
aperture: f64,
3031
vertical_fov: f64,
3132
) -> Image {
32-
let image_height = (image_width as f64 / aspect_ratio) as i32;
33+
let image_height = (image_width as f64 / aspect_ratio) as u32;
3334
let camera = Camera::new(
3435
lookfrom,
3536
lookat,
@@ -72,17 +73,8 @@ impl Image {
7273

7374
/// Renders the image to the PPM format to the specified stream
7475
/// (may be a file or just standard output)
75-
pub fn render_image(
76-
&self,
77-
stream: &mut impl Write,
78-
samples_per_pixel: i32,
79-
max_depth: i32,
80-
) -> std::io::Result<()> {
81-
write!(
82-
stream,
83-
"P3\n{} {}\n255\n",
84-
self.image_width, self.image_height
85-
)?;
76+
pub fn render_image(&self, samples_per_pixel: i32, max_depth: i32) -> DynamicImage {
77+
let mut img = DynamicImage::new_rgb8(self.image_width, self.image_height);
8678

8779
for j in (0..self.image_height).rev() {
8880
eprint!("\rLines remaining: {} ", j);
@@ -94,10 +86,10 @@ impl Image {
9486
let r = self.camera.get_ray(u, v);
9587
pixel_color += self.ray_color(r, max_depth);
9688
}
97-
pixel_color.write(stream, samples_per_pixel)?
89+
pixel_color.write(img.as_mut_rgb8().unwrap(), i, j, samples_per_pixel);
9890
}
9991
}
10092

101-
Ok(())
93+
img
10294
}
10395
}

src/main.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::material::metal::Metal;
88
use crate::random::{canonical_random, random_range};
99
use crate::vec3::{Point3, Vec3};
1010

11-
use std::io::stdout;
11+
use std::path::Path;
1212
use std::rc::Rc;
1313

1414
mod camera;
@@ -116,8 +116,10 @@ fn main() {
116116
let max_depth = 50;
117117

118118
image
119-
.render_image(&mut stdout(), samples_per_pixel, max_depth)
120-
.expect("An error occurred while writing to standard output");
119+
.render_image(samples_per_pixel, max_depth)
120+
.flipv()
121+
.save_with_format(Path::new("./image.bmp"), ::image::ImageFormat::Bmp)
122+
.expect("An error occurred while writing the image to the file.");
121123

122124
eprintln!("\nDone!");
123125
}

0 commit comments

Comments
 (0)