1 jls.loader.provide('jls.util.Image');
  2 
  3 jls.loader.requireLibrary('jls_jpeg');
  4 
  5 jls.loader.require('jls.io.File');
  6 jls.loader.require('jls.io.FileChannel');
  7 
  8 jls.util.Image = jls.lang.Class.create( /** @lends jls.util.Image.prototype */
  9 {
 10     /**
 11      * Creates an image.
 12      *
 13      * @param {Number} width The image width.
 14      * @param {Number} height The image height.
 15      * @param {Number} [mode] The image mode.
 16      * @constructs
 17      * @class This class represents an image
 18      */
 19     initialize : function(width, height, mode) {
 20         this._width = width;
 21         this._height = height;
 22         this._bitPerPixel = 24;
 23         this._bytePerPixel = 3;
 24         this._rowLength = (this._width * this._bitPerPixel) / 8;
 25         if (this._rowLength % 4 != 0) {
 26             this._rowLength = this._rowLength + 4 - this._rowLength % 4;
 27         }
 28         this._size = this._rowLength * this._height;
 29         this._buffer = jls.lang.ByteBuffer.allocate(this._size);
 30         mode = mode || 0;
 31         this._mode = mode;
 32     },
 33     /**
 34      * Returns the image width.
 35      * 
 36      * @returns {Number} The image width.
 37      */
 38     getWidth : function() {
 39         return this._width;
 40     },
 41     /**
 42      * Returns the image height.
 43      * 
 44      * @returns {Number} The image height.
 45      */
 46     getHeight : function() {
 47         return this._height;
 48     },
 49     /**
 50      * Returns the image buffer.
 51      * 
 52      * @returns {jls.lang.Buffer} The image buffer.
 53      */
 54     getBuffer : function() {
 55         return this._buffer;
 56     },
 57     _moveTo : function(x, y) {
 58         var offset = this._rowLength * y + this._bytePerPixel * x;
 59         this._buffer.setPosition(offset);
 60         return this;
 61     },
 62     /**
 63      * Returns a pixel value.
 64      * 
 65      * @param {Number} x The x coordinate of the pixel.
 66      * @param {Number} y The y coordinate of the pixel.
 67      * @returns {Array} The pixel value.
 68      */
 69     getPixel : function(x, y) {
 70         this._moveTo(x, y);
 71         var p = [];
 72         p.push(this._buffer.getByte());
 73         p.push(this._buffer.getByte());
 74         p.push(this._buffer.getByte());
 75         return p;
 76     },
 77     /**
 78      * Sets a pixel.
 79      * 
 80      * @param {Number} x The x coordinate of the pixel.
 81      * @param {Number} y The y coordinate of the pixel.
 82      * @param {Number} r The red value to set.
 83      * @param {Number} g The green value to set.
 84      * @param {Number} b The blue value to set.
 85      */
 86     setPixel : function(x, y, r, g, b) {
 87         this._moveTo(x, y);
 88         this._buffer.putByte(r);
 89         this._buffer.putByte(g);
 90         this._buffer.putByte(b);
 91         return this;
 92     }
 93 });
 94 
 95 /*
 96 typedef struct tagBITMAPFILEHEADER {
 97   WORD  bfType; 2
 98   DWORD bfSize; 4
 99   WORD  bfReserved1; 2
100   WORD  bfReserved2; 2
101   DWORD bfOffBits; 4
102 } BITMAPFILEHEADER, *PBITMAPFILEHEADER; = 14
103 
104 typedef struct tagBITMAPCOREHEADER {
105   DWORD bcSize;
106   WORD  bcWidth;
107   WORD  bcHeight;
108   WORD  bcPlanes;
109   WORD  bcBitCount;
110 } BITMAPCOREHEADER, *PBITMAPCOREHEADER; = 12
111 
112 typedef struct tagBITMAPINFOHEADER {
113   DWORD biSize;
114   LONG  biWidth;
115   LONG  biHeight;
116   WORD  biPlanes;
117   WORD  biBitCount;
118   DWORD biCompression;
119   DWORD biSizeImage;
120   LONG  biXPelsPerMeter;
121   LONG  biYPelsPerMeter;
122   DWORD biClrUsed;
123   DWORD biClrImportant;
124 } BITMAPINFOHEADER, *PBITMAPINFOHEADER; = 9*4 + 2*2 = 40
125 */
126 
127 Object.extend(jls.util.Image, /** @lends jls.util.Image */
128 {
129     /**
130      * Reads a BMP.
131      * 
132      * @param {jls.io.FileInputStream} input The input to read the image.
133      * @returns {jls.util.Image} The image.
134      */
135     readBMP : function(input) {
136         /*var dumpObj = function(obj) {
137             for (var key in obj) {
138                 if (typeof obj[key] == 'function') continue;
139                 jls.logger.debug('obj.' + key + ': ' + obj[key]);
140             }
141         };*/
142         /*var dumpNum = function(num) {
143             jls.logger.debug('num: ' + num + ' (0x' + num.toString(16) + ')');
144         };*/
145         var buffer = jls.lang.ByteBuffer.allocate(1024);
146         buffer.setByteOrder(jls.lang.Buffer.LITTLE_ENDIAN);
147         
148         buffer.clear();
149         buffer.setLimit(14);
150         input.read(buffer);
151         buffer.flip();
152         //var typeStr = buffer.getString(2);
153         //jls.logger.debug('type: "' + typeStr + '"');
154         var typeStr = buffer.getShort();
155         var size = buffer.getInt(true);
156         //dumpNum(size);
157         buffer.incrementPosition(4);
158         var offBits = buffer.getInt(true);
159         //dumpNum(offBits);
160 
161         buffer.clear();
162         buffer.setLimit(offBits - 14);
163         input.read(buffer);
164         buffer.flip();
165         
166         var sSize = buffer.getInt(true);
167         //dumpNum(sSize);
168         var width, height, planes, bitCount;
169         if (sSize == 12) {
170             width = buffer.getShort(true);
171             height = buffer.getShort(true);
172             planes = buffer.getShort(true);
173             bitCount = buffer.getShort(true);
174         } else if (sSize == 40) {
175             width = buffer.getInt(true);
176             height = buffer.getInt(true);
177             planes = buffer.getShort(true);
178             bitCount = buffer.getShort(true);
179         } else {
180             throw 'Invalid BMP (' + sSize + ')';
181         }
182         jls.logger.debug('BMP: ' + width + ', ' + height + ', ' + planes + ', ' + bitCount);
183         var img = new jls.util.Image(width, height);
184         input.read(img.getBuffer());
185         return img;
186     },
187     /**
188      * Reads a JPEG.
189      * 
190      * @param {jls.io.FileInputStream} input The input to read the image.
191      * @returns {jls.util.Image} The image.
192      */
193     readJPEG : function(input) {
194         var jdecompressor = new _native.jpeg.JpegDecompressor();
195         var buffer = jls.lang.ByteBuffer.allocate(40000);
196         /** @ignore */
197         var srcMgr = {
198             sourceBuffer : buffer,
199             sourceByteArray : buffer._barray,
200             sourceCapacity : buffer.capacity(),
201             sourceOffset : 0,
202             initSource : function() {
203                 jls.logger.debug('initSource()');
204             },
205             fillSource : function() {
206                 jls.logger.debug('fillSource()');
207                 //this.sourceCapacity = file.read(this.sourceByteArray, this.sourceOffset, this.sourceByteArray.size() - this.sourceOffset);
208                 this.sourceBuffer.clear();
209                 this.sourceBuffer.setPosition(this.sourceOffset);
210                 jls.logger.debug('sourceOffset: ' + this.sourceOffset);
211                 //this.sourceBuffer.setLimit(this.sourceBuffer.capacity());
212                 this.sourceCapacity = input.read(this.sourceBuffer);
213                 jls.logger.debug('sourceCapacity: ' + this.sourceCapacity);
214             },
215             skipSource : function(count) {
216                 jls.logger.debug('skipSource(' + count + ')');
217                 // TODO
218             },
219             termSource : function() {
220                 jls.logger.debug('termSource()');
221             }
222         };
223         jdecompressor.start(srcMgr);
224         var width = jdecompressor.getWidth();
225         var height = jdecompressor.getHeight();
226         var components = jdecompressor.getComponents();
227         jls.logger.debug('JPEG: ' + width + ', ' + height + ', ' + components);
228         var img = new jls.util.Image(width, height);
229         jdecompressor.read(img.getBuffer()._barray, -1);
230         jdecompressor.finish();
231         _native.jpeg.swapRGB(img.getBuffer()._barray, width, height);
232         return img;
233     }
234 });
235 
236