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