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