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