1 /* 2 * dimage - png.d 3 * by Laszlo Szeremi 4 * 5 * Copyright under Boost Software License. 6 */ 7 8 module dimage.gif; 9 10 import std.bitmanip; 11 import bitleveld.datatypes; 12 import dimage.base; 13 import dimage.util; 14 15 static import std.stdio; 16 17 /** 18 * Implements reader/writer for *.GIF-files. 19 * Animation is accessed from a sliding window of setting the required frame. 20 * Requires linking against the ncompress library for LZW support. 21 */ 22 version (lzwsupport) { 23 import ncompress42; 24 25 public class GIF : Image, MultiImage { 26 /** 27 * Header for both 87a and 89a versions. 28 */ 29 align(1) public struct Header { 30 char[3] signature = "GIF"; ///Header signature (always GIF) 31 char[3] _version; ///GIF format version ("87a" or "89a") 32 ushort width; ///Image width 33 ushort height; ///Image height 34 union { 35 ubyte packed; ///Screen and color map information 36 mixin bitfields!( 37 ubyte, "sOfGlobalColorTable", 3, 38 bool, "colorTableSort", 1, 39 ubyte, "colorResolution", 3, 40 bool, "globalColorTable", 1, 41 ); 42 } 43 ubyte backgroundColor; ///Background color index 44 ubyte aspectRatio; ///Pixel aspect ratio 45 } 46 /** 47 * Per image descriptor. 48 */ 49 align(1) public struct ImageDescriptor { 50 //ubyte separator = 0x2c; 51 static enum ubyte id = 0x2c;///Image descriptor identifier 52 ushort left; ///X position of image on display 53 ushort top; ///Y position of image on display 54 ushort width; ///Width of the image in pixels 55 ushort height; ///Height of the image in pixels 56 union { 57 ubyte packed; ///Image and color table data information 58 mixin bitfields!( 59 bool, "localColorTable", 1, 60 bool, "interlace", 1, 61 bool, "sort", 1, 62 ubyte, "reserved", 2, 63 ubyte, "sOfLocalColorTable", 3, 64 ); 65 } 66 } 67 static enum ubyte extensionIntroducer = 0x21; ///Extension identifier 68 /** 69 * Extension found in GIF89a versions 70 */ 71 align(1) public struct GraphicsControlExtension { 72 static enum ubyte id = 0xF9; ///Graphics control identifier 73 union { 74 ubyte packed; ///Method of graphics disposal flag 75 mixin bitfields!( 76 bool, "transparentColorFlag", 1, 77 bool, "userInputFlag", 1, 78 ubyte, "disposalMethod", 3, 79 ubyte, "reserved", 3, 80 ); 81 ushort delayTime; ///Hundredth of seconds to wait 82 ubyte colorIndex; ///Transparent color index 83 ubyte terminator; ///Always zero 84 } 85 } 86 /** 87 * Plain text extension of GIF89a 88 */ 89 public class PlainTextExtension { 90 static enum ubyte id = 0x01; ///Plain text extension identifier 91 ///Header of this extension 92 align(1) public struct Header { 93 ushort textGridLeft; ///X position of text grid in pixels 94 ushort textGridTop; ///Y position of text grid in pixels 95 ushort textGridWidth; ///Width of the text grid in pixels 96 ushort textGridHeight; ///Height of the text grid in pixels 97 ubyte cellWidth; ///Width of a grid cell in pixels 98 ubyte cellHeight; ///Height of a grid cell in pixels 99 ubyte textFgColorIndex; ///Text foreground color index value 100 ubyte textBgColorIndex; ///Text background color index value 101 } 102 Header header; ///The header of this block 103 string[] plainTextData; ///Contains all individual text blocks that were found in the file 104 } 105 /** 106 * Application extension block 107 */ 108 public class ApplicationExtension { 109 static enum ubyte id = 0xFF; ///Application extension label 110 ///Header of this extension 111 align(1) public struct Header { 112 char[8] identifier; ///Application identifier 113 ubyte[3] authenticationCode; ///Authentication code 114 } 115 Header header; ///The header of this block 116 ubyte[] data; ///The data contained in this block 117 } 118 protected Header header; 119 protected ImageDescriptor[] imageDescriptors; 120 protected ubyte[] frames; 121 /** 122 * Empty constructor used by the loader 123 */ 124 protected this() { 125 126 } 127 /** 128 * Loads a *.gif file from a file 129 */ 130 public static load(F = std.stdio.File)(F file) { 131 ubyte[] buffer, secBuf; 132 GIF result; 133 buffer.length = Header.sizeof; 134 secBuf.length = 1; 135 buffer = file.rawRead(buffer); 136 if (buffer.length == Header.sizeof) { 137 result.header = reinterpretGet!Header(buffer); 138 } else { 139 throw new ImageFileException("File is not a GIF file or corrupted!"); 140 } 141 //Initialize LZW decompression 142 int lzwStreamReader (ubyte* bytes, size_t numBytes, void* rwCtxt) { 143 file.rawRead(secBuf); 144 buffer.length = secBuf[0]; 145 buffer = file.rawRead(buffer); 146 } 147 148 return result; 149 } 150 } 151 }