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.OriginWidth > this.imageEl.OriginHeight){
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.imageEl.OriginHeight){
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                 var buffer = e.target.result,
1182                     dataView = new DataView(buffer),
1183                     offset = 2,
1184                     maxOffset = dataView.byteLength - 4,
1185                     markerBytes,
1186                     markerLength;
1187                 
1188                 if (dataView.getUint16(0) === 0xffd8) {
1189                     while (offset < maxOffset) {
1190                         markerBytes = dataView.getUint16(offset);
1191                         
1192                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
1193                             markerLength = dataView.getUint16(offset + 2) + 2;
1194                             if (offset + markerLength > dataView.byteLength) {
1195                                 Roo.log('Invalid meta data: Invalid segment size.');
1196                                 break;
1197                             }
1198                             
1199                             if(markerBytes == 0xffe1){
1200                                 _this.parseExifData(
1201                                     dataView,
1202                                     offset,
1203                                     markerLength
1204                                 );
1205                             }
1206                             
1207                             offset += markerLength;
1208                             
1209                             continue;
1210                         }
1211                         
1212                         break;
1213                     }
1214                     
1215                 }
1216                 
1217                 var url = _this.urlAPI.createObjectURL(_this.file);
1218                 
1219                 _this.loadCanvas(url);
1220                 
1221                 return;
1222             }
1223             
1224             reader.readAsArrayBuffer(this.file);
1225             
1226         }
1227         
1228     },
1229     
1230     parseExifData : function(dataView, offset, length)
1231     {
1232         var tiffOffset = offset + 10,
1233             littleEndian,
1234             dirOffset;
1235     
1236         if (dataView.getUint32(offset + 4) !== 0x45786966) {
1237             // No Exif data, might be XMP data instead
1238             return;
1239         }
1240         
1241         // Check for the ASCII code for "Exif" (0x45786966):
1242         if (dataView.getUint32(offset + 4) !== 0x45786966) {
1243             // No Exif data, might be XMP data instead
1244             return;
1245         }
1246         if (tiffOffset + 8 > dataView.byteLength) {
1247             Roo.log('Invalid Exif data: Invalid segment size.');
1248             return;
1249         }
1250         // Check for the two null bytes:
1251         if (dataView.getUint16(offset + 8) !== 0x0000) {
1252             Roo.log('Invalid Exif data: Missing byte alignment offset.');
1253             return;
1254         }
1255         // Check the byte alignment:
1256         switch (dataView.getUint16(tiffOffset)) {
1257         case 0x4949:
1258             littleEndian = true;
1259             break;
1260         case 0x4D4D:
1261             littleEndian = false;
1262             break;
1263         default:
1264             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
1265             return;
1266         }
1267         // Check for the TIFF tag marker (0x002A):
1268         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
1269             Roo.log('Invalid Exif data: Missing TIFF marker.');
1270             return;
1271         }
1272         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
1273         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
1274         
1275         this.parseExifTags(
1276             dataView,
1277             tiffOffset,
1278             tiffOffset + dirOffset,
1279             littleEndian
1280         );
1281     },
1282     
1283     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
1284     {
1285         var tagsNumber,
1286             dirEndOffset,
1287             i;
1288         if (dirOffset + 6 > dataView.byteLength) {
1289             Roo.log('Invalid Exif data: Invalid directory offset.');
1290             return;
1291         }
1292         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
1293         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
1294         if (dirEndOffset + 4 > dataView.byteLength) {
1295             Roo.log('Invalid Exif data: Invalid directory size.');
1296             return;
1297         }
1298         for (i = 0; i < tagsNumber; i += 1) {
1299             this.parseExifTag(
1300                 dataView,
1301                 tiffOffset,
1302                 dirOffset + 2 + 12 * i, // tag offset
1303                 littleEndian
1304             );
1305         }
1306         // Return the offset to the next directory:
1307         return dataView.getUint32(dirEndOffset, littleEndian);
1308     },
1309     
1310     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
1311     {
1312         var tag = dataView.getUint16(offset, littleEndian);
1313         
1314         this.exif[tag] = this.getExifValue(
1315             dataView,
1316             tiffOffset,
1317             offset,
1318             dataView.getUint16(offset + 2, littleEndian), // tag type
1319             dataView.getUint32(offset + 4, littleEndian), // tag length
1320             littleEndian
1321         );
1322     },
1323     
1324     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
1325     {
1326         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
1327             tagSize,
1328             dataOffset,
1329             values,
1330             i,
1331             str,
1332             c;
1333     
1334         if (!tagType) {
1335             Roo.log('Invalid Exif data: Invalid tag type.');
1336             return;
1337         }
1338         
1339         tagSize = tagType.size * length;
1340         // Determine if the value is contained in the dataOffset bytes,
1341         // or if the value at the dataOffset is a pointer to the actual data:
1342         dataOffset = tagSize > 4 ?
1343                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
1344         if (dataOffset + tagSize > dataView.byteLength) {
1345             Roo.log('Invalid Exif data: Invalid data offset.');
1346             return;
1347         }
1348         if (length === 1) {
1349             return tagType.getValue(dataView, dataOffset, littleEndian);
1350         }
1351         values = [];
1352         for (i = 0; i < length; i += 1) {
1353             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
1354         }
1355         
1356         if (tagType.ascii) {
1357             str = '';
1358             // Concatenate the chars:
1359             for (i = 0; i < values.length; i += 1) {
1360                 c = values[i];
1361                 // Ignore the terminating NULL byte(s):
1362                 if (c === '\u0000') {
1363                     break;
1364                 }
1365                 str += c;
1366             }
1367             return str;
1368         }
1369         return values;
1370     }
1371     
1372 });
1373
1374 Roo.apply(Roo.bootstrap.UploadCropbox, {
1375     tags : {
1376         'Orientation': 0x0112
1377     },
1378     
1379     Orientation: {
1380             1: 0, //'top-left',
1381 //            2: 'top-right',
1382             3: 180, //'bottom-right',
1383 //            4: 'bottom-left',
1384 //            5: 'left-top',
1385             6: 90, //'right-top',
1386 //            7: 'right-bottom',
1387             8: 270 //'left-bottom'
1388     },
1389     
1390     exifTagTypes : {
1391         // byte, 8-bit unsigned int:
1392         1: {
1393             getValue: function (dataView, dataOffset) {
1394                 return dataView.getUint8(dataOffset);
1395             },
1396             size: 1
1397         },
1398         // ascii, 8-bit byte:
1399         2: {
1400             getValue: function (dataView, dataOffset) {
1401                 return String.fromCharCode(dataView.getUint8(dataOffset));
1402             },
1403             size: 1,
1404             ascii: true
1405         },
1406         // short, 16 bit int:
1407         3: {
1408             getValue: function (dataView, dataOffset, littleEndian) {
1409                 return dataView.getUint16(dataOffset, littleEndian);
1410             },
1411             size: 2
1412         },
1413         // long, 32 bit int:
1414         4: {
1415             getValue: function (dataView, dataOffset, littleEndian) {
1416                 return dataView.getUint32(dataOffset, littleEndian);
1417             },
1418             size: 4
1419         },
1420         // rational = two long values, first is numerator, second is denominator:
1421         5: {
1422             getValue: function (dataView, dataOffset, littleEndian) {
1423                 return dataView.getUint32(dataOffset, littleEndian) /
1424                     dataView.getUint32(dataOffset + 4, littleEndian);
1425             },
1426             size: 8
1427         },
1428         // slong, 32 bit signed int:
1429         9: {
1430             getValue: function (dataView, dataOffset, littleEndian) {
1431                 return dataView.getInt32(dataOffset, littleEndian);
1432             },
1433             size: 4
1434         },
1435         // srational, two slongs, first is numerator, second is denominator:
1436         10: {
1437             getValue: function (dataView, dataOffset, littleEndian) {
1438                 return dataView.getInt32(dataOffset, littleEndian) /
1439                     dataView.getInt32(dataOffset + 4, littleEndian);
1440             },
1441             size: 8
1442         }
1443     },
1444     
1445     footer : {
1446         STANDARD : [
1447             {
1448                 tag : 'div',
1449                 cls : 'btn-group roo-upload-cropbox-rotate-left',
1450                 action : 'rotate-left',
1451                 cn : [
1452                     {
1453                         tag : 'button',
1454                         cls : 'btn btn-default',
1455                         html : '<i class="fa fa-undo"></i>'
1456                     }
1457                 ]
1458             },
1459             {
1460                 tag : 'div',
1461                 cls : 'btn-group roo-upload-cropbox-picture',
1462                 action : 'picture',
1463                 cn : [
1464                     {
1465                         tag : 'button',
1466                         cls : 'btn btn-default',
1467                         html : '<i class="fa fa-picture-o"></i>'
1468                     }
1469                 ]
1470             },
1471             {
1472                 tag : 'div',
1473                 cls : 'btn-group roo-upload-cropbox-rotate-right',
1474                 action : 'rotate-right',
1475                 cn : [
1476                     {
1477                         tag : 'button',
1478                         cls : 'btn btn-default',
1479                         html : '<i class="fa fa-repeat"></i>'
1480                     }
1481                 ]
1482             }
1483         ],
1484         DOCUMENT : [
1485             {
1486                 tag : 'div',
1487                 cls : 'btn-group roo-upload-cropbox-rotate-left',
1488                 action : 'rotate-left',
1489                 cn : [
1490                     {
1491                         tag : 'button',
1492                         cls : 'btn btn-default',
1493                         html : '<i class="fa fa-undo"></i>'
1494                     }
1495                 ]
1496             },
1497             {
1498                 tag : 'div',
1499                 cls : 'btn-group roo-upload-cropbox-download',
1500                 action : 'download',
1501                 cn : [
1502                     {
1503                         tag : 'button',
1504                         cls : 'btn btn-default',
1505                         html : '<i class="fa fa-download"></i>'
1506                     }
1507                 ]
1508             },
1509             {
1510                 tag : 'div',
1511                 cls : 'btn-group roo-upload-cropbox-crop',
1512                 action : 'crop',
1513                 cn : [
1514                     {
1515                         tag : 'button',
1516                         cls : 'btn btn-default',
1517                         html : '<i class="fa fa-crop"></i>'
1518                     }
1519                 ]
1520             },
1521             {
1522                 tag : 'div',
1523                 cls : 'btn-group roo-upload-cropbox-trash',
1524                 action : 'trash',
1525                 cn : [
1526                     {
1527                         tag : 'button',
1528                         cls : 'btn btn-default',
1529                         html : '<i class="fa fa-trash"></i>'
1530                     }
1531                 ]
1532             },
1533             {
1534                 tag : 'div',
1535                 cls : 'btn-group roo-upload-cropbox-rotate-right',
1536                 action : 'rotate-right',
1537                 cn : [
1538                     {
1539                         tag : 'button',
1540                         cls : 'btn btn-default',
1541                         html : '<i class="fa fa-repeat"></i>'
1542                     }
1543                 ]
1544             }
1545         ],
1546         ROTATOR : [
1547             {
1548                 tag : 'div',
1549                 cls : 'btn-group roo-upload-cropbox-rotate-left',
1550                 action : 'rotate-left',
1551                 cn : [
1552                     {
1553                         tag : 'button',
1554                         cls : 'btn btn-default',
1555                         html : '<i class="fa fa-undo"></i>'
1556                     }
1557                 ]
1558             },
1559             {
1560                 tag : 'div',
1561                 cls : 'btn-group roo-upload-cropbox-rotate-right',
1562                 action : 'rotate-right',
1563                 cn : [
1564                     {
1565                         tag : 'button',
1566                         cls : 'btn btn-default',
1567                         html : '<i class="fa fa-repeat"></i>'
1568                     }
1569                 ]
1570             }
1571         ]
1572     }
1573 });