2016-08-11 2 views
3

u8バイト(1ピクセルあたり4バイト - RGBA)のベクトルが与えられた場合、これをどのようにしてPNGファイルに保存できますか?錆にPNG画像を保存するには?

+0

[あなたの試みはどこですか?](http://meta.stackoverflow.com/q/261592/155423) – Shepmaster

+0

@Shepmaster、公正なポイント、実際に私は自分の答えを書く意図で尋ねた(まだ計画されています)、この質問に似ていますが、これは複数の有益な答えを持っています - http://stackoverflow.com/questions/902761(私自身の答えをPythonからRustに移植しようとしています) – ideasman42

+0

あなたは自分の自己回答が準備が整うまで待ってから、それほど素晴らしい質問を投稿することはできません。 – Shepmaster

答えて

12

生のバッファをディスクに保存するには、use the image crate in the Piston repositoryを使用できます。ページの一番下に

の例では、これを行う方法を示します..:

extern crate image; 

fn main() { 

    let buffer: &[u8] = ...; // Generate the image data 

    // Save the buffer as "image.png" 
    image::save_buffer(&Path::new("image.png"), buffer, 800, 600, image::RGBA(8)) 
} 
3

これは、PNG形式の画像書き込み機能の自己完結型、純粋な錆の実装です。

私のPythonの回答hereに基づいています。

  • 錆がZLIBを露出しないので、これは元のPythonコードよりもかなり大きいです。
  • これにより、圧縮されていないイメージを書き込むことによってzlibを使用することが回避されます。
  • crc32およびadler32チェックサム実装がモジュールとして含まれています。
  • チェックするキー機能はwriteで、書き込み可能なタイプ(通常はファイル)を使用します。

例:これは、基本的に、このスニペットと同じであるpng_encode_mini crate、になされたものであり、

mod crc32 { 
    // https://github.com/ledbettj/crc32/blob/master/rust/src/crc32.rs 
    pub struct Crc32 { 
     table: [u32; 256], 
     value: u32, 
    } 

    const CRC32_INITIAL: u32 = 0xedb88320; 

    impl Crc32 { 
     pub fn new() -> Crc32 { 
      let mut c = Crc32 { 
       table: [0; 256], 
       value: 0xffffffff, 
      }; 
      for i in 0..256 { 
       let mut v = i as u32; 
       for _ in 0..8 { 
        v = if v & 1 != 0 { 
         CRC32_INITIAL^(v >> 1) 
        } else { 
         v >> 1 
        } 
       } 
       c.table[i] = v; 
      } 
      return c; 
     } 

     pub fn start(&mut self) { 
      self.value = 0xffffffff; 
     } 

     pub fn update(&mut self, buf: &[u8]) { 
      for &i in buf { 
       self.value = self.table[((self.value^(i as u32)) & 0xff) as usize]^
          (self.value >> 8); 
      } 
     } 

     pub fn finalize(&mut self) -> u32 { 
      self.value^0xffffffff_u32 
     } 

     #[allow(dead_code)] 
     pub fn crc(&mut self, buf: &[u8]) -> u32 { 
      self.start(); 
      self.update(buf); 
      self.finalize() 
     } 
    } 
} 

mod adler32 { 
    // https://en.wikipedia.org/wiki/Adler-32 

    pub struct Adler32 { 
     a: u32, 
     b: u32, 
    } 

    const MOD_ADLER: u32 = 65521; 

    impl Adler32 { 
     pub fn new() -> Adler32 { 
      Adler32 { a: 1, b: 0 } 
     } 

     pub fn start(&mut self) { 
      self.a = 1; 
      self.b = 0; 
     } 

     pub fn update(&mut self, buf: &[u8]) { 
      for &i in buf { 
       self.a = (self.a + i as u32) % MOD_ADLER; 
       self.b = (self.a + self.b) % MOD_ADLER; 
      } 
     } 

     pub fn finalize(&self) -> u32 { 
      return (self.b << 16) | self.a; 
     } 

     #[allow(dead_code)] 
     pub fn crc(&mut self, buf: &[u8]) -> u32 { 
      self.start(); 
      self.update(buf); 
      self.finalize() 
     } 
    } 
} 

// big endian 
#[inline] 
fn u32_to_u8_be(v: u32) -> [u8; 4] { 
    [(v >> 24) as u8, (v >> 16) as u8, (v >> 8) as u8, v as u8] 
} 

mod fake_zlib { 
    use super::adler32; 
    use super::u32_to_u8_be; 

    // Use 'none' compression 
    pub fn compress(data: &[u8]) -> Vec<u8> { 
     const CHUNK_SIZE: usize = 65530; 

     let final_len = 
      // header 
      2 + 
      // every chunk adds 5 bytes [1:type, 4:size]. 
      (5 * { 
       let n = data.len()/CHUNK_SIZE; 
       // include an extra chunk when we don't fit exactly into CHUNK_SIZE 
       (n + {if data.len() == n * CHUNK_SIZE && data.len() != 0 { 0 } else { 1 }}) 
      }) + 
      // data 
      data.len() + 
      // crc 
      4 
     ; 

     let mut raw_data = Vec::with_capacity(final_len); 
     // header 
     raw_data.extend(&[120, 1]); 
     let mut pos_curr = 0_usize; 
     let mut crc = adler32::Adler32::new(); 
     loop { 
      let pos_next = ::std::cmp::min(data.len(), pos_curr + CHUNK_SIZE); 
      let chunk_len = (pos_next - pos_curr) as u32; 
      let is_last = pos_next == data.len(); 
      raw_data.extend(&[ 
       // type 
       if is_last { 1 } else { 0 }, 

       // size 
       (chunk_len & 0xff) as u8, 
       ((chunk_len >> 8) & 0xff) as u8, 
       (0xff - (chunk_len & 0xff)) as u8, 
       (0xff - ((chunk_len >> 8) & 0xff)) as u8, 
      ]); 

      raw_data.extend(&data[pos_curr..pos_next]); 

      crc.update(&data[pos_curr..pos_next]); 

      if is_last { 
       break; 
      } 
      pos_curr = pos_next; 
     } 

     raw_data.extend(&u32_to_u8_be(crc.finalize())); 

     assert_eq!(final_len, raw_data.len()); 
     return raw_data; 
    } 
} 

/// 
/// Write RGBA pixels to uncompressed PNG. 
/// 
pub fn write<W: ::std::io::Write>(
    file: &mut W, 
    image: &[u8], 
    w: u32, 
    h: u32, 
) -> Result<(), ::std::io::Error> { 

    assert!(w as usize * h as usize * 4 == image.len()); 

    fn png_pack<W: ::std::io::Write>(
     file: &mut W, 
     png_tag: &[u8; 4], 
     data: &[u8], 
    ) -> Result<(), ::std::io::Error> { 
     file.write(&u32_to_u8_be(data.len() as u32))?; 
     file.write(png_tag)?; 
     file.write(data)?; 
     { 
      let mut crc = crc32::Crc32::new(); 
      crc.start(); 
      crc.update(png_tag); 
      crc.update(data); 
      file.write(&u32_to_u8_be(crc.finalize()))?; 
     } 
     Ok(()) 
    } 

    file.write(b"\x89PNG\r\n\x1a\n")?; 
    { 
     let wb = u32_to_u8_be(w); 
     let hb = u32_to_u8_be(h); 
     let data = [wb[0], wb[1], wb[2], wb[3], 
        hb[0], hb[1], hb[2], hb[3], 
        8, 6, 0, 0, 0]; 
     png_pack(file, b"IHDR", &data)?; 
    } 

    { 
     let width_byte_4 = w * 4; 
     let final_len = (width_byte_4 + 1) * h; 
     let mut raw_data = Vec::with_capacity(final_len as usize); 
     let mut span: u32 = (h - 1) * width_byte_4; 
     loop { 
      raw_data.push(0); 
      raw_data.extend((&image[(span as usize)..(span + width_byte_4) as usize])); 
      if span == 0 { 
       break; 
      } 
      span -= width_byte_4; 
     } 
     assert!(final_len == (raw_data.len() as u32)); 

     png_pack(file, b"IDAT", &fake_zlib::compress(&raw_data))?; 
    } 

    png_pack(file, b"IEND", &[])?; 

    Ok(()) 
} 


fn main() { 
    let mut f = std::fs::File::create("test.png").unwrap(); 

    // image from bottom to top 3x2 
    let image_width = 3; 
    let image_height = 2; 
    let image = vec!(
     // R  G  B  A 
     0xff, 0x00, 0x00, 0xff, 
     0x00, 0xff, 0x00, 0xff, 
     0x00, 0x00, 0xff, 0xff, 

     0x80, 0x00, 0x00, 0xff, 
     0x00, 0x80, 0x00, 0xff, 
     0x00, 0x00, 0x80, 0xff, 
    ); 

    match write(&mut f, &image, image_width, image_height) { 
     Ok(_) => println!("Written image!"), 
     Err(e) => println!("Error {:?}", e), 
    } 
} 

関連する問題