AviExporter::AviExporter(const String& fileName, Vec2i size, int fps) : m_file (fileName, File::Create), m_size (size), m_frame (size, ImageFormat::R8_G8_B8), m_fps (fps) { FW_ASSERT(size.min() > 0 && fps > 0); m_lineBytes = (m_size.x * 3 + 3) & -4; m_frameBytes = m_lineBytes * m_size.y; m_numFrames = 0; writeHeader(); }
void FW::exportTiffImage(OutputStream& stream, const Image* image) { // Select format and convert. // - RGBA and floats are not well-supported. // - PackBits compression does not make sense for RGB data. FW_ASSERT(image); Vec2i size = image->getSize(); bool empty = (size.min() <= 0); const Image* source = image; Image* converted = NULL; if (empty || image->getFormat().getID() != ImageFormat::R8_G8_B8 || (int)image->getStride() != size.x * 4) { size = Vec2i(max(size.x, 1), max(size.y, 1)); converted = new Image(size, ImageFormat::R8_G8_B8); if (empty) converted->clear(); else *converted = *image; source = converted; } int numBytes = (int)source->getStride() * size.y; // Write. stream.writeU8('I'); // 0x00: endianess tag stream.writeU8('I'); // 0x01: (little-endian) stream.writeU16LE(42); // 0x02: format identifier stream.writeU32LE(0x08); // 0x04: IFD offset stream.writeU16LE(12); // 0x08: number of IFD entries stream.writeU16LE(256); // 0x0A: Tag = ImageWidth stream.writeU16LE(4); // 0x0C: Type = LONG stream.writeU32LE(1); // 0x0E: Count stream.writeU32LE(size.x); // 0x12: Value stream.writeU16LE(257); // 0x16: Tag = ImageLength stream.writeU16LE(4); // 0x18: Type = LONG stream.writeU32LE(1); // 0x1A: Count stream.writeU32LE(size.y); // 0x1E: Value stream.writeU16LE(258); // 0x22: Tag = BitsPerSample stream.writeU16LE(3); // 0x24: Type = SHORT stream.writeU32LE(3); // 0x26: Count stream.writeU32LE(0x9E); // 0x2A: Value offset stream.writeU16LE(259); // 0x2E: Tag = Compression stream.writeU16LE(3); // 0x30: Type = SHORT stream.writeU32LE(1); // 0x32: Count stream.writeU32LE(1); // 0x36: Value = No compression stream.writeU16LE(262); // 0x3A: Tag = PhotometricInterpretation stream.writeU16LE(3); // 0x3C: Type = SHORT stream.writeU32LE(1); // 0x3E: Count stream.writeU32LE(2); // 0x42: Value = RGB stream.writeU16LE(273); // 0x46: Tag = StripOffsets stream.writeU16LE(4); // 0x48: Type = LONG stream.writeU32LE(1); // 0x4A: Count stream.writeU32LE(0xAC); // 0x4E: Value stream.writeU16LE(277); // 0x52: Tag = SamplesPerPixel stream.writeU16LE(3); // 0x54: Type = SHORT stream.writeU32LE(1); // 0x56: Count stream.writeU32LE(3); // 0x5A: Value stream.writeU16LE(278); // 0x5E: Tag = RowsPerStrip stream.writeU16LE(4); // 0x60: Type = LONG stream.writeU32LE(1); // 0x62: Count stream.writeU32LE(size.y); // 0x66: Value stream.writeU16LE(279); // 0x6A: Tag = StripByteCounts stream.writeU16LE(4); // 0x6C: Type = LONG stream.writeU32LE(1); // 0x6E: Count stream.writeU32LE(numBytes); // 0x72: Value stream.writeU16LE(282); // 0x76: Tag = XResolution stream.writeU16LE(5); // 0x78: Type = RATIONAL stream.writeU32LE(1); // 0x7A: Count stream.writeU32LE(0xA4); // 0x7E: Value offset stream.writeU16LE(283); // 0x82: Tag = YResolution stream.writeU16LE(5); // 0x84: Type = RATIONAL stream.writeU32LE(1); // 0x86: Count stream.writeU32LE(0xA4); // 0x8A: Value offset stream.writeU16LE(296); // 0x8E: Tag = ResolutionUnit stream.writeU16LE(3); // 0x90: Type = SHORT stream.writeU32LE(1); // 0x92: Count stream.writeU32LE(2); // 0x96: Value = Inch stream.writeU32LE(0); // 0x9A: next IFD offset stream.writeU16LE(8); // 0x9E: BitsPerSample[0] stream.writeU16LE(8); // 0xA0: BitsPerSample[1] stream.writeU16LE(8); // 0xA2: BitsPerSample[2] stream.writeU32LE(72); // 0xA4: Resolution numerator stream.writeU32LE(1); // 0xA8: Resolution denominator stream.write(source->getPtr(), numBytes); // 0xAC: image data // Clean up. delete converted; }