Roo/bootstrap/UploadCropbox.js
[roojs1] / Roo / bootstrap / UploadCropbox.js
1
2 /*
3 * Licence: LGPL
4 */
5
6 /**
7  * @class Roo.bootstrap.UploadCropbox
8  * @extends Roo.bootstrap.Component
9  * Bootstrap UploadCropbox class
10  * @cfg {String} emptyText show when image has been loaded
11  * @cfg {String} rotateNotify show when image too small to rotate
12  * @cfg {Number} errorTimeout default 3000
13  * @cfg {Number} minWidth default 300
14  * @cfg {Number} minHeight default 300
15  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
16  * @cfg {Boolean} isDocument (true|false) default false
17  * 
18  * @constructor
19  * Create a new UploadCropbox
20  * @param {Object} config The config object
21  */
22
23 Roo.bootstrap.UploadCropbox = function(config){
24     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
25     
26     this.addEvents({
27         /**
28          * @event beforeselectfile
29          * Fire before select file
30          * @param {Roo.bootstrap.UploadCropbox} this
31          */
32         "beforeselectfile" : true,
33         /**
34          * @event initial
35          * Fire after initEvent
36          * @param {Roo.bootstrap.UploadCropbox} this
37          */
38         "initial" : true,
39         /**
40          * @event crop
41          * Fire after initEvent
42          * @param {Roo.bootstrap.UploadCropbox} this
43          * @param {String} data
44          */
45         "crop" : true,
46         /**
47          * @event prepare
48          * Fire when preparing the file data
49          * @param {Roo.bootstrap.UploadCropbox} this
50          * @param {Object} file
51          */
52         "prepare" : true,
53         /**
54          * @event exception
55          * Fire when get exception
56          * @param {Roo.bootstrap.UploadCropbox} this
57          * @param {Object} options
58          */
59         "exception" : true,
60         /**
61          * @event beforeloadcanvas
62          * Fire before load the canvas
63          * @param {Roo.bootstrap.UploadCropbox} this
64          * @param {String} src
65          */
66         "beforeloadcanvas" : true,
67         /**
68          * @event trash
69          * Fire when trash image
70          * @param {Roo.bootstrap.UploadCropbox} this
71          */
72         "trash" : true,
73         /**
74          * @event download
75          * Fire when download the image
76          * @param {Roo.bootstrap.UploadCropbox} this
77          */
78         "download" : true,
79         /**
80          * @event footerbuttonclick
81          * Fire when footerbuttonclick
82          * @param {Roo.bootstrap.UploadCropbox} this
83          * @param {String} type
84          */
85         "footerbuttonclick" : true,
86         /**
87          * @event resize
88          * Fire when resize
89          * @param {Roo.bootstrap.UploadCropbox} this
90          */
91         "resize" : true,
92         /**
93          * @event rotate
94          * Fire when rotate the image
95          * @param {Roo.bootstrap.UploadCropbox} this
96          * @param {String} pos
97          */
98         "rotate" : true
99     });
100     
101     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
102 };
103
104 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
105     
106     emptyText : 'Click to upload image',
107     rotateNotify : 'Image is too small to rotate',
108     errorTimeout : 3000,
109     scale : 0,
110     baseScale : 1,
111     rotate : 0,
112     dragable : false,
113     pinching : false,
114     mouseX : 0,
115     mouseY : 0,
116     cropData : false,
117     minWidth : 300,
118     minHeight : 300,
119     file : false,
120     exif : {},
121     baseRotate : 1,
122     cropType : 'image/jpeg',
123     buttons : false,
124     canvasLoaded : false,
125     isDocument : false,
126     
127     getAutoCreate : function()
128     {
129         var cfg = {
130             tag : 'div',
131             cls : 'roo-upload-cropbox',
132             cn : [
133                 {
134                     tag : 'div',
135                     cls : 'roo-upload-cropbox-body',
136                     style : 'cursor:pointer',
137                     cn : [
138                         {
139                             tag : 'div',
140                             cls : 'roo-upload-cropbox-preview'
141                         },
142                         {
143                             tag : 'div',
144                             cls : 'roo-upload-cropbox-thumb'
145                         },
146                         {
147                             tag : 'div',
148                             cls : 'roo-upload-cropbox-empty-notify',
149                             html : this.emptyText
150                         },
151                         {
152                             tag : 'div',
153                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
154                             html : this.rotateNotify
155                         }
156                     ]
157                 },
158                 {
159                     tag : 'div',
160                     cls : 'roo-upload-cropbox-footer',
161                     cn : {
162                         tag : 'div',
163                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
164                         cn : []
165                     }
166                 }
167             ]
168         };
169         
170         return cfg;
171     },
172     
173     onRender : function(ct, position)
174     {
175         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
176         
177         if (this.buttons.length) {
178             
179             Roo.each(this.buttons, function(bb) {
180                 
181                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
182                 
183                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
184                 
185             }, this);
186         }
187     },
188     
189     initEvents : function()
190     {
191         this.urlAPI = (window.createObjectURL && window) || 
192                                 (window.URL && URL.revokeObjectURL && URL) || 
193                                 (window.webkitURL && webkitURL);
194                         
195         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
196         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
197         
198         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
199         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
200         
201         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
202         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
203         this.thumbEl.hide();
204         
205         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
206         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
207         
208         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
209         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
210         this.errorEl.hide();
211         
212         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
213         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
214         this.footerEl.hide();
215         
216         this.setThumbBoxSize();
217         
218         this.bind();
219         
220         this.resize();
221         
222         this.fireEvent('initial', this);
223     },
224
225     bind : function()
226     {
227         var _this = this;
228         
229         window.addEventListener("resize", function() { _this.resize(); } );
230         
231         this.bodyEl.on('click', this.beforeSelectFile, this);
232         
233         if(Roo.isTouch){
234             this.bodyEl.on('touchstart', this.onTouchStart, this);
235             this.bodyEl.on('touchmove', this.onTouchMove, this);
236             this.bodyEl.on('touchend', this.onTouchEnd, this);
237         }
238         
239         if(!Roo.isTouch){
240             this.bodyEl.on('mousedown', this.onMouseDown, this);
241             this.bodyEl.on('mousemove', this.onMouseMove, this);
242             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
243             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
244             Roo.get(document).on('mouseup', this.onMouseUp, this);
245         }
246     },
247     
248     reset : function()
249     {    
250         this.scale = 0;
251         this.baseScale = 1;
252         this.rotate = 0;
253         this.baseRotate = 1;
254         this.dragable = false;
255         this.pinching = false;
256         this.mouseX = 0;
257         this.mouseY = 0;
258         this.cropData = false;
259         this.notifyEl.dom.innerHTML = this.emptyText;
260         
261     },
262     
263     resize : function()
264     {
265         if(this.fireEvent('resize', this) != false){
266             this.setThumbBoxPosition();
267             this.setCanvasPosition();
268         }
269     },
270     
271     onFooterButtonClick : function(e, el, o, type)
272     {
273         switch (type) {
274             case 'rotate-left' :
275                 this.onRotateLeft(e);
276                 break;
277             case 'rotate-right' :
278                 this.onRotateRight(e);
279                 break;
280             case 'picture' :
281                 this.beforeSelectFile(e);
282                 break;
283             case 'trash' :
284                 this.trash(e);
285                 break;
286             case 'crop' :
287                 this.crop(e);
288                 break;
289             case 'download' :
290                 this.download(e);
291                 break;
292             default :
293                 break;
294         }
295         
296         this.fireEvent('footerbuttonclick', this, type);
297     },
298     
299     beforeSelectFile : function(e)
300     {
301         this.fireEvent('beforeselectfile', this);
302     },
303     
304     trash : function(e)
305     {
306         this.fireEvent('trash', this);
307     },
308     
309     download : function(e)
310     {
311         this.fireEvent('download', this);
312     },
313     
314     loadCanvas : function(src)
315     {   
316         if(this.fireEvent('beforeloadcanvas', this, src) != false){
317             
318             this.reset();
319             
320             this.imageEl = document.createElement('img');
321             
322             var _this = this;
323             
324             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
325             
326             this.imageEl.src = src;
327         }
328     },
329     
330     onLoadCanvas : function()
331     {   
332         this.bodyEl.un('click', this.beforeSelectFile, this);
333         
334         this.notifyEl.hide();
335         this.thumbEl.show();
336         this.footerEl.show();
337         
338         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
339         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
340         
341         this.baseRotateLevel();
342         
343         if(this.isDocument){
344             this.setThumbBoxSize();
345         }
346         
347         this.setThumbBoxPosition();
348         
349         this.baseScaleLevel();
350         
351         this.draw();
352         
353         this.resize();
354         
355         this.canvasLoaded = true;
356         
357     },
358     
359     setCanvasPosition : function()
360     {   
361         if(!this.canvasEl){
362             return;
363         }
364         
365         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
366         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
367         
368         this.previewEl.setLeft(pw);
369         this.previewEl.setTop(ph);
370         
371     },
372     
373     onMouseDown : function(e)
374     {   
375         e.stopEvent();
376         
377         this.dragable = true;
378         this.pinching = false;
379         
380         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
381             this.dragable = false;
382             return;
383         }
384         
385         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
386         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
387         
388     },
389     
390     onMouseMove : function(e)
391     {   
392         e.stopEvent();
393         
394         if(!this.canvasLoaded){
395             return;
396         }
397         
398         if (!this.dragable){
399             return;
400         }
401         
402         var minX = Math.ceil(this.thumbEl.getLeft(true));
403         var minY = Math.ceil(this.thumbEl.getTop(true));
404         
405         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
406         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
407         
408         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
409         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
410         
411         x = x - this.mouseX;
412         y = y - this.mouseY;
413         
414         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
415         var bgY = Math.ceil(y + this.previewEl.getTop(true));
416         
417         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
418         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
419         
420         this.previewEl.setLeft(bgX);
421         this.previewEl.setTop(bgY);
422         
423         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
424         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
425     },
426     
427     onMouseUp : function(e)
428     {   
429         e.stopEvent();
430         
431         this.dragable = false;
432     },
433     
434     onMouseWheel : function(e)
435     {   
436         e.stopEvent();
437         
438         this.startScale = this.scale;
439         
440         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
441         
442         if(!this.zoomable()){
443             this.scale = this.startScale;
444             return;
445         }
446         
447         this.draw();
448         
449         return;
450     },
451     
452     zoomable : function()
453     {
454         var minScale = this.thumbEl.getWidth() / this.minWidth;
455         
456         if(this.minWidth < this.minHeight){
457             minScale = this.thumbEl.getHeight() / this.minHeight;
458         }
459         
460         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
461         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
462         
463         if(
464                 this.isDocument &&
465                 (this.rotate == 0 || this.rotate == 180) && 
466                 (
467                     width > this.imageEl.OriginWidth || 
468                     height > this.imageEl.OriginHeight ||
469                     (width < this.minWidth && height < this.minHeight)
470                 )
471         ){
472             return false;
473         }
474         
475         if(
476                 this.isDocument &&
477                 (this.rotate == 90 || this.rotate == 270) && 
478                 (
479                     width > this.imageEl.OriginWidth || 
480                     height > this.imageEl.OriginHeight ||
481                     (width < this.minHeight && height < this.minWidth)
482                 )
483         ){
484             return false;
485         }
486         
487         if(
488                 !this.isDocument &&
489                 (this.rotate == 0 || this.rotate == 180) && 
490                 (
491                     width < this.minWidth || 
492                     width > this.imageEl.OriginWidth || 
493                     height < this.minHeight || 
494                     height > this.imageEl.OriginHeight
495                 )
496         ){
497             return false;
498         }
499         
500         if(
501                 !this.isDocument &&
502                 (this.rotate == 90 || this.rotate == 270) && 
503                 (
504                     width < this.minHeight || 
505                     width > this.imageEl.OriginWidth || 
506                     height < this.minWidth || 
507                     height > this.imageEl.OriginHeight
508                 )
509         ){
510             return false;
511         }
512         
513         return true;
514         
515     },
516     
517     onRotateLeft : function(e)
518     {   
519         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
520             
521             var minScale = this.thumbEl.getWidth() / this.minWidth;
522             
523             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
524             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
525             
526             this.startScale = this.scale;
527             
528             while (this.getScaleLevel() < minScale){
529             
530                 this.scale = this.scale + 1;
531                 
532                 if(!this.zoomable()){
533                     break;
534                 }
535                 
536                 if(
537                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
538                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
539                 ){
540                     continue;
541                 }
542                 
543                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
544
545                 this.draw();
546                 
547                 return;
548             }
549             
550             this.scale = this.startScale;
551             
552             this.onRotateFail();
553             
554             return false;
555         }
556         
557         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
558
559         if(this.isDocument){
560             this.setThumbBoxSize();
561             this.setThumbBoxPosition();
562             this.setCanvasPosition();
563         }
564         
565         this.draw();
566         
567         this.fireEvent('rotate', this, 'left');
568         
569     },
570     
571     onRotateRight : function(e)
572     {
573         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
574             
575             var minScale = this.thumbEl.getWidth() / this.minWidth;
576         
577             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
578             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
579             
580             this.startScale = this.scale;
581             
582             while (this.getScaleLevel() < minScale){
583             
584                 this.scale = this.scale + 1;
585                 
586                 if(!this.zoomable()){
587                     break;
588                 }
589                 
590                 if(
591                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
592                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
593                 ){
594                     continue;
595                 }
596                 
597                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
598
599                 this.draw();
600                 
601                 return;
602             }
603             
604             this.scale = this.startScale;
605             
606             this.onRotateFail();
607             
608             return false;
609         }
610         
611         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
612
613         if(this.isDocument){
614             this.setThumbBoxSize();
615             this.setThumbBoxPosition();
616             this.setCanvasPosition();
617         }
618         
619         this.draw();
620         
621         this.fireEvent('rotate', this, 'right');
622     },
623     
624     onRotateFail : function()
625     {
626         this.errorEl.show(true);
627         
628         var _this = this;
629         
630         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
631     },
632     
633     draw : function()
634     {
635         this.previewEl.dom.innerHTML = '';
636         
637         var canvasEl = document.createElement("canvas");
638         
639         var contextEl = canvasEl.getContext("2d");
640         
641         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
642         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
643         var center = this.imageEl.OriginWidth / 2;
644         
645         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
646             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
647             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
648             center = this.imageEl.OriginHeight / 2;
649         }
650         
651         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
652         
653         contextEl.translate(center, center);
654         contextEl.rotate(this.rotate * Math.PI / 180);
655
656         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
657         
658         this.canvasEl = document.createElement("canvas");
659         
660         this.contextEl = this.canvasEl.getContext("2d");
661         
662         switch (this.rotate) {
663             case 0 :
664                 
665                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
666                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
667                 
668                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
669                 
670                 break;
671             case 90 : 
672                 
673                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
674                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
675                 
676                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
677                     this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
678                     break;
679                 }
680                 
681                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
682                 
683                 break;
684             case 180 :
685                 
686                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
687                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
688                 
689                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
690                     this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
691                     break;
692                 }
693                 
694                 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
695                 
696                 break;
697             case 270 :
698                 
699                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
700                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
701         
702                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
703                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
704                     break;
705                 }
706                 
707                 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
708                 
709                 break;
710             default : 
711                 break;
712         }
713         
714         this.previewEl.appendChild(this.canvasEl);
715         
716         this.setCanvasPosition();
717     },
718     
719     crop : function()
720     {
721         if(!this.canvasLoaded){
722             return;
723         }
724         
725         var imageCanvas = document.createElement("canvas");
726         
727         var imageContext = imageCanvas.getContext("2d");
728         
729         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
730         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
731         
732         var center = imageCanvas.width / 2;
733         
734         imageContext.translate(center, center);
735         
736         imageContext.rotate(this.rotate * Math.PI / 180);
737         
738         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
739         
740         var canvas = document.createElement("canvas");
741         
742         var context = canvas.getContext("2d");
743                 
744         canvas.width = this.minWidth;
745         canvas.height = this.minHeight;
746
747         switch (this.rotate) {
748             case 0 :
749                 
750                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
751                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
752                 
753                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
754                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
755                 
756                 var targetWidth = this.minWidth - 2 * x;
757                 var targetHeight = this.minHeight - 2 * y;
758                 
759                 var scale = 1;
760                 
761                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
762                     scale = targetWidth / width;
763                 }
764                 
765                 if(x > 0 && y == 0){
766                     scale = targetHeight / height;
767                 }
768                 
769                 if(x > 0 && y > 0){
770                     scale = targetWidth / width;
771                     
772                     if(width < height){
773                         scale = targetHeight / height;
774                     }
775                 }
776                 
777                 context.scale(scale, scale);
778                 
779                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
780                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
781
782                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
783                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
784
785                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
786                 
787                 break;
788             case 90 : 
789                 
790                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
791                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
792                 
793                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
794                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
795                 
796                 var targetWidth = this.minWidth - 2 * x;
797                 var targetHeight = this.minHeight - 2 * y;
798                 
799                 var scale = 1;
800                 
801                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
802                     scale = targetWidth / width;
803                 }
804                 
805                 if(x > 0 && y == 0){
806                     scale = targetHeight / height;
807                 }
808                 
809                 if(x > 0 && y > 0){
810                     scale = targetWidth / width;
811                     
812                     if(width < height){
813                         scale = targetHeight / height;
814                     }
815                 }
816                 
817                 context.scale(scale, scale);
818                 
819                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
820                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
821
822                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
823                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
824                 
825                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
826                 
827                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
828                 
829                 break;
830             case 180 :
831                 
832                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
833                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
834                 
835                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
836                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
837                 
838                 var targetWidth = this.minWidth - 2 * x;
839                 var targetHeight = this.minHeight - 2 * y;
840                 
841                 var scale = 1;
842                 
843                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
844                     scale = targetWidth / width;
845                 }
846                 
847                 if(x > 0 && y == 0){
848                     scale = targetHeight / height;
849                 }
850                 
851                 if(x > 0 && y > 0){
852                     scale = targetWidth / width;
853                     
854                     if(width < height){
855                         scale = targetHeight / height;
856                     }
857                 }
858                 
859                 context.scale(scale, scale);
860                 
861                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
862                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
863
864                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
865                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
866
867                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
868                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
869                 
870                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
871                 
872                 break;
873             case 270 :
874                 
875                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
876                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
877                 
878                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
879                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
880                 
881                 var targetWidth = this.minWidth - 2 * x;
882                 var targetHeight = this.minHeight - 2 * y;
883                 
884                 var scale = 1;
885                 
886                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
887                     scale = targetWidth / width;
888                 }
889                 
890                 if(x > 0 && y == 0){
891                     scale = targetHeight / height;
892                 }
893                 
894                 if(x > 0 && y > 0){
895                     scale = targetWidth / width;
896                     
897                     if(width < height){
898                         scale = targetHeight / height;
899                     }
900                 }
901                 
902                 context.scale(scale, scale);
903                 
904                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
905                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
906
907                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
908                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
909                 
910                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
911                 
912                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
913                 
914                 break;
915             default : 
916                 break;
917         }
918         
919         this.cropData = canvas.toDataURL(this.cropType);
920         
921         this.fireEvent('crop', this, this.cropData);
922         
923     },
924     
925     setThumbBoxSize : function()
926     {
927         var width, height;
928         
929         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
930             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
931             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
932             
933             this.minWidth = width;
934             this.minHeight = height;
935             
936             if(this.rotate == 90 || this.rotate == 270){
937                 this.minWidth = height;
938                 this.minHeight = width;
939             }
940         }
941         
942         height = 300;
943         width = Math.ceil(this.minWidth * height / this.minHeight);
944         
945         if(this.minWidth > this.minHeight){
946             width = 300;
947             height = Math.ceil(this.minHeight * width / this.minWidth);
948         }
949         
950         this.thumbEl.setStyle({
951             width : width + 'px',
952             height : height + 'px'
953         });
954
955         return;
956             
957     },
958     
959     setThumbBoxPosition : function()
960     {
961         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
962         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
963         
964         this.thumbEl.setLeft(x);
965         this.thumbEl.setTop(y);
966         
967     },
968     
969     baseRotateLevel : function()
970     {
971         this.baseRotate = 1;
972         
973         if(
974                 typeof(this.exif) != 'undefined' &&
975                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
976                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
977         ){
978             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
979         }
980         
981         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
982         
983     },
984     
985     baseScaleLevel : function()
986     {
987         var width, height;
988         
989         if(this.isDocument){
990             
991             if(this.baseRotate == 6 || this.baseRotate == 8){
992             
993                 height = this.thumbEl.getHeight();
994                 this.baseScale = height / this.imageEl.OriginWidth;
995
996                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
997                     width = this.thumbEl.getWidth();
998                     this.baseScale = width / this.imageEl.OriginHeight;
999                 }
1000
1001                 return;
1002             }
1003
1004             height = this.thumbEl.getHeight();
1005             this.baseScale = height / this.imageEl.OriginHeight;
1006
1007             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
1008                 width = this.thumbEl.getWidth();
1009                 this.baseScale = width / this.imageEl.OriginWidth;
1010             }
1011
1012             return;
1013         }
1014         
1015         if(this.baseRotate == 6 || this.baseRotate == 8){
1016             
1017             width = this.thumbEl.getHeight();
1018             this.baseScale = width / this.imageEl.OriginHeight;
1019             
1020             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
1021                 height = this.thumbEl.getWidth();
1022                 this.baseScale = height / this.imageEl.OriginHeight;
1023             }
1024             
1025             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
1026                 height = this.thumbEl.getWidth();
1027                 this.baseScale = height / this.imageEl.OriginHeight;
1028                 
1029                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
1030                     width = this.thumbEl.getHeight();
1031                     this.baseScale = width / this.imageEl.OriginWidth;
1032                 }
1033             }
1034             
1035             return;
1036         }
1037         
1038         width = this.thumbEl.getWidth();
1039         this.baseScale = width / this.imageEl.OriginWidth;
1040         
1041         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
1042             height = this.thumbEl.getHeight();
1043             this.baseScale = height / this.imageEl.OriginHeight;
1044         }
1045         
1046         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
1047             
1048             height = this.thumbEl.getHeight();
1049             this.baseScale = height / this.imageEl.OriginHeight;
1050             
1051             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
1052                 width = this.thumbEl.getWidth();
1053                 this.baseScale = width / this.imageEl.OriginWidth;
1054             }
1055             
1056         }
1057         
1058         return;
1059     },
1060     
1061     getScaleLevel : function()
1062     {
1063         return this.baseScale * Math.pow(1.1, this.scale);
1064     },
1065     
1066     onTouchStart : function(e)
1067     {
1068         if(!this.canvasLoaded){
1069             this.beforeSelectFile(e);
1070             return;
1071         }
1072         
1073         var touches = e.browserEvent.touches;
1074         
1075         if(!touches){
1076             return;
1077         }
1078         
1079         if(touches.length == 1){
1080             this.onMouseDown(e);
1081             return;
1082         }
1083         
1084         if(touches.length != 2){
1085             return;
1086         }
1087         
1088         var coords = [];
1089         
1090         for(var i = 0, finger; finger = touches[i]; i++){
1091             coords.push(finger.pageX, finger.pageY);
1092         }
1093         
1094         var x = Math.pow(coords[0] - coords[2], 2);
1095         var y = Math.pow(coords[1] - coords[3], 2);
1096         
1097         this.startDistance = Math.sqrt(x + y);
1098         
1099         this.startScale = this.scale;
1100         
1101         this.pinching = true;
1102         this.dragable = false;
1103         
1104     },
1105     
1106     onTouchMove : function(e)
1107     {
1108         if(!this.pinching && !this.dragable){
1109             return;
1110         }
1111         
1112         var touches = e.browserEvent.touches;
1113         
1114         if(!touches){
1115             return;
1116         }
1117         
1118         if(this.dragable){
1119             this.onMouseMove(e);
1120             return;
1121         }
1122         
1123         var coords = [];
1124         
1125         for(var i = 0, finger; finger = touches[i]; i++){
1126             coords.push(finger.pageX, finger.pageY);
1127         }
1128         
1129         var x = Math.pow(coords[0] - coords[2], 2);
1130         var y = Math.pow(coords[1] - coords[3], 2);
1131         
1132         this.endDistance = Math.sqrt(x + y);
1133         
1134         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
1135         
1136         if(!this.zoomable()){
1137             this.scale = this.startScale;
1138             return;
1139         }
1140         
1141         this.draw();
1142         
1143     },
1144     
1145     onTouchEnd : function(e)
1146     {
1147         this.pinching = false;
1148         this.dragable = false;
1149         
1150     },
1151     
1152     prepare : function(file)
1153     {   
1154         this.file = false;
1155         this.exif = {};
1156         
1157         if(typeof(file) === 'string'){
1158             this.loadCanvas(file);
1159             return;
1160         }
1161         
1162         if(!file || !this.urlAPI){
1163             return;
1164         }
1165         
1166         this.file = file;
1167         this.cropType = file.type;
1168         
1169         var _this = this;
1170         
1171         if(this.fireEvent('prepare', this, this.file) != false){
1172             
1173             var reader = new FileReader();
1174             
1175             reader.onload = function (e) {
1176                 if (e.target.error) {
1177                     Roo.log(e.target.error);
1178                     return;
1179                 }
1180                 
1181                 Roo.log(e);
1182                 
1183                 var buffer = e.target.result,
1184                     dataView = new DataView(buffer),
1185                     offset = 2,
1186                     maxOffset = dataView.byteLength - 4,
1187                     markerBytes,
1188                     markerLength;
1189                 
1190                 if (dataView.getUint16(0) === 0xffd8) {
1191                     while (offset < maxOffset) {
1192                         markerBytes = dataView.getUint16(offset);
1193                         
1194                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
1195                             markerLength = dataView.getUint16(offset + 2) + 2;
1196                             if (offset + markerLength > dataView.byteLength) {
1197                                 Roo.log('Invalid meta data: Invalid segment size.');
1198                                 break;
1199                             }
1200                             
1201                             if(markerBytes == 0xffe1){
1202                                 _this.parseExifData(
1203                                     dataView,
1204                                     offset,
1205                                     markerLength
1206                                 );
1207                             }
1208                             
1209                             offset += markerLength;
1210                             
1211                             continue;
1212                         }
1213                         
1214                         break;
1215                     }
1216                     
1217                 }
1218                 
1219                 var url = _this.urlAPI.createObjectURL(_this.file);
1220                 
1221                 _this.loadCanvas(url);
1222                 
1223                 return;
1224             }
1225             
1226             reader.readAsArrayBuffer(this.file);
1227             
1228         }
1229         
1230     },
1231     
1232     parseExifData : function(dataView, offset, length)
1233     {
1234         var tiffOffset = offset + 10,
1235             littleEndian,
1236             dirOffset;
1237     
1238         if (dataView.getUint32(offset + 4) !== 0x45786966) {
1239             // No Exif data, might be XMP data instead
1240             return;
1241         }
1242         
1243         // Check for the ASCII code for "Exif" (0x45786966):
1244         if (dataView.getUint32(offset + 4) !== 0x45786966) {
1245             // No Exif data, might be XMP data instead
1246             return;
1247         }
1248         if (tiffOffset + 8 > dataView.byteLength) {
1249             Roo.log('Invalid Exif data: Invalid segment size.');
1250             return;
1251         }
1252         // Check for the two null bytes:
1253         if (dataView.getUint16(offset + 8) !== 0x0000) {
1254             Roo.log('Invalid Exif data: Missing byte alignment offset.');
1255             return;
1256         }
1257         // Check the byte alignment:
1258         switch (dataView.getUint16(tiffOffset)) {
1259         case 0x4949:
1260             littleEndian = true;
1261             break;
1262         case 0x4D4D:
1263             littleEndian = false;
1264             break;
1265         default:
1266             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
1267             return;
1268         }
1269         // Check for the TIFF tag marker (0x002A):
1270         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
1271             Roo.log('Invalid Exif data: Missing TIFF marker.');
1272             return;
1273         }
1274         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
1275         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
1276         
1277         this.parseExifTags(
1278             dataView,
1279             tiffOffset,
1280             tiffOffset + dirOffset,
1281             littleEndian
1282         );
1283     },
1284     
1285     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
1286     {
1287         var tagsNumber,
1288             dirEndOffset,
1289             i;
1290         if (dirOffset + 6 > dataView.byteLength) {
1291             Roo.log('Invalid Exif data: Invalid directory offset.');
1292             return;
1293         }
1294         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
1295         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
1296         if (dirEndOffset + 4 > dataView.byteLength) {
1297             Roo.log('Invalid Exif data: Invalid directory size.');
1298             return;
1299         }
1300         for (i = 0; i < tagsNumber; i += 1) {
1301             this.parseExifTag(
1302                 dataView,
1303                 tiffOffset,
1304                 dirOffset + 2 + 12 * i, // tag offset
1305                 littleEndian
1306             );
1307         }
1308         // Return the offset to the next directory:
1309         return dataView.getUint32(dirEndOffset, littleEndian);
1310     },
1311     
1312     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
1313     {
1314         var tag = dataView.getUint16(offset, littleEndian);
1315         
1316         this.exif[tag] = this.getExifValue(
1317             dataView,
1318             tiffOffset,
1319             offset,
1320             dataView.getUint16(offset + 2, littleEndian), // tag type
1321             dataView.getUint32(offset + 4, littleEndian), // tag length
1322             littleEndian
1323         );
1324     },
1325     
1326     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
1327     {
1328         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
1329             tagSize,
1330             dataOffset,
1331             values,
1332             i,
1333             str,
1334             c;
1335     
1336         if (!tagType) {
1337             Roo.log('Invalid Exif data: Invalid tag type.');
1338             return;
1339         }
1340         
1341         tagSize = tagType.size * length;
1342         // Determine if the value is contained in the dataOffset bytes,
1343         // or if the value at the dataOffset is a pointer to the actual data:
1344         dataOffset = tagSize > 4 ?
1345                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
1346         if (dataOffset + tagSize > dataView.byteLength) {
1347             Roo.log('Invalid Exif data: Invalid data offset.');
1348             return;
1349         }
1350         if (length === 1) {
1351             return tagType.getValue(dataView, dataOffset, littleEndian);
1352         }
1353         values = [];
1354         for (i = 0; i < length; i += 1) {
1355             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
1356         }
1357         
1358         if (tagType.ascii) {
1359             str = '';
1360             // Concatenate the chars:
1361             for (i = 0; i < values.length; i += 1) {
1362                 c = values[i];
1363                 // Ignore the terminating NULL byte(s):
1364                 if (c === '\u0000') {
1365                     break;
1366                 }
1367                 str += c;
1368             }
1369             return str;
1370         }
1371         return values;
1372     }
1373     
1374 });
1375
1376 Roo.apply(Roo.bootstrap.UploadCropbox, {
1377     tags : {
1378         'Orientation': 0x0112
1379     },
1380     
1381     Orientation: {
1382             1: 0, //'top-left',
1383 //            2: 'top-right',
1384             3: 180, //'bottom-right',
1385 //            4: 'bottom-left',
1386 //            5: 'left-top',
1387             6: 90, //'right-top',
1388 //            7: 'right-bottom',
1389             8: 270 //'left-bottom'
1390     },
1391     
1392     exifTagTypes : {
1393         // byte, 8-bit unsigned int:
1394         1: {
1395             getValue: function (dataView, dataOffset) {
1396                 return dataView.getUint8(dataOffset);
1397             },
1398             size: 1
1399         },
1400         // ascii, 8-bit byte:
1401         2: {
1402             getValue: function (dataView, dataOffset) {
1403                 return String.fromCharCode(dataView.getUint8(dataOffset));
1404             },
1405             size: 1,
1406             ascii: true
1407         },
1408         // short, 16 bit int:
1409         3: {
1410             getValue: function (dataView, dataOffset, littleEndian) {
1411                 return dataView.getUint16(dataOffset, littleEndian);
1412             },
1413             size: 2
1414         },
1415         // long, 32 bit int:
1416         4: {
1417             getValue: function (dataView, dataOffset, littleEndian) {
1418                 return dataView.getUint32(dataOffset, littleEndian);
1419             },
1420             size: 4
1421         },
1422         // rational = two long values, first is numerator, second is denominator:
1423         5: {
1424             getValue: function (dataView, dataOffset, littleEndian) {
1425                 return dataView.getUint32(dataOffset, littleEndian) /
1426                     dataView.getUint32(dataOffset + 4, littleEndian);
1427             },
1428             size: 8
1429         },
1430         // slong, 32 bit signed int:
1431         9: {
1432             getValue: function (dataView, dataOffset, littleEndian) {
1433                 return dataView.getInt32(dataOffset, littleEndian);
1434             },
1435             size: 4
1436         },
1437         // srational, two slongs, first is numerator, second is denominator:
1438         10: {
1439             getValue: function (dataView, dataOffset, littleEndian) {
1440                 return dataView.getInt32(dataOffset, littleEndian) /
1441                     dataView.getInt32(dataOffset + 4, littleEndian);
1442             },
1443             size: 8
1444         }
1445     },
1446     
1447     footer : {
1448         STANDARD : [
1449             {
1450                 tag : 'div',
1451                 cls : 'btn-group roo-upload-cropbox-rotate-left',
1452                 action : 'rotate-left',
1453                 cn : [
1454                     {
1455                         tag : 'button',
1456                         cls : 'btn btn-default',
1457                         html : '<i class="fa fa-undo"></i>'
1458                     }
1459                 ]
1460             },
1461             {
1462                 tag : 'div',
1463                 cls : 'btn-group roo-upload-cropbox-picture',
1464                 action : 'picture',
1465                 cn : [
1466                     {
1467                         tag : 'button',
1468                         cls : 'btn btn-default',
1469                         html : '<i class="fa fa-picture-o"></i>'
1470                     }
1471                 ]
1472             },
1473             {
1474                 tag : 'div',
1475                 cls : 'btn-group roo-upload-cropbox-rotate-right',
1476                 action : 'rotate-right',
1477                 cn : [
1478                     {
1479                         tag : 'button',
1480                         cls : 'btn btn-default',
1481                         html : '<i class="fa fa-repeat"></i>'
1482                     }
1483                 ]
1484             }
1485         ],
1486         DOCUMENT : [
1487             {
1488                 tag : 'div',
1489                 cls : 'btn-group roo-upload-cropbox-rotate-left',
1490                 action : 'rotate-left',
1491                 cn : [
1492                     {
1493                         tag : 'button',
1494                         cls : 'btn btn-default',
1495                         html : '<i class="fa fa-undo"></i>'
1496                     }
1497                 ]
1498             },
1499             {
1500                 tag : 'div',
1501                 cls : 'btn-group roo-upload-cropbox-download',
1502                 action : 'download',
1503                 cn : [
1504                     {
1505                         tag : 'button',
1506                         cls : 'btn btn-default',
1507                         html : '<i class="fa fa-download"></i>'
1508                     }
1509                 ]
1510             },
1511             {
1512                 tag : 'div',
1513                 cls : 'btn-group roo-upload-cropbox-crop',
1514                 action : 'crop',
1515                 cn : [
1516                     {
1517                         tag : 'button',
1518                         cls : 'btn btn-default',
1519                         html : '<i class="fa fa-crop"></i>'
1520                     }
1521                 ]
1522             },
1523             {
1524                 tag : 'div',
1525                 cls : 'btn-group roo-upload-cropbox-trash',
1526                 action : 'trash',
1527                 cn : [
1528                     {
1529                         tag : 'button',
1530                         cls : 'btn btn-default',
1531                         html : '<i class="fa fa-trash"></i>'
1532                     }
1533                 ]
1534             },
1535             {
1536                 tag : 'div',
1537                 cls : 'btn-group roo-upload-cropbox-rotate-right',
1538                 action : 'rotate-right',
1539                 cn : [
1540                     {
1541                         tag : 'button',
1542                         cls : 'btn btn-default',
1543                         html : '<i class="fa fa-repeat"></i>'
1544                     }
1545                 ]
1546             }
1547         ],
1548         ROTATOR : [
1549             {
1550                 tag : 'div',
1551                 cls : 'btn-group roo-upload-cropbox-rotate-left',
1552                 action : 'rotate-left',
1553                 cn : [
1554                     {
1555                         tag : 'button',
1556                         cls : 'btn btn-default',
1557                         html : '<i class="fa fa-undo"></i>'
1558                     }
1559                 ]
1560             },
1561             {
1562                 tag : 'div',
1563                 cls : 'btn-group roo-upload-cropbox-rotate-right',
1564                 action : 'rotate-right',
1565                 cn : [
1566                     {
1567                         tag : 'button',
1568                         cls : 'btn btn-default',
1569                         html : '<i class="fa fa-repeat"></i>'
1570                     }
1571                 ]
1572             }
1573         ]
1574     }
1575 });