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 }