2016-08-11 5 views
3

벡터가 u8 바이트 (픽셀 당 4 바이트 - RGBA) 인 경우 어떻게 PNG 파일에 저장할 수 있습니까?녹에 PNG 이미지를 저장하는 방법은 무엇입니까?

+0

[귀하의 시도는 어떤 연구입니까?] (http://meta.stackoverflow.com/q/261592/155423) – Shepmaster

+0

@Shepmaster, 공정한 지적, 사실 내 대답을 쓰려는 의도로 물었습니다. (여전히 계획), 여러 유용한 답변을 가지고이 질문과 유사 - http://stackoverflow.com/questions/902761 (나는 파이썬에서 녹이기까지 내 자신의 대답을 포팅 찾고 있어요). – 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 이미지의 쓰기 기능의 순수한 녹 구현입니다.

내 파이썬 대답은 here을 기반으로합니다.

참고 : 녹는 ZLIB를 노출하지 않기 때문에

  • 이 원래 파이썬 코드보다 꽤 크다.
  • 이렇게하면 압축되지 않은 이미지를 작성하여 zlib을 사용하지 않아도됩니다.
  • crc32adler32 체크섬 구현이 모듈로 포함되어 있습니다.
  • 확인할 핵심 기능은 쓰기 가능한 유형 (일반적으로 파일) 인 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), 
    } 
} 

.

관련 문제