Repository: SerenityOS/serenity
File: Userland/Libraries/LibGfx/ImageFormats/TIFFWriter.cpp (C++)

Code before:
    entries.append({ TIFF::Tag::RowsPerStrip, { image_height } });
    entries.append({ TIFF::Tag::StripByteCounts, { image_data_size } });
    entries.append({ TIFF::Tag::XResolution, { TIFF::Rational<u32> { 1, 1 } } });
    entries.append({ TIFF::Tag::YResolution, { TIFF::Rational<u32> { 1, 1 } } });
    entries.append({ TIFF::Tag::ResolutionUnit, { static_cast<u32>(TIFF::ResolutionUnit::NoAbsolute) } });

    // "The entries in an IFD must be sorted in ascending order by Tag."
    for (size_t i = 1; i < entries.size(); ++i)
        VERIFY(entries[i - 1].tag < entries[i].tag);

    // Compute sizes.
    u32 size_of_ifd = 0;
    u32 size_of_ifd_entry_data_area = 0;
    size_of_ifd += 2; // u16 number of entries
    for (auto const& entry : entries) {
        size_of_ifd += 2; // u16 tag
        size_of_ifd += 2; // u16 type
        size_of_ifd += 4; // u32 count
        size_of_ifd += 4; // u32 value or offset

        auto type = type_for_ifd_entry(entry);
        if (entry.value.size() * TIFF::size_of_type(type) > 4)
            size_of_ifd_entry_data_area += entry.value.size() * TIFF::size_of_type(type);
    }
    size_of_ifd += 4; // u32 offset to next IFD

    // Update entries that need offsets.
    auto strip_offsets = entries.find_if([](auto& entry) {
        return entry.tag == TIFF::Tag::StripOffsets;
    });
    strip_offsets->value[0] = ifd_offset + size_of_ifd + size_of_ifd_entry_data_area;

    // Finally, write the IFD.
    TRY(stream.write_value<LittleEndian<u16>>(entries.size()));
    AllocatingMemoryStream value_data_stream;
    for (auto const& entry : entries) {
        auto type = type_for_ifd_entry(entry);

        TRY(stream.write_value<LittleEndian<u16>>(to_underlying(entry.tag)));
        TRY(stream.write_value<LittleEndian<u16>>(to_underlying(type)));
        TRY(stream.write_value<LittleEndian<u32>>(entry.value.size()));

        auto data_size = entry.value.size() * TIFF::size_of_type(type);
        if (data_size <= 4) {
            TRY(encode_ifd_entry_value_data(stream, entry));
            for (u32 i = data_size; i < 4; ++i)
                TRY(stream.write_value<u8>(0));
        } else {
            u32 offset = ifd_offset + size_of_ifd + value_data_stream.used_buffer_size();
            TRY(stream.write_value<LittleEndian<u32>>(offset));
            TRY(encode_ifd_entry_value_data(value_data_stream, entry));

Review comment (suggestion):
I'm pretty sure these three are not necessary in practice. If anything, I bet that they can cause more harm than good (like image viewers assuming an image with square dimensions).

Overall, that's not a big deal, so do as you prefer.

Code after:
    // SamplesPerPixel            277  115  SHORT           3 or more
    // RowsPerStrip               278  116  SHORT or LONG
    // StripByteCounts            279  117  LONG or SHORT
    // XResolution                282  11A  RATIONAL
    // YResolution                283  11B  RATIONAL
    // ResolutionUnit             296  128  SHORT           1, 2 or 3"

    Vector<IFDEntry> entries;
    entries.append({ TIFF::Tag::ImageWidth, { image_width } });
    entries.append({ TIFF::Tag::ImageLength, { image_height } });
    if (include_alpha)
        entries.append({ TIFF::Tag::BitsPerSample, { 8u, 8u, 8u, 8u } });
    else
        entries.append({ TIFF::Tag::BitsPerSample, { 8u, 8u, 8u } });
    entries.append({ TIFF::Tag::Compression, { static_cast<u32>(TIFF::Compression::NoCompression) } });
    entries.append({ TIFF::Tag::PhotometricInterpretation, { static_cast<u32>(TIFF::PhotometricInterpretation::RGB) } });
    entries.append({ TIFF::Tag::StripOffsets, { 0u } });
    if (include_alpha)
        entries.append({ TIFF::Tag::SamplesPerPixel, { 4u } });
    else
        entries.append({ TIFF::Tag::SamplesPerPixel, { 3u } });
    entries.append({ TIFF::Tag::RowsPerStrip, { image_height } });
    entries.append({ TIFF::Tag::StripByteCounts, { image_data_size } });
    entries.append({ TIFF::Tag::XResolution, { TIFF::Rational<u32> { 1, 1 } } });
    entries.append({ TIFF::Tag::YResolution, { TIFF::Rational<u32> { 1, 1 } } });
    entries.append({ TIFF::Tag::ResolutionUnit, { static_cast<u32>(TIFF::ResolutionUnit::NoAbsolute) } });

    if (include_alpha)
        entries.append({ TIFF::Tag::ExtraSamples, { static_cast<u32>(TIFF::ExtraSample::UnassociatedAlpha) } });

    if (icc_data.has_value()) {
        // https://www.color.org/technotes/ICC-Technote-ProfileEmbedding.pdf
        // "An ICC profile is embedded, in its entirety, as a single TIFF field or Image File Directory (IFD) entry in
        // the IFD containing the corresponding image data."
        entries.append({ TIFF::Tag::ICCProfile, { move(icc_data.value()) } });
    }
    return entries;
}

static Vector<IFDEntry> make_cmyk_ifd(u32 image_width, u32 image_height, u32 image_data_size, Optional<ByteBuffer> icc_data)
{
    Vector<IFDEntry> entries;
    entries.append({ TIFF::Tag::ImageWidth, { image_width } });
    entries.append({ TIFF::Tag::ImageLength, { image_height } });
    entries.append({ TIFF::Tag::BitsPerSample, { 8u, 8u, 8u, 8u } });
    entries.append({ TIFF::Tag::Compression, { static_cast<u32>(TIFF::Compression::NoCompression) } });
    entries.append({ TIFF::Tag::PhotometricInterpretation, { static_cast<u32>(TIFF::PhotometricInterpretation::CMYK) } });
    entries.append({ TIFF::Tag::StripOffsets, { 0u } });
    entries.append({ TIFF::Tag::SamplesPerPixel, { 4u } });
    entries.append({ TIFF::Tag::RowsPerStrip, { image_height } });
    entries.append({ TIFF::Tag::StripByteCounts, { image_data_size } });