Gegeben ein Vektor von u8
Bytes (4 Bytes pro Pixel - RGBA), wie kann dies in einer PNG-Datei gespeichert werden?Wie kann man ein PNG-Bild in Rust speichern?
3
A
Antwort
12
Sie könnten use the image crate in the Piston repository den Rohpuffer auf der Festplatte speichern.
Das Beispiel am unteren Rand der Seite sehen Sie, wie dies zu tun ..:
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
Dies ist ein selbst enthalten sind, reine Rust Implementierung einer Schreibfunktion PNG-Bild.
Es basiert auf meiner Python-Antwort here.
Hinweise:
- Da Rust nicht zlib belichten ist, das ist ein bisschen größer als der ursprüngliche Python-Code.
- Dies vermeidet die Verwendung von zlib durch Schreiben eines unkomprimierten Bildes.
crc32
undadler32
Prüfsummenimplementierungen sind als Module enthalten.- Die zu überprüfende Schlüsselfunktion ist
write
, die jeden beschreibbaren Typ (normalerweise eine Datei) übernimmt.
Beispiel:
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),
}
}
Dies ist seit dem in die png_encode_mini crate gemacht worden, die im Grunde die gleichen wie dieser Schnipsel ist.
Verwandte Themen
- 1. Kann man in Rust eine Kompilierzeitkonstante überprüfen?
- 2. Wie kann ich ein Muster in einer Variablen in Rust speichern?
- 3. Wie überprüft man, ob ein Thread in Rust fertig ist?
- 4. Wie erstellt man ein Handle für den Anwendungskontext in Rust?
- 5. Wie erstellt man ein virtuelles Dateisystem in Rust?
- 6. Wie speichern/holen Sie eine Struktur mit Redis in Rust?
- 7. Wie kann ich ein * Char über FFI in Rust freigeben?
- 8. Wie kann ich ein Speicherproblem in Rust debuggen?
- 9. Wie teilt man Funktionalität in Rust?
- 10. Wie kann man ein trainiertes Modell in theano speichern/serialisieren?
- 11. Wie misst man einen Funktionsstack in Rust?
- 12. Wie gruppiert man 'Options' in Rust?
- 13. Wie fügt man einem Rust-Merkmal ein Sized-Supertrait hinzu?
- 14. Kann ein Rust-Makro neue Kennungen erstellen?
- 15. In Rust, ist ein Vektor ein Iterator?
- 16. Wie dekodiert man ein JSON-Objekt mit dem Rust-Attributnamen?
- 17. Wie erstellt man ein Rust-Programm mit dem Atom-Editor?
- 18. Wie kann man mit der Karte .or_insert_with umgehen? Rust (1,11)
- 19. Wie speichern Sie ein SqliteConnection und SqliteStatement Objekte in der gleichen Struktur in Rust?
- 20. Wie kann man ein Passwort ohne Hashes sicher speichern?
- 21. Wie benutze ich stdout in Rust?
- 22. Plattform in Rust erkennen
- 23. Rust:
- 24. Wie man eine Anfrage mit Client-Zertifikat in Rust
- 25. Hat Rust ein Debug-Makro?
- 26. Wie man benannte Schleifenetiketten zu einem Makro in Rust übergibt?
- 27. Wie speichert Rust Enum-Werte in Arrays?
- 28. Wie erstellt man neue Instanzen eines verpackten Vektors in Rust?
- 29. Kann ich Module "seitlich" in Rust einbauen?
- 30. Wie kann ich einen Rust-Prozess abbrechen?
[Wo ist Ihr Versuch oder sogar Forschung?] (Http://meta.stackoverflow.com/q/261592/155423) – Shepmaster
@Shempmaster, Messepunkt, in der Tat fragte ich mit der Absicht, meine eigene Antwort zu schreiben (noch geplant), Es ist ähnlich zu dieser Frage, die mehrere nützliche Antworten hat - http://StackOverflow.com/Questions/902761 (Ich freue mich, meine eigene Antwort von Python nach Rust zu portieren). – ideasman42
Sie können immer warten, bis Ihre selbst Antwort bereit ist, bevor Sie die nicht-große Frage stellen. – Shepmaster