PageRenderTime 44ms CodeModel.GetById 14ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 1ms

/resource/image.d

http://github.com/wilkie/djehuty
D | 235 lines | 150 code | 39 blank | 46 comment | 31 complexity | f8a1efaa4de90568d2421ad8ae0db8b8 MD5 | raw file
  1/*
  2 * image.d
  3 *
  4 * This file contains the magic behind Image.
  5 *
  6 * Author: Dave Wilkinson
  7 *
  8 */
  9
 10module resource.image;
 11
 12import core.stream;
 13import core.string;
 14import core.stream;
 15import core.definitions;
 16
 17import graphics.bitmap;
 18import graphics.graphics;
 19
 20import io.file;
 21import io.console;
 22
 23import synch.semaphore;
 24
 25// import the codec information
 26import decoders.image.decoder;
 27import decoders.image.all;
 28
 29// Section: Core/Resources
 30
 31// Description: This class will wrap a DIB view object and load into this view an image file
 32//   as long as it has a decoder.  So far, I have BMP, PNG, and GIF (animated as well).  Animated
 33//   Images are supported, but you will have to load them a frame at a time.
 34class Image {
 35	this() {
 36		//_loaded = new Semaphore();
 37		//_loaded.init(1);
 38	}
 39
 40	this(string filename) {
 41		load(filename);
 42	}
 43
 44	// Description: Will load the image.  It will throw the file to all the available decoders
 45	//   with a preference to the ones that match the file extension.  When the decoder accepts
 46	//   the file, it will return true, otherwise on error it will return false.
 47	// filename: The filename to open as an image.
 48	// Returns: Will return true when the file is accepted and the image is loaded.
 49	bool load(string filename) {
 50		File f = File.open(filename);
 51
 52		if (f is null) {
 53			return false;
 54		}
 55
 56		return _stream(f) == StreamData.Accepted;
 57	}
 58
 59	// Description: Will load the image from a valid stream.  Use this to open an image from within
 60	//   a file or from a network socket.  The decoders support progressive images already and are
 61	//   developed with this in mind.  You do not need to send a complete stream as images can be
 62	//   rendered by chunks.  The function will return information on the stream's acceptance.
 63	// stream: The stream to read as an image.
 64	// Returns: Describes the current state of the stream decoding.  If it is StreamData.Invalid,
 65	//   then the stream cannot be decoded.  If it is StreamData.Required, then more data is required
 66	//   to render the stream, and only a partial image is available.  If it is StreamData.Accepted,
 67	//   then the stream has been decoded successfully and the image is available.
 68	StreamData load(Stream stream) {
 69		return _stream(stream);
 70	}
 71
 72	// Description: Will return the width of the loaded image.
 73	// Returns: The width of the image.
 74	uint width() {
 75		return _view.width;
 76	}
 77
 78	// Description: Will return the height of the loaded image.
 79	// Returns: The height of the image.
 80	uint height() {
 81		return _view.height;
 82	}
 83
 84	// Description: This function will return the view object associated with this image.
 85	// Returns: The view that can be manipulated.
 86	Bitmap view() {
 87		return _view;
 88	}
 89
 90	// Description: This function will return the currently used ImageDecoder, if available.
 91	// Returns: The ImageDecoder being used.
 92	ImageDecoder codec() {
 93		return _curCodec;
 94	}
 95
 96	uint numFrames() {
 97		if (!_hasFrames) {
 98			return 1;
 99		}
100		return _frameCount;
101	}
102
103	uint frame() {
104		if (!_hasFrames) {
105			return 0;
106		}
107		return _frameIdx;
108	}
109
110	void frame(uint value) {
111		if (!_hasFrames) {
112			return;
113		}
114
115		if (value > this.numFrames) {
116			if (this.numFrames == 0) {
117				value = 0;
118			}
119			else {
120				value = this.numFrames - 1;
121			}
122		}
123		_frameIdx = value;
124		_view = _frames[_frameIdx];
125		_frameDesc = _frameDescs[_frameIdx];
126	}
127
128	ImageFrameDescription frameDescription() {
129		return _frameDesc;
130	}
131
132	void next() {
133		uint lastFrame = _frameIdx;
134		_frameIdx = (_frameIdx + 1) % this.numFrames;
135		if (lastFrame == _frameIdx) { return; }
136		_frameDesc = _frameDescs[_frameIdx];
137
138		if (_view !is null) {
139			// Update view, if necessary
140			Graphics g = _view.lock;
141			if (_frameDesc.clearFirst) {
142				g.brush = new Brush(_frameDesc.clearColor);
143				g.drawRect(0,0,_view.width,_view.height);
144			}
145			g.drawView(_frameDesc.xoffset, _frameDesc.yoffset, _frames[_frameIdx]);
146			g.drawView(_frameDesc.xoffset, _frameDesc.yoffset, _frames[_frameIdx]);
147			_view.unlock;
148		}
149		else {
150			_view = _frames[_frameIdx];
151		}
152	}
153
154protected:
155
156	Bitmap _view;
157	ImageFrameDescription _frameDesc;
158
159	ImageDecoder _curCodec;
160
161	// Information about the frames
162	uint _frameCount;
163	uint _frameIdx;
164
165	// Whether or not this image has frames
166	bool _hasFrames;
167	ImageFrameDescription[] _frameDescs;
168	Bitmap[] _frames;
169
170	Bitmap _curView;
171	ImageFrameDescription _curFrameDesc;
172
173	//Semaphore _loaded;
174
175	StreamData _stream(Stream stream) {
176		StreamData ret = StreamData.Invalid;
177
178		if (_curView is null) {
179			_curView = new Bitmap();
180			_curFrameDesc = ImageFrameDescription.init;
181		}
182
183		if (!_hasFrames) {
184			if (_curCodec is null) {
185				ret = runAllDecoders(_curCodec, stream, _curView);
186			}
187			else {
188				ret = _curCodec.decode(stream, _curView);
189			}
190
191			if (ret == StreamData.Accepted) {
192				// This means the image decoder is indeed the correct choice
193				// and that this image contains multiple frames.
194				_hasFrames = true;		
195			}
196			else if (ret != StreamData.Invalid) {
197				_view = _curView;
198			}
199		}
200
201		if (_hasFrames) {
202			ret = StreamData.Accepted;
203			while(ret == StreamData.Accepted) {
204				if (_curView is null) {
205					_curView = new Bitmap();
206					_curFrameDesc = ImageFrameDescription.init;
207				}
208				ret = _curCodec.decodeFrame(stream, _curView, _curFrameDesc);
209				if (ret == StreamData.Accepted || ret == StreamData.Complete) {
210					// Frame was decoded.
211					_frames ~= _curView;
212					_frameDescs ~= _curFrameDesc;
213					if (_view is null) {
214						_view = new Bitmap(_curView.width, _curView.height);
215						Graphics g = _view.lock();
216						g.drawView(0,0,_curView);
217						_view.unlock();
218					}
219					_curView = null;
220					_frameCount++;
221				}	
222			}
223		}
224
225		return ret;
226	}
227}
228
229void ImageLock(ref Image img) {
230	//img._loaded.down();
231}
232
233void ImageUnlock(ref Image img) {
234	//img._loaded.up();
235}