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