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