fortran66のブログ

fortran について書きます。

【メモ帳】rust で bmp 試しゴミ

週末 rust ゴミメモ帳

flang が、最初の威勢のよさとは裏腹になかなか進まないので、WebAssembly 吐き出すのに rust でもいじってみるかと数時間w 文法は並列プログラミングのデータレースの類を避けようとしていると思えば、分からなくもない? 

Fortranbmp 出力プログラムを移植しようとしましたが、バイナリでバイト以外の変数を出す方法がよく分からないです。I/O がそもそも難しいし、構造体の二次元配列が簡単に作れないし等々で一応四角がかけたところで、本殿に入る前に投げ出し。

出力

$ ./bmp
write test.bmp: 200 x 200

f:id:fortran66:20210412150134p:plain

Fortran (移植元)

    module m_bmp
        use, intrinsic :: iso_fortran_env
        implicit none
        type :: t_bmp_file_header
            sequence  
            integer(int16) :: bfType = transfer('BM', 0_int16) ! BitMap
            integer(int32) :: bfSize          ! file size in bytes
            integer(int16) :: bfReserved1 = 0 ! always 0
            integer(int16) :: bfReserved2 = 0 ! always 0
            integer(int32) :: bfOffBits
        end type t_bmp_file_header
        !
        type :: t_bmp_info_header
            sequence
            integer(int32) :: biSize     = Z'28' ! size of bmp_info_header ; 40bytes 
            integer(int32) :: biWidth
            integer(int32) :: biHeight
            integer(int16) :: biPlanes   = 1 ! always 1
            integer(int16) :: biBitCount
            integer(int32) :: biCompression = 0 ! 0:nocompression, 1:8bitRLE, 2:4bitRLE, 3:bitfield
            integer(int32) :: biSizeImage
            integer(int32) :: biXPelsPerMeter = 3780 ! 96dpi
            integer(int32) :: biYPelsPerMeter = 3780 ! 96dpi 
            integer(int32) :: biClrUsed       = 0
            integer(int32) :: biClrImportant  = 0 
        end type t_bmp_info_header
        !
        type :: t_rgb
            sequence
            integer(int8) :: ib, ig, ir
        end type t_rgb  
    contains   
        subroutine wr(bmp)
            type(t_rgb), intent(in) :: bmp(:, :)
            type(t_bmp_file_header) :: bmp_file_header
            type(t_bmp_info_header) :: bmp_info_header
            integer :: nx, ny
            nx = size(bmp, 1)
            ny = size(bmp, 2)
            bmp_file_header%bfSize      = 14 + 40 + 0 + nx * ny * 3
            bmp_file_header%bfOffBits   = 14 + 40
            bmp_info_header%biWidth     = nx
            bmp_info_header%biHeight    = ny
            bmp_info_header%biBitCount  = 24 
            bmp_info_header%biSizeImage = nx * ny * 3
            open(9, file = 'mandel.bmp', form = 'binary', status = 'unknown')
            write(9) bmp_file_header, bmp_info_header, bmp
            close(9)
        end subroutine wr  
    end module m_bmp
    
    program test
        use :: m_bmp
        implicit none
        integer, parameter :: nx = 200, ny = 200
        type(t_rgb) :: bmp(nx, ny)
        bmp = t_rgb(255, 255, 0)
        call wr(bmp)
    end program test

Fortran ハンドブック

Fortran ハンドブック

Rust

まるで分からん。

第三版

structure の配列: stackoverflow.com

use std::fs::File;
use std::io::{Write, BufWriter};
//use std::io::prelude::*;
use std::io;

struct BmpFileHeader {
    bf_type: i16, //'BM'
    bf_size: i32, // file size in bytes
    bf_reserved1: i16,
    bf_reserved2: i16,
    bf_off_bits: i32
}

struct  BmpInfoHeader{
    bi_size: i32,          // Z'28' ! size of bmp_info_header ; 40bytes 
    bi_width: i32,
    bi_height: i32,
    bi_planes: i16,       // = 1 ! always 1
    bi_bit_count: i16,
    bi_compression: i32,   // = 0 ! 0:nocompression, 1:8bitRLE, 2:4bitRLE, 3:bitfield
    bi_size_image: i32,
    bi_x_pels_per_meter: i32, // = 3780 ! 96dpi
    bi_y_pels_per_meter: i32, // = 3780 ! 96dpi 
    bi_clr_used: i32,       // = 0
    bi_clr_important: i32  // = 0    
}

trait Wr {
   fn wr(&self, writer: &mut BufWriter<File>) -> io::Result<()>;
}

impl Wr for BmpFileHeader {
    fn wr(&self, writer: &mut BufWriter<File>) -> io::Result<()> {
        let mut b2: [u8;2] = self.bf_type.to_le_bytes();
        writer.write_all(&b2)?;
        let mut b4: [u8;4] = self.bf_size.to_le_bytes();
        writer.write_all(&b4)?;
        b2 = self.bf_reserved1.to_le_bytes();
        writer.write_all(&b2)?;
        b2 = self.bf_reserved2.to_le_bytes();
        writer.write_all(&b2)?;
        b4 = self.bf_off_bits.to_le_bytes();
        writer.write_all(&b4)?;
        Ok(())
    }    
}

impl Wr for BmpInfoHeader{
    fn wr(&self, writer: &mut BufWriter<File>) -> io::Result<()> {
        let mut b4: [u8;4] = self.bi_size.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = self.bi_width.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = self.bi_height.to_le_bytes();
        writer.write_all(&b4)?;
        let mut b2: [u8;2] = self.bi_planes.to_le_bytes();
        writer.write_all(&b2)?;
        b2 = self.bi_bit_count.to_le_bytes();
        writer.write_all(&b2)?;
        b4 = self.bi_compression.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = self.bi_size_image.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = self.bi_x_pels_per_meter.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = self.bi_y_pels_per_meter.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = self.bi_clr_used.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = self.bi_clr_important.to_le_bytes();
        writer.write_all(&b4)?;
        Ok(())
    }
}


#[derive(Clone, Copy)]
struct Rgb {
    b: u8,
    g: u8,
    r: u8
}

struct Bmp {
    width: usize,
    height: usize,
    data: Box<[Rgb]>
}

trait Wri {
    fn wri(&self, filename: &str) -> io::Result<()>;
}
 
impl Wri for Bmp {
    fn wri(&self, filename: &str) -> io::Result<()> {
        let nx = self.width as i32;
        let ny = self.height as i32;
    
        let bfile_header = BmpFileHeader {bf_type: 0x4d42, bf_size: 14 + 40 + 0 + (3 * nx + (ny % 4)) * ny, bf_reserved1: 0, bf_reserved2: 0, bf_off_bits: 14 + 40};
        let binfo_header = BmpInfoHeader {bi_size: 0x28, bi_width: nx, bi_height: ny, bi_planes: 1, bi_bit_count: 24, bi_compression: 0,
                                          bi_size_image: (3 * nx + (ny % 4)) * ny, 
                                          bi_x_pels_per_meter: 3780, bi_y_pels_per_meter: 3780, bi_clr_used: 0, bi_clr_important: 0};

        let mut writer = BufWriter::new(File::create(filename)?);

        bfile_header.wr(&mut writer)?;
        binfo_header.wr(&mut writer)?; 
        for iy in 0..ny {
            for ix in 0..nx {
                let p = nx * iy + ix; 
                let a = self.data[p as usize];
                writer.write(&[a.b])?;
                writer.write(&[a.g])?;
                writer.write(&[a.r])?;
            }
        } 
        println!("write {}: {} x {}", &filename, nx, ny);
        Ok(())
    }
}


fn main() -> std::io::Result<()>  {
    const NX:usize = 200;
    const NY:usize = 200;
 
    let data = [Rgb{r:0, g:255, b:255}; NX * NY];
    let bmp = Bmp {
        width: NX,
        height: NY,
        data: Box::new(data)
    };
    
    let filename = "test.bmp";
    bmp.wri(filename)
}

第二版

use std::fs::File;
use std::io::{Write, BufWriter};
use std::io;

struct BmpFileHeader {
    bf_type: i16, //'BM'
    bf_size: i32, // file size in bytes
    bf_reserved1: i16,
    bf_reserved2: i16,
    bf_off_bits: i32
}

struct  BmpInfoHeader{
    bi_size: i32,          // Z'28' ! size of bmp_info_header ; 40bytes 
    bi_width: i32,
    bi_height: i32,
    bi_planes: i16,       // = 1 ! always 1
    bi_bit_count: i16,
    bi_compression: i32,   // = 0 ! 0:nocompression, 1:8bitRLE, 2:4bitRLE, 3:bitfield
    bi_size_image: i32,
    bi_x_pels_per_meter: i32, // = 3780 ! 96dpi
    bi_y_pels_per_meter: i32, // = 3780 ! 96dpi 
    bi_clr_used: i32,       // = 0
    bi_clr_important: i32  // = 0    
}

struct Rgb {
    b: u8,
    g: u8,
    r: u8
}

impl BmpFileHeader {
    fn wr(writer: &mut BufWriter<File>, bfile_header: &BmpFileHeader) -> io::Result<()> {
        let mut b2: [u8;2] = bfile_header.bf_type.to_le_bytes();
        writer.write_all(&b2)?;
        let mut b4: [u8;4] = bfile_header.bf_size.to_le_bytes();
        writer.write_all(&b4)?;
        b2 = bfile_header.bf_reserved1.to_le_bytes();
        writer.write_all(&b2)?;
        b2 = bfile_header.bf_reserved2.to_le_bytes();
        writer.write_all(&b2)?;
        b4 = bfile_header.bf_off_bits.to_le_bytes();
        writer.write_all(&b4)?;
    
        Ok(())
    }    
}

impl BmpInfoHeader{
    fn wr(writer: &mut BufWriter<File>, binfo_header: &BmpInfoHeader) -> io::Result<()> {
        let mut b4: [u8;4] = binfo_header.bi_size.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = binfo_header.bi_width.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = binfo_header.bi_height.to_le_bytes();
        writer.write_all(&b4)?;
        let mut b2: [u8;2] = binfo_header.bi_planes.to_le_bytes();
        writer.write_all(&b2)?;
        b2 = binfo_header.bi_bit_count.to_le_bytes();
        writer.write_all(&b2)?;
        b4 = binfo_header.bi_compression.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = binfo_header.bi_size_image.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = binfo_header.bi_x_pels_per_meter.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = binfo_header.bi_y_pels_per_meter.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = binfo_header.bi_clr_used.to_le_bytes();
        writer.write_all(&b4)?;
        b4 = binfo_header.bi_clr_important.to_le_bytes();
        writer.write_all(&b4)?;
        
        Ok(())
    }
}



fn main() -> std::io::Result<()>  {
    let nx = 200;
    let ny = 200;
    
    let bfile_header = BmpFileHeader {bf_type: 0x4d42, bf_size: 14 + 40 + 0 + (3 * nx + (ny % 4)) * ny, bf_reserved1: 0, bf_reserved2: 0, bf_off_bits: 14 + 40};
    let binfo_header = BmpInfoHeader {bi_size: 0x28, bi_width: nx, bi_height: ny, bi_planes: 1, bi_bit_count: 24, bi_compression: 0,
                                      bi_size_image: (3 * nx + (ny % 4)) * ny, 
                                      bi_x_pels_per_meter: 3780, bi_y_pels_per_meter: 3780, bi_clr_used: 0, bi_clr_important: 0};
    
    let filename = "test.bmp";
    let mut writer = BufWriter::new(File::create(filename)?);

    BmpFileHeader::wr(&mut writer, &bfile_header)?;
    BmpInfoHeader::wr(&mut writer, &binfo_header)?; 
    

    let a = Rgb{b: 255, g: 255, r: 0};
    for _iy in 0..ny {
        for _ix in 0..nx {
            writer.write(&[a.b])?;
            writer.write(&[a.g])?;
            writer.write(&[a.r])?;
        }
    } 

    println!("write {}: {} x {}", &filename, nx, ny);

    Ok(())
}

初版

use std::fs::File;
use std::io::{Write, BufWriter};


struct BmpFileHeader {
    bf_type: i16, //'BM'
    bf_size: i32, // file size in bytes
    bf_reserved1: i16,
    bf_reserved2: i16,
    bf_off_bits: i32
}

struct  BmpInfoHeader{
    bi_size: i32,          // Z'28' ! size of bmp_info_header ; 40bytes 
    bi_width: i32,
    bi_height: i32,
    bi_planes: i16,       // = 1 ! always 1
    bi_bit_count: i16,
    bi_compression: i32,   // = 0 ! 0:nocompression, 1:8bitRLE, 2:4bitRLE, 3:bitfield
    bi_size_image: i32,
    bi_x_pels_per_meter: i32, // = 3780 ! 96dpi
    bi_y_pels_per_meter: i32, // = 3780 ! 96dpi 
    bi_clr_used: i32,       // = 0
    bi_clr_important: i32  // = 0    
}

struct Rgb {
    b: u8,
    g: u8,
    r: u8
}

impl BmpFileHeader {
    fn new(bf_type: i16, bf_size: i32, bf_reserved1: i16, bf_reserved2: i16, bf_off_bits: i32) ->  BmpFileHeader{
       BmpFileHeader {bf_type: bf_type, bf_size: bf_size, bf_reserved1: bf_reserved1, bf_reserved2: bf_reserved2, bf_off_bits: bf_off_bits}
    }
}

impl BmpInfoHeader{
    fn new(bi_size: i32, bi_width: i32, bi_height: i32, bi_planes: i16, bi_bit_count: i16,
           bi_compression: i32, bi_size_image: i32, bi_x_pels_per_meter: i32, 
           bi_y_pels_per_meter: i32, bi_clr_used: i32, bi_clr_important: i32) -> BmpInfoHeader {
              BmpInfoHeader {
                bi_size: bi_size, bi_width: bi_width, bi_height: bi_height, bi_planes: bi_planes,
                bi_bit_count: bi_bit_count, bi_compression: bi_compression, 
                bi_size_image: bi_size_image, bi_x_pels_per_meter: bi_x_pels_per_meter, 
                bi_y_pels_per_meter: bi_y_pels_per_meter, bi_clr_used: bi_clr_used, bi_clr_important: bi_clr_important
              }
            }    
}


fn main() -> std::io::Result<()>  {
    let nx = 200;
    let ny = 200;
    
    let bfile_header = BmpFileHeader::new(0x4d42, 14 + 40 + 0 + (3 * nx + (ny % 4)) * ny, 0, 0, 14 + 40);
    let binfo_header = BmpInfoHeader::new(0x28, nx, ny, 1, 24, 0, (3 * nx + (ny % 4)) * ny, 3780, 3780, 0, 0);  
    let a = Rgb{b: 255, g: 255, r: 0};

    println!("write test.bmp: {} x {}", nx, ny);
    
    let mut writer = BufWriter::new(File::create("test.bmp")?);

    let b: [u8;2] = bfile_header.bf_type.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = bfile_header.bf_size.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;2] = bfile_header.bf_reserved1.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;2] = bfile_header.bf_reserved2.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = bfile_header.bf_off_bits.to_le_bytes();
    writer.write_all(&b)?;

    let b: [u8;4] = binfo_header.bi_size.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_width.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_height.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;2] = binfo_header.bi_planes.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;2] = binfo_header.bi_bit_count.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_compression.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_size_image.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_x_pels_per_meter.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_y_pels_per_meter.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_clr_used.to_le_bytes();
    writer.write_all(&b)?;
    let b: [u8;4] = binfo_header.bi_clr_important.to_le_bytes();
    writer.write_all(&b)?;

    for _iy in 0..ny {
        for _ix in 0..nx {
            writer.write(&[a.b])?;
            writer.write(&[a.g])?;
            writer.write(&[a.r])?;
        }
    }  
    Ok(())
}