Expand description

Text chunks (tEXt/zTXt/iTXt) structs and functions

The PNG spec optionally allows for embedded text chunks in the file. They may appear either before or after the image data chunks. There are three kinds of text chunks.

  • tEXt: This has a keyword and text field, and is ISO 8859-1 encoded.
  • zTXt: This is semantically the same as tEXt, i.e. it has the same fields and encoding, but the text field is compressed before being written into the PNG file.
  • iTXt: This chunk allows for its text field to be any valid UTF-8, and supports compression of the text field as well.

The ISO 8859-1 encoding technically doesn’t allow any control characters to be used, but in practice these values are encountered anyway. This can either be the extended ISO-8859-1 encoding with control characters or the Windows-1252 encoding. This crate assumes the ISO-8859-1 encoding is used.

Reading text chunks

As a PNG is decoded, any text chunk encountered is appended the Info struct, in the uncompressed_latin1_text, compressed_latin1_text, and the utf8_text fields depending on whether the encountered chunk is tEXt, zTXt, or iTXt.

use std::fs::File;
use std::iter::FromIterator;
use std::path::PathBuf;

// Opening a png file that has a zTXt chunk
let decoder = png::Decoder::new(
    File::open(PathBuf::from_iter([
        "tests",
        "text_chunk_examples",
        "ztxt_example.png",
    ]))
    .unwrap(),
);
let mut reader = decoder.read_info().unwrap();
// If the text chunk is before the image data frames, `reader.info()` already contains the text.
for text_chunk in &reader.info().compressed_latin1_text {
    println!("{:?}", text_chunk.keyword); // Prints the keyword
    println!("{:#?}", text_chunk); // Prints out the text chunk.
    // To get the uncompressed text, use the `get_text` method.
    println!("{}", text_chunk.get_text().unwrap());
}

Writing text chunks

There are two ways to write text chunks: the first is to add the appropriate text structs directly to the encoder header before the header is written to file. To add a text chunk at any point in the stream, use the write_text_chunk method.

let mut encoder = png::Encoder::new(w, 2, 1); // Width is 2 pixels and height is 1.
encoder.set_color(png::ColorType::Rgba);
encoder.set_depth(png::BitDepth::Eight);
// Adding text chunks to the header
encoder
   .add_text_chunk(
       "Testing tEXt".to_string(),
       "This is a tEXt chunk that will appear before the IDAT chunks.".to_string(),
   )
   .unwrap();
encoder
    .add_ztxt_chunk(
        "Testing zTXt".to_string(),
        "This is a zTXt chunk that is compressed in the png file.".to_string(),
    )
    .unwrap();
encoder
    .add_itxt_chunk(
        "Testing iTXt".to_string(),
        "iTXt chunks support all of UTF8. Example: हिंदी.".to_string(),
    )
    .unwrap();

let mut writer = encoder.write_header().unwrap();

let data = [255, 0, 0, 255, 0, 0, 0, 255]; // An array containing a RGBA sequence. First pixel is red and second pixel is black.
writer.write_image_data(&data).unwrap(); // Save

// We can add a tEXt/zTXt/iTXt at any point before the encoder is dropped from scope. These chunks will be at the end of the png file.
let tail_ztxt_chunk = ZTXtChunk::new("Comment".to_string(), "A zTXt chunk after the image data.".to_string());
writer.write_text_chunk(&tail_ztxt_chunk).unwrap();

// The fields of the text chunk are public, so they can be mutated before being written to the file.
let mut tail_itxt_chunk = ITXtChunk::new("Author".to_string(), "सायंतन खान".to_string());
tail_itxt_chunk.compressed = true;
tail_itxt_chunk.language_tag = "hi".to_string();
tail_itxt_chunk.translated_keyword = "लेखक".to_string();
writer.write_text_chunk(&tail_itxt_chunk).unwrap();

Structs

Struct encoding an iTXt chunk

Struct representing a tEXt chunk

Struct representing a zTXt chunk

Constants

Default decompression limit for compressed text chunks.

Traits

A generalized text chunk trait