Initial commit

This commit is contained in:
mykola2312 2023-11-07 06:09:14 +02:00
commit a49a9bbb90
4 changed files with 432 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
/target
*.bin
*.bak
*.txt
*.bmp
*.jpg

23
Cargo.lock generated Normal file
View file

@ -0,0 +1,23 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "lab2"
version = "0.1.0"
dependencies = [
"anyhow",
"byteorder",
]

10
Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "lab2"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.75"
byteorder = "1.5.0"

393
src/main.rs Normal file
View file

@ -0,0 +1,393 @@
use anyhow::{anyhow, Result};
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use std::{
fs::{File, OpenOptions},
io::{BufReader, BufWriter, Seek, SeekFrom},
path::Path,
};
#[derive(Debug)]
struct Pixel {
pub r: u8,
pub g: u8,
pub b: u8,
}
trait Image {
fn width(&self) -> u32;
fn height(&self) -> u32;
fn pixel(&self, x: u32, y: u32) -> &Pixel;
fn pixel_mut(&mut self, x: u32, y: u32) -> &mut Pixel;
}
#[derive(Debug)]
struct BMP {
magic: u16,
size: u32,
offset: u32,
hdr_size: u32,
width: u32,
height: u32,
num_planes: u16,
bpp: u16,
compression: u32,
image_size: u32,
h_ppm: i32,
v_ppm: i32,
num_colors: u32,
used_colors: u32,
pixels: Vec<Pixel>,
}
impl BMP {
fn read(path: &Path) -> Result<Self> {
let file = OpenOptions::new().read(true).open(path)?;
let mut rd = BufReader::new(file);
let magic = rd.read_u16::<LE>()?;
let size = rd.read_u32::<LE>()?;
let _ = rd.read_u32::<LE>()?;
let offset = rd.read_u32::<LE>()?;
let hdr_size = rd.read_u32::<LE>()?;
let width = rd.read_u32::<LE>()?;
let height = rd.read_u32::<LE>()?;
let num_planes = rd.read_u16::<LE>()?;
let bpp = rd.read_u16::<LE>()?;
let compression = rd.read_u32::<LE>()?;
let image_size = rd.read_u32::<LE>()?;
let h_ppm = rd.read_i32::<LE>()?;
let v_ppm = rd.read_i32::<LE>()?;
let num_colors = rd.read_u32::<LE>()?;
let used_colors = rd.read_u32::<LE>()?;
let row_size = {
let row_bytes = (bpp as u32 / 8) * width;
4 * ((row_bytes / 4) + if row_bytes % 4 != 0 { 1 } else { 0 })
};
let mut pixels: Vec<Pixel> = Vec::new();
for y in (0..height as u32).rev() {
rd.seek(SeekFrom::Start((offset + y as u32 * row_size) as u64))?;
for _ in 0..width {
let b = rd.read_u8()?;
let g = rd.read_u8()?;
let r = rd.read_u8()?;
pixels.push(Pixel { r, g, b });
}
}
Ok(BMP {
magic,
size,
offset,
hdr_size,
width,
height,
num_planes,
num_colors,
bpp,
compression,
image_size,
h_ppm,
v_ppm,
used_colors,
pixels,
})
}
fn write(&self, path: &Path) -> Result<()> {
let file = OpenOptions::new().write(true).create(true).open(path)?;
let mut wd = BufWriter::new(file);
wd.write_u16::<LE>(self.magic)?;
wd.write_u32::<LE>(self.size)?;
wd.write_u32::<LE>(0)?;
wd.write_u32::<LE>(self.offset)?;
wd.write_u32::<LE>(self.hdr_size)?;
wd.write_u32::<LE>(self.width)?;
wd.write_u32::<LE>(self.height)?;
wd.write_u16::<LE>(self.num_planes)?;
wd.write_u16::<LE>(self.bpp)?;
wd.write_u32::<LE>(self.compression)?;
wd.write_u32::<LE>(self.image_size)?;
wd.write_i32::<LE>(self.h_ppm)?;
wd.write_i32::<LE>(self.v_ppm)?;
wd.write_u32::<LE>(self.num_colors)?;
wd.write_u32::<LE>(self.used_colors)?;
let pad = {
let row_bytes = (self.bpp as u32 / 8) * self.width;
let row_size = 4 * ((row_bytes / 4) + if row_bytes % 4 != 0 { 1 } else { 0 });
row_size - row_bytes
};
for y in (0..self.height).rev() {
for x in 0..self.width {
let pixel = self.pixel(x, y);
wd.write_u8(pixel.b)?;
wd.write_u8(pixel.g)?;
wd.write_u8(pixel.r)?;
}
for _ in 0..pad {
wd.write_u8(0)?;
}
}
Ok(())
}
}
impl Image for BMP {
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
fn pixel(&self, x: u32, y: u32) -> &Pixel {
&self.pixels[(x + y * self.width) as usize]
}
fn pixel_mut(&mut self, x: u32, y: u32) -> &mut Pixel {
&mut self.pixels[(x + y * self.width) as usize]
}
}
struct FileBitReader {
pub size: u64,
rd: BufReader<File>,
bit_position: u64,
}
impl FileBitReader {
pub fn open(path: &Path) -> Result<Self> {
let file = OpenOptions::new().read(true).open(path)?;
let size = file.metadata()?.len();
let rd = BufReader::new(file);
let bit_position: u64 = 0;
Ok(Self {
rd,
size,
bit_position,
})
}
pub fn read_bit(&mut self) -> Result<u8> {
self.rd.seek(SeekFrom::Start(self.bit_position / 8))?;
let bit = {
let byte = self.rd.read_u8()?;
(byte >> (self.bit_position % 8)) & 1
};
self.bit_position += 1;
Ok(bit)
}
pub fn read_bits(&mut self, len: u8) -> Result<u8> {
assert!(len > 0 && len <= 8);
let mut out: u8 = 0;
for i in 0..len {
out |= self.read_bit()? << i;
}
Ok(out)
}
}
struct FileBitWriter {
wd: BufWriter<File>,
bit_position: u64,
byte: Option<u8>,
}
impl FileBitWriter {
pub fn open(path: &Path) -> Result<Self> {
let file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)?;
let wd = BufWriter::new(file);
let bit_position: u64 = 0;
let byte = None;
Ok(Self {
wd,
bit_position,
byte,
})
}
fn flush(&mut self) -> Result<()> {
if let Some(byte) = self.byte {
self.wd.write_u8(byte)?;
self.byte = None;
}
Ok(())
}
pub fn write_bit(&mut self, bit: u8) -> Result<()> {
self.byte = if let Some(byte) = self.byte {
let value = byte | (bit << (self.bit_position % 8));
Some(value)
} else {
Some(bit)
};
self.bit_position += 1;
if self.bit_position != 0 && self.bit_position % 8 == 0 {
self.flush()?;
}
Ok(())
}
pub fn write_bits(&mut self, mut bits: u8, len: u8) -> Result<()> {
assert!(len > 0 && len <= 8);
for i in 0..len {
self.write_bit(bits & 1)?;
bits >>= 1;
}
Ok(())
}
}
impl Drop for FileBitWriter {
fn drop(&mut self) {
self.flush().expect("flush before drop");
}
}
struct ImageDataStream<T: Image> {
image: T,
}
impl<T: Image> ImageDataStream<T> {
pub fn new(image: T) -> Self {
Self { image }
}
fn pixel(&self, addr: u32) -> &Pixel {
self.image
.pixel(addr % self.image.width(), addr / self.image.height())
}
fn pixel_mut(&mut self, addr: u32) -> &mut Pixel {
self.image
.pixel_mut(addr % self.image.width(), addr / self.image.height())
}
const R_BITS: u8 = 3;
const G_BITS: u8 = 2;
const B_BITS: u8 = 2;
const R_MASK: u8 = (1 << Self::R_BITS) - 1;
const G_MASK: u8 = (1 << Self::G_BITS) - 1;
const B_MASK: u8 = (1 << Self::B_BITS) - 1;
const B_POS: u8 = 0;
const G_POS: u8 = Self::B_BITS;
const R_POS: u8 = Self::G_BITS + Self::B_BITS;
const WORD_SIZE: u8 = Self::R_BITS + Self::G_BITS + Self::B_BITS;
const WORD_MASK: u8 = (1 << Self::WORD_SIZE) - 1;
pub fn read_word(&self, addr: u32) -> u8 {
let pixel = self.pixel(addr);
(pixel.r & Self::R_MASK) << Self::R_POS
| (pixel.g & Self::G_MASK) << Self::G_POS
| (pixel.b & Self::B_MASK) << Self::B_POS
}
pub fn write_word(&mut self, addr: u32, value: u8) {
let pixel = self.pixel_mut(addr);
pixel.r = (pixel.r & !Self::R_MASK) | ((value >> Self::R_POS) & Self::R_MASK);
pixel.g = (pixel.g & !Self::G_MASK) | ((value >> Self::G_POS) & Self::G_MASK);
pixel.b = (pixel.b & !Self::B_MASK) | (value & Self::B_MASK);
}
const HEADER_SIZE: u8 = 63;
const HEADER_WORDS: u8 = Self::HEADER_SIZE / Self::WORD_SIZE;
fn read_header(&self) -> u64 {
let mut header: u64 = 0;
for i in 0..Self::HEADER_WORDS {
header |= (self.read_word(i as u32) as u64) << (i * Self::WORD_SIZE);
}
header
}
fn write_header(&mut self, header: u64) {
for i in 0..Self::HEADER_WORDS {
let value = (header >> (i * Self::WORD_SIZE)) as u8 & Self::WORD_MASK;
self.write_word(i as u32, value);
}
}
const DATA_START: u64 = Self::HEADER_WORDS as u64;
pub fn read_stream(&self, output: &mut FileBitWriter) -> Result<()> {
let bytes = self.read_header();
let bits = bytes * 8;
let count = bits / Self::WORD_SIZE as u64;
let rem = bits % Self::WORD_SIZE as u64;
for i in Self::DATA_START..Self::DATA_START + count {
output.write_bits(self.read_word(i as u32), Self::WORD_SIZE)?;
}
if rem != 0 {
let value = self.read_word((Self::DATA_START + count) as u32);
output.write_bits(value, rem as u8)?; // & !((1<<rem)-1);
}
Ok(())
}
pub fn write_stream(&mut self, input: &mut FileBitReader) -> Result<()> {
let bytes = input.size;
let bits = bytes * 8;
let count = bits / Self::WORD_SIZE as u64;
let rem = bits % Self::WORD_SIZE as u64;
self.write_header(bytes);
for i in Self::DATA_START..Self::DATA_START + count {
self.write_word(i as u32, input.read_bits(Self::WORD_SIZE)?);
}
if rem != 0 {
let value = input.read_bits(rem as u8)?;
self.write_word((Self::DATA_START + count) as u32, value);
}
Ok(())
}
pub fn into_inner(self) -> T {
self.image
}
}
fn main() {
let bmp = BMP::read(Path::new("blank.bmp")).expect("read");
let mut test = ImageDataStream::new(bmp);
let mut input = FileBitReader::open(Path::new("input.jpg")).expect("open");
test.write_stream(&mut input).expect("write_stream");
let mut output = FileBitWriter::open(Path::new("output.jpg")).expect("open");
test.read_stream(&mut output).expect("read_stream");
let out = test.into_inner();
out.write(Path::new("test2.bmp")).expect("write");
}