summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock126
-rw-r--r--Cargo.toml5
-rw-r--r--src/bmp.rs107
-rw-r--r--src/image.rs89
-rw-r--r--src/main.rs187
-rw-r--r--src/reader.rs8
-rw-r--r--src/writer.rs69
7 files changed, 280 insertions, 311 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4dafa25..fe5b1d1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,131 +3,5 @@
version = 4
[[package]]
-name = "cfg-if"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
-
-[[package]]
-name = "getrandom"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.186"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
-dependencies = [
- "zerocopy",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.118"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
name = "testing"
version = "0.1.0"
-dependencies = [
- "rand",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
-
-[[package]]
-name = "wasi"
-version = "0.11.1+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
-
-[[package]]
-name = "zerocopy"
-version = "0.8.52"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
-dependencies = [
- "zerocopy-derive",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.8.52"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
diff --git a/Cargo.toml b/Cargo.toml
index 8b225fa..10fb7c7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,4 @@
[package]
name = "testing"
version = "0.1.0"
-edition = "2024"
-
-[dependencies]
-rand = "0.8.5"
+edition = "2024" \ No newline at end of file
diff --git a/src/bmp.rs b/src/bmp.rs
new file mode 100644
index 0000000..f6c0c7e
--- /dev/null
+++ b/src/bmp.rs
@@ -0,0 +1,107 @@
+use crate::{image::{ColorType, Image, ImageBase, PixelArr, RGB}, reader::FileReader, writer::FileWriter};
+
+impl Image for BMPImage
+{
+ fn read_image(reader: &mut FileReader) -> Result<ImageBase, &'static str>
+ {
+ let magic: [u8; 2] = reader.read_array();
+ if magic != [0x42, 0x4d]
+ {
+ return Err("Not a bitmap!");
+ }
+
+ let _file_size: u32 = reader.read();
+ reader.skip(4);
+ let _offset: u32 = reader.read();
+
+ let header_size: u32 = reader.read();
+
+ // println!("File header: {file_size} {offset} {header_size}");
+
+ if header_size == 40
+ {
+
+ let width: u32 = reader.read();
+ let height: u32 = reader.read();
+ let _color_planes: u16 = reader.read();
+ let bpp = reader.read::<2, u16>() as u8;
+ let compression_method: u32 = reader.read();
+ let _image_size: u32 = reader.read();
+ let _horr_res: u32 = reader.read();
+ let _vert_res: u32 = reader.read();
+ let _color_count: u32 = reader.read();
+ let _impotant_color_count: u32 = reader.read();
+
+ if
+ bpp != 24
+ || compression_method != 0
+ {
+ return Err("bpp or compresssion method not supported")
+ }
+
+ let row_size = (((bpp as u32) * width + 31)/32) * 4;
+ let skip: usize = (row_size - width * 3) as usize;
+ let mut pixel_arr = PixelArr::new(width, height);
+ for y in (0..height).rev()
+ {
+ for x in 0..width
+ {
+ let mut pixel = RGB::DEFAULT;
+ pixel.b = reader.read();
+ pixel.g = reader.read();
+ pixel.r = reader.read();
+ pixel_arr[(x as usize, y as usize)] = pixel;
+ }
+ reader.skip(skip);
+ }
+
+ return Ok(ImageBase
+ {
+ bit_depth: bpp,
+ pixels: pixel_arr,
+ })
+ }
+ else
+ {
+ return Err("Header size not supported yet");
+ }
+
+
+ }
+
+ fn write_image(image: &ImageBase, writer: &mut FileWriter) -> () {
+ writer.write_array([0x42, 0x4d] as [u8; 2]);
+
+ let row_size = (((24) * image.pixels.width + 31)/32) * 4;
+ let file_size: u32 = 14 + 12 + row_size*image.pixels.height;
+ let offset: u32 = 26;
+ writer.write(file_size as u32);
+ writer.write_zeros(4);
+ writer.write(offset as u32);
+ writer.write(12 as u32); // Header size
+
+ writer.write(image.pixels.width as u16);
+ writer.write(image.pixels.height as u16);
+ writer.write(1 as u16); // Color planes
+ writer.write(24 as u16); // bpp
+
+ let skip: usize = (row_size - image.pixels.width * 3) as usize;
+ for y in (0..image.pixels.height).rev()
+ {
+ for x in 0..image.pixels.width
+ {
+ let pixel = image.pixels[(x as usize, y as usize)];
+ writer.write(pixel.b);
+ writer.write(pixel.g);
+ writer.write(pixel.r);
+ }
+ writer.write_zeros(skip);
+ }
+ writer.flush();
+ }
+}
+
+
+pub struct BMPImage
+{
+}
diff --git a/src/image.rs b/src/image.rs
new file mode 100644
index 0000000..ab5dc99
--- /dev/null
+++ b/src/image.rs
@@ -0,0 +1,89 @@
+use std::ops;
+
+use crate::{reader::FileReader, writer::FileWriter};
+
+pub trait ColorDepth: Clone
+{
+ const DEFAULT: Self;
+}
+impl ColorDepth for u8 {
+ const DEFAULT: Self = 0;
+}
+impl ColorDepth for u16 {
+ const DEFAULT: Self = 0;
+}
+impl ColorDepth for u32 {
+ const DEFAULT: Self = 0;
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct RGBA<T: ColorDepth>
+{
+ pub r: T,
+ pub g: T,
+ pub b: T,
+ pub a: T
+}
+#[derive(Debug, Clone, Copy)]
+pub struct RGB<T: ColorDepth>
+{
+ pub r: T,
+ pub g: T,
+ pub b: T,
+}
+
+pub trait ColorType: Clone
+{
+ const DEFAULT: Self;
+}
+impl<T: ColorDepth> ColorType for RGBA<T>
+{
+ const DEFAULT: Self = Self { r: T::DEFAULT, g: T::DEFAULT, b: T::DEFAULT, a: T::DEFAULT };
+}
+impl<T: ColorDepth> ColorType for RGB<T>
+{
+ const DEFAULT: Self = Self { r: T::DEFAULT, g: T::DEFAULT, b: T::DEFAULT};
+}
+
+#[derive(Debug)]
+pub struct PixelArr<T: ColorType>
+{
+ pub width: u32,
+ pub height: u32,
+ raw: Vec<T>
+}
+impl<T: ColorType> PixelArr<T> {
+ pub fn new(width: u32, height: u32) -> Self {
+ let raw = vec![T::DEFAULT;(width*height) as usize];
+ Self { width, height, raw }
+ }
+}
+impl<T: ColorType> ops::Index<(usize, usize)> for PixelArr<T>
+{
+ type Output = T;
+
+ fn index(&self, index: (usize, usize)) -> &Self::Output {
+ let (x, y) = index;
+ &self.raw[x + y*(self.width as usize)]
+ }
+}
+impl<T: ColorType> ops::IndexMut<(usize, usize)> for PixelArr<T>
+{
+ fn index_mut(&mut self, index: (usize, usize)) -> &mut T {
+ let (x, y) = index;
+ &mut self.raw[x + y*(self.width as usize)]
+ }
+}
+
+#[derive(Debug)]
+pub struct ImageBase
+{
+ pub bit_depth: u8,
+ pub pixels: PixelArr<RGB<u8>>
+}
+
+pub trait Image
+{
+ fn read_image(reader: &mut FileReader) -> Result<ImageBase, &'static str>;
+ fn write_image(image: &ImageBase, writer: &mut FileWriter)-> ();
+}
diff --git a/src/main.rs b/src/main.rs
index c348e77..2d68a02 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,185 +1,18 @@
-// #![allow(dead_code)]
-
-use crate::reader::FileReader;
-use std::{fs::File, io::BufReader, ops::{self}};
+use crate::{bmp::BMPImage, image::Image, reader::FileReader, writer::FileWriter};
+use std::{fs::File, io::{BufReader, BufWriter}};
mod reader;
-
-// #[derive(Debug)]
-// struct RGB<T: Add<Output = T> + Copy>
-// {
-// r: T,
-// g: T,
-// b: T
-// }
-
-trait ColorDepth: Clone
-{
- const DEFAULT: Self;
-}
-impl ColorDepth for u8 {
- const DEFAULT: Self = 0;
-}
-impl ColorDepth for u16 {
- const DEFAULT: Self = 0;
-}
-impl ColorDepth for u32 {
- const DEFAULT: Self = 0;
-}
-
-#[derive(Debug, Clone)]
-struct RGBA<T: ColorDepth>
-{
- r: T,
- g: T,
- b: T,
- a: T
-}
-#[derive(Debug, Clone)]
-struct RGB<T: ColorDepth>
-{
- r: T,
- g: T,
- b: T,
-}
-
-trait ColorType: Clone
-{
- const DEFAULT: Self;
-}
-impl<T: ColorDepth> ColorType for RGBA<T>
-{
- const DEFAULT: Self = Self { r: T::DEFAULT, g: T::DEFAULT, b: T::DEFAULT, a: T::DEFAULT };
-}
-impl<T: ColorDepth> ColorType for RGB<T>
-{
- const DEFAULT: Self = Self { r: T::DEFAULT, g: T::DEFAULT, b: T::DEFAULT};
-}
-
-#[derive(Debug)]
-struct PixelArr<T: ColorType>
-{
- width: u32,
- height: u32,
- raw: Vec<T>
-}
-impl<T: ColorType> PixelArr<T> {
- fn new(width: u32, height: u32) -> Self {
- let raw = vec![T::DEFAULT;(width*height) as usize];
- Self { width, height, raw }
- }
-}
-impl<T: ColorType> ops::Index<(usize, usize)> for PixelArr<T>
-{
- type Output = T;
-
- fn index(&self, index: (usize, usize)) -> &Self::Output {
- let (x, y) = index;
- &self.raw[x + y*(self.width as usize)]
- }
-}
-impl<T: ColorType> ops::IndexMut<(usize, usize)> for PixelArr<T>
-{
- fn index_mut(&mut self, index: (usize, usize)) -> &mut T {
- let (x, y) = index;
- &mut self.raw[x + y*(self.width as usize)]
- }
-}
-
-#[derive(Debug)]
-struct ImageBase
-{
- width: u32,
- height: u32,
- bit_depth: u8,
- pixels: PixelArr<RGB<u8>>
-}
-
-struct BMPImage
-{
-}
-
-
-trait Image
-{
- fn read_image(reader: &mut FileReader) -> Result<ImageBase, &'static str>;
-}
-
-impl Image for BMPImage
-{
- fn read_image(reader: &mut FileReader) -> Result<ImageBase, &'static str>
- {
- let magic: [u8; 2] = reader.read_array();
- if magic != [0x42, 0x4d]
- {
- return Err("Not a bitmap!");
- }
-
- let _file_size: u32 = reader.read();
- reader.skip(4);
- let _offset: u32 = reader.read();
-
- let header_size: u32 = reader.read();
-
- // println!("File header: {file_size} {offset} {header_size}");
-
- if header_size == 40
- {
-
- let width: u32 = reader.read();
- let height: u32 = reader.read();
- let _color_planes: u16 = reader.read();
- let bpp = reader.read::<2, u16>() as u8;
- let compression_method: u32 = reader.read();
- let _image_size: u32 = reader.read();
- let _horr_res: u32 = reader.read();
- let _vert_res: u32 = reader.read();
- let _color_count: u32 = reader.read();
- let _impotant_color_count: u32 = reader.read();
-
- if
- bpp != 24
- || compression_method != 0
- {
- return Err("bpp or compresssion method not supported")
- }
-
- let row_size = (((bpp as u32) * width + 31)/32) * 4;
- let skip: usize = (row_size - width * 3) as usize;
- let mut pixel_arr = PixelArr::new(width, height);
- for y in (0..height).rev()
- {
- for x in 0..width
- {
- let mut pixel = RGB::DEFAULT;
- pixel.b = reader.read();
- pixel.g = reader.read();
- pixel.r = reader.read();
- pixel_arr[(x as usize, y as usize)] = pixel;
- }
- reader.skip(skip);
- }
-
- return Ok(ImageBase
- {
- width,
- height,
- bit_depth: bpp,
- pixels: pixel_arr,
- })
- }
- else
- {
- return Err("Header size not supported yet");
- }
-
-
- }
-}
+mod image;
+mod bmp;
+mod writer;
fn main() {
let file = File::open("smiley.bmp").expect("File does not exist");
let mut reader = FileReader::new(BufReader::new(file));
let _bmp = BMPImage::read_image(&mut reader).expect("Bitmap had error");
- // println!("{bmp:?}");
+
+ let out_file = File::create("tmp.bmp").expect("Cannot create fiel");
+ let mut writer = FileWriter::new(BufWriter::new(out_file));
+ BMPImage::write_image(&_bmp, &mut writer);
+ // println!("{_bmp:?}");
}
diff --git a/src/reader.rs b/src/reader.rs
index affd2da..00f66cb 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -1,11 +1,11 @@
use std::{fs::File, io::{BufReader, Read}};
-pub struct FileReader<const BUFF_SIZE: usize = 1024>
+pub struct FileReader
{
buf_reader: BufReader<File>
}
-impl<const BUFF_SIZE: usize> FileReader<BUFF_SIZE> {
+impl FileReader {
pub fn new(buf_reader: BufReader<File>) -> Self
{
Self
@@ -23,7 +23,7 @@ impl<const BUFF_SIZE: usize> FileReader<BUFF_SIZE> {
std::array::from_fn(|_| self.read())
}
- pub fn read<const N: usize, T: FromBytes<N> + Sized>(&mut self) -> T
+ pub fn read<const N: usize, T: FromBytes<N>>(&mut self) -> T
{
let mut data = [0u8; N];
self.buf_reader.read_exact(&mut data).expect("Bad read");
@@ -31,7 +31,7 @@ impl<const BUFF_SIZE: usize> FileReader<BUFF_SIZE> {
}
}
-pub trait FromBytes<const N: usize>: Sized
+pub trait FromBytes<const N: usize>: Sized + Copy
{
fn from_le_bytes(buffer: &[u8; N]) -> Self;
}
diff --git a/src/writer.rs b/src/writer.rs
new file mode 100644
index 0000000..dc1ac85
--- /dev/null
+++ b/src/writer.rs
@@ -0,0 +1,69 @@
+use std::io::Write;
+use std::{fs::File, io::BufWriter};
+
+pub struct FileWriter
+{
+ buf_writer: BufWriter<File>
+}
+
+impl FileWriter
+{
+ pub fn new(buf_writer: BufWriter<File>) -> Self
+ {
+ Self
+ {
+ buf_writer
+ }
+ }
+
+ pub fn write_zeros(&mut self, c: usize)
+ {
+ for _ in 0..c
+ {
+ self.write(0 as u8);
+ }
+ // self.buf_writer.write_all(&[0u8; c]).expect("Could not write 0s");
+ }
+
+ pub fn write_array<const N: usize, T: ToBytes<N>, const C: usize>(&mut self, xs: [T; C])
+ {
+ for x in xs
+ {
+ self.write(x);
+ }
+ }
+ pub fn write<const N: usize, T: ToBytes<N>>(&mut self, x: T)
+ {
+ let data = x.to_le_bytes();
+ self.buf_writer.write_all(&data).expect("Could not write");
+ }
+
+ pub fn flush(&mut self)
+ {
+ self.buf_writer.flush().expect("Could not flush");
+ }
+}
+
+pub trait ToBytes<const N: usize>: Sized + Copy
+{
+ fn to_le_bytes(&self) -> [u8; N];
+}
+
+impl ToBytes<4> for u32
+{
+ fn to_le_bytes(&self) -> [u8; 4] {
+ u32::to_le_bytes(*self)
+ }
+}
+impl ToBytes<2> for u16
+{
+ fn to_le_bytes(&self) -> [u8; 2] {
+ u16::to_le_bytes(*self)
+ }
+}
+impl ToBytes<1> for u8
+{
+ fn to_le_bytes(&self) -> [u8; 1] {
+ u8::to_le_bytes(*self)
+ }
+}