Initial commit

This commit is contained in:
易焱
2021-04-18 18:51:51 +08:00
commit ec705f2fa8
3240 changed files with 623103 additions and 0 deletions
@@ -0,0 +1,50 @@
/**
* @fileOverview Fix android canvas.toDataUrl bug.
*/
define([
'./util',
'./jpegencoder',
'../../base'
], function( Util, encoder, Base ) {
var origin = Util.canvasToDataUrl,
supportJpeg;
Util.canvasToDataUrl = function( canvas, type, quality ) {
var ctx, w, h, fragement, parts;
// 非android手机直接跳过。
if ( !Base.os.android ) {
return origin.apply( null, arguments );
}
// 检测是否canvas支持jpeg导出,根据数据格式来判断。
// JPEG 前两位分别是:255, 216
if ( type === 'image/jpeg' && typeof supportJpeg === 'undefined' ) {
fragement = origin.apply( null, arguments );
parts = fragement.split(',');
if ( ~parts[ 0 ].indexOf('base64') ) {
fragement = atob( parts[ 1 ] );
} else {
fragement = decodeURIComponent( parts[ 1 ] );
}
fragement = fragement.substring( 0, 2 );
supportJpeg = fragement.charCodeAt( 0 ) === 255 &&
fragement.charCodeAt( 1 ) === 216;
}
// 只有在android环境下才修复
if ( type === 'image/jpeg' && !supportJpeg ) {
w = canvas.width;
h = canvas.height;
ctx = canvas.getContext('2d');
return encoder.encode( ctx.getImageData( 0, 0, w, h ), quality );
}
return origin.apply( null, arguments );
};
});
+19
View File
@@ -0,0 +1,19 @@
/**
* @fileOverview Blob Html实现
*/
define([
'./runtime',
'../../lib/blob'
], function( Html5Runtime, Blob ) {
return Html5Runtime.register( 'Blob', {
slice: function( start, end ) {
var blob = this.owner.source,
slice = blob.slice || blob.webkitSlice || blob.mozSlice;
blob = slice.call( blob, start, end );
return new Blob( this.getRuid(), blob );
}
});
});
+209
View File
@@ -0,0 +1,209 @@
/**
* @fileOverview FilePaste
*/
define([
'../../base',
'./runtime',
'../../lib/file'
], function( Base, Html5Runtime, File ) {
var $ = Base.$,
prefix = 'webuploader-dnd-';
return Html5Runtime.register( 'DragAndDrop', {
init: function() {
var elem = this.elem = this.options.container;
this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );
this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );
this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );
this.dropHandler = Base.bindFn( this._dropHandler, this );
this.dndOver = false;
elem.on( 'dragenter', this.dragEnterHandler );
elem.on( 'dragover', this.dragOverHandler );
elem.on( 'dragleave', this.dragLeaveHandler );
elem.on( 'drop', this.dropHandler );
if ( this.options.disableGlobalDnd ) {
$( document ).on( 'dragover', this.dragOverHandler );
$( document ).on( 'drop', this.dropHandler );
}
},
_dragEnterHandler: function( e ) {
var me = this,
denied = me._denied || false,
items;
e = e.originalEvent || e;
if ( !me.dndOver ) {
me.dndOver = true;
// 注意只有 chrome 支持。
items = e.dataTransfer.items;
if ( items && items.length ) {
me._denied = denied = !me.trigger( 'accept', items );
}
me.elem.addClass( prefix + 'over' );
me.elem[ denied ? 'addClass' :
'removeClass' ]( prefix + 'denied' );
}
e.dataTransfer.dropEffect = denied ? 'none' : 'copy';
return false;
},
_dragOverHandler: function( e ) {
// 只处理框内的。
var parentElem = this.elem.parent().get( 0 );
if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {
return false;
}
clearTimeout( this._leaveTimer );
this._dragEnterHandler.call( this, e );
return false;
},
_dragLeaveHandler: function() {
var me = this,
handler;
handler = function() {
me.dndOver = false;
me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );
};
clearTimeout( me._leaveTimer );
me._leaveTimer = setTimeout( handler, 100 );
return false;
},
_dropHandler: function( e ) {
var me = this,
ruid = me.getRuid(),
parentElem = me.elem.parent().get( 0 ),
dataTransfer, data;
// 只处理框内的。
if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {
return false;
}
e = e.originalEvent || e;
dataTransfer = e.dataTransfer;
// 如果是页面内拖拽,还不能处理,不阻止事件。
// 此处 ie11 下会报参数错误,
try {
data = dataTransfer.getData('text/html');
} catch( err ) {
}
me.dndOver = false;
me.elem.removeClass( prefix + 'over' );
if ( !dataTransfer || data ) {
return;
}
me._getTansferFiles( dataTransfer, function( results ) {
me.trigger( 'drop', $.map( results, function( file ) {
return new File( ruid, file );
}) );
});
return false;
},
// 如果传入 callback 则去查看文件夹,否则只管当前文件夹。
_getTansferFiles: function( dataTransfer, callback ) {
var results = [],
promises = [],
items, files, file, item, i, len, canAccessFolder;
items = dataTransfer.items;
files = dataTransfer.files;
canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);
for ( i = 0, len = files.length; i < len; i++ ) {
file = files[ i ];
item = items && items[ i ];
if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {
promises.push( this._traverseDirectoryTree(
item.webkitGetAsEntry(), results ) );
} else {
results.push( file );
}
}
Base.when.apply( Base, promises ).done(function() {
if ( !results.length ) {
return;
}
callback( results );
});
},
_traverseDirectoryTree: function( entry, results ) {
var deferred = Base.Deferred(),
me = this;
if ( entry.isFile ) {
entry.file(function( file ) {
results.push( file );
deferred.resolve();
});
} else if ( entry.isDirectory ) {
entry.createReader().readEntries(function( entries ) {
var len = entries.length,
promises = [],
arr = [], // 为了保证顺序。
i;
for ( i = 0; i < len; i++ ) {
promises.push( me._traverseDirectoryTree(
entries[ i ], arr ) );
}
Base.when.apply( Base, promises ).then(function() {
results.push.apply( results, arr );
deferred.resolve();
}, deferred.reject );
});
}
return deferred.promise();
},
destroy: function() {
var elem = this.elem;
// 还没 init 就调用 destroy
if (!elem) {
return;
}
elem.off( 'dragenter', this.dragEnterHandler );
elem.off( 'dragover', this.dragOverHandler );
elem.off( 'dragleave', this.dragLeaveHandler );
elem.off( 'drop', this.dropHandler );
if ( this.options.disableGlobalDnd ) {
$( document ).off( 'dragover', this.dragOverHandler );
$( document ).off( 'drop', this.dropHandler );
}
}
});
});
@@ -0,0 +1,66 @@
/**
* @fileOverview FilePaste
*/
define([
'../../base',
'./runtime',
'../../lib/file'
], function( Base, Html5Runtime, File ) {
return Html5Runtime.register( 'FilePaste', {
init: function() {
var opts = this.options,
elem = this.elem = opts.container,
accept = '.*',
arr, i, len, item;
// accetp的mimeTypes中生成匹配正则。
if ( opts.accept ) {
arr = [];
for ( i = 0, len = opts.accept.length; i < len; i++ ) {
item = opts.accept[ i ].mimeTypes;
item && arr.push( item );
}
if ( arr.length ) {
accept = arr.join(',');
accept = accept.replace( /,/g, '|' ).replace( /\*/g, '.*' );
}
}
this.accept = accept = new RegExp( accept, 'i' );
this.hander = Base.bindFn( this._pasteHander, this );
elem.on( 'paste', this.hander );
},
_pasteHander: function( e ) {
var allowed = [],
ruid = this.getRuid(),
items, item, blob, i, len;
e = e.originalEvent || e;
items = e.clipboardData.items;
for ( i = 0, len = items.length; i < len; i++ ) {
item = items[ i ];
if ( item.kind !== 'file' || !(blob = item.getAsFile()) ) {
continue;
}
allowed.push( new File( ruid, blob ) );
}
if ( allowed.length ) {
// 不阻止非文件粘贴(文字粘贴)的事件冒泡
e.preventDefault();
e.stopPropagation();
this.trigger( 'paste', allowed );
}
},
destroy: function() {
this.elem.off( 'paste', this.hander );
}
});
});
@@ -0,0 +1,95 @@
/**
* @fileOverview FilePicker
*/
define([
'../../base',
'./runtime'
], function( Base, Html5Runtime ) {
var $ = Base.$;
return Html5Runtime.register( 'FilePicker', {
init: function() {
var container = this.getRuntime().getContainer(),
me = this,
owner = me.owner,
opts = me.options,
label = this.label = $( document.createElement('label') ),
input = this.input = $( document.createElement('input') ),
arr, i, len, mouseHandler;
input.attr( 'type', 'file' );
input.attr( 'capture', 'camera');
input.attr( 'name', opts.name );
input.addClass('webuploader-element-invisible');
label.on( 'click', function(e) {
input.trigger('click');
e.stopPropagation();
owner.trigger('dialogopen');
});
label.css({
opacity: 0,
width: '100%',
height: '100%',
display: 'block',
cursor: 'pointer',
background: '#ffffff'
});
if ( opts.multiple ) {
input.attr( 'multiple', 'multiple' );
}
// @todo Firefox不支持单独指定后缀
if ( opts.accept && opts.accept.length > 0 ) {
arr = [];
for ( i = 0, len = opts.accept.length; i < len; i++ ) {
arr.push( opts.accept[ i ].mimeTypes );
}
input.attr( 'accept', arr.join(',') );
}
container.append( input );
container.append( label );
mouseHandler = function( e ) {
owner.trigger( e.type );
};
input.on( 'change', function( e ) {
var fn = arguments.callee,
clone;
me.files = e.target.files;
// reset input
clone = this.cloneNode( true );
clone.value = null;
this.parentNode.replaceChild( clone, this );
input.off();
input = $( clone ).on( 'change', fn )
.on( 'mouseenter mouseleave', mouseHandler );
owner.trigger('change');
});
label.on( 'mouseenter mouseleave', mouseHandler );
},
getFiles: function() {
return this.files;
},
destroy: function() {
this.input.off();
this.label.off();
}
});
});
+435
View File
@@ -0,0 +1,435 @@
/**
* @fileOverview Image
*/
define([
'../../base',
'./runtime',
'./util'
], function( Base, Html5Runtime, Util ) {
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D';
return Html5Runtime.register( 'Image', {
// flag: 标记是否被修改过。
modified: false,
init: function() {
var me = this,
img = new Image();
img.onload = function() {
me._info = {
type: me.type,
width: this.width,
height: this.height
};
//debugger;
// 读取meta信息。
if ( !me._metas && 'image/jpeg' === me.type ) {
Util.parseMeta( me._blob, function( error, ret ) {
me._metas = ret;
me.owner.trigger('load');
});
} else {
me.owner.trigger('load');
}
};
img.onerror = function() {
me.owner.trigger('error');
};
me._img = img;
},
loadFromBlob: function( blob ) {
var me = this,
img = me._img;
me._blob = blob;
me.type = blob.type;
img.src = Util.createObjectURL( blob.getSource() );
me.owner.once( 'load', function() {
Util.revokeObjectURL( img.src );
});
},
resize: function( width, height ) {
var canvas = this._canvas ||
(this._canvas = document.createElement('canvas'));
this._resize( this._img, canvas, width, height );
this._blob = null; // 没用了,可以删掉了。
this.modified = true;
this.owner.trigger( 'complete', 'resize' );
},
crop: function( x, y, w, h, s ) {
var cvs = this._canvas ||
(this._canvas = document.createElement('canvas')),
opts = this.options,
img = this._img,
iw = img.naturalWidth,
ih = img.naturalHeight,
orientation = this.getOrientation();
s = s || 1;
// todo 解决 orientation 的问题。
// values that require 90 degree rotation
// if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {
// switch ( orientation ) {
// case 6:
// tmp = x;
// x = y;
// y = iw * s - tmp - w;
// console.log(ih * s, tmp, w)
// break;
// }
// (w ^= h, h ^= w, w ^= h);
// }
cvs.width = w;
cvs.height = h;
opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );
this._renderImageToCanvas( cvs, img, -x, -y, iw * s, ih * s );
this._blob = null; // 没用了,可以删掉了。
this.modified = true;
this.owner.trigger( 'complete', 'crop' );
},
getAsBlob: function( type ) {
var blob = this._blob,
opts = this.options,
canvas;
type = type || this.type;
// blob需要重新生成。
if ( this.modified || this.type !== type ) {
canvas = this._canvas;
if ( type === 'image/jpeg' ) {
blob = Util.canvasToDataUrl( canvas, type, opts.quality );
if ( opts.preserveHeaders && this._metas &&
this._metas.imageHead ) {
blob = Util.dataURL2ArrayBuffer( blob );
blob = Util.updateImageHead( blob,
this._metas.imageHead );
blob = Util.arrayBufferToBlob( blob, type );
return blob;
}
} else {
blob = Util.canvasToDataUrl( canvas, type );
}
blob = Util.dataURL2Blob( blob );
}
return blob;
},
getAsDataUrl: function( type ) {
var opts = this.options;
type = type || this.type;
if ( type === 'image/jpeg' ) {
return Util.canvasToDataUrl( this._canvas, type, opts.quality );
} else {
return this._canvas.toDataURL( type );
}
},
getOrientation: function() {
return this._metas && this._metas.exif &&
this._metas.exif.get('Orientation') || 1;
},
info: function( val ) {
// setter
if ( val ) {
this._info = val;
return this;
}
// getter
return this._info;
},
meta: function( val ) {
// setter
if ( val ) {
this._metas = val;
return this;
}
// getter
return this._metas;
},
destroy: function() {
var canvas = this._canvas;
this._img.onload = null;
if ( canvas ) {
canvas.getContext('2d')
.clearRect( 0, 0, canvas.width, canvas.height );
canvas.width = canvas.height = 0;
this._canvas = null;
}
// 释放内存。非常重要,否则释放不了image的内存。
this._img.src = BLANK;
this._img = this._blob = null;
},
_resize: function( img, cvs, width, height ) {
var opts = this.options,
naturalWidth = img.width,
naturalHeight = img.height,
orientation = this.getOrientation(),
scale, w, h, x, y;
// values that require 90 degree rotation
if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {
// 交换width, height的值。
width ^= height;
height ^= width;
width ^= height;
}
scale = Math[ opts.crop ? 'max' : 'min' ]( width / naturalWidth,
height / naturalHeight );
// 不允许放大。
opts.allowMagnify || (scale = Math.min( 1, scale ));
w = naturalWidth * scale;
h = naturalHeight * scale;
if ( opts.crop ) {
cvs.width = width;
cvs.height = height;
} else {
cvs.width = w;
cvs.height = h;
}
x = (cvs.width - w) / 2;
y = (cvs.height - h) / 2;
opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );
this._renderImageToCanvas( cvs, img, x, y, w, h );
},
_rotate2Orientaion: function( canvas, orientation ) {
var width = canvas.width,
height = canvas.height,
ctx = canvas.getContext('2d');
switch ( orientation ) {
case 5:
case 6:
case 7:
case 8:
canvas.width = height;
canvas.height = width;
break;
}
switch ( orientation ) {
case 2: // horizontal flip
ctx.translate( width, 0 );
ctx.scale( -1, 1 );
break;
case 3: // 180 rotate left
ctx.translate( width, height );
ctx.rotate( Math.PI );
break;
case 4: // vertical flip
ctx.translate( 0, height );
ctx.scale( 1, -1 );
break;
case 5: // vertical flip + 90 rotate right
ctx.rotate( 0.5 * Math.PI );
ctx.scale( 1, -1 );
break;
case 6: // 90 rotate right
ctx.rotate( 0.5 * Math.PI );
ctx.translate( 0, -height );
break;
case 7: // horizontal flip + 90 rotate right
ctx.rotate( 0.5 * Math.PI );
ctx.translate( width, -height );
ctx.scale( -1, 1 );
break;
case 8: // 90 rotate left
ctx.rotate( -0.5 * Math.PI );
ctx.translate( -width, 0 );
break;
}
},
// https://github.com/stomita/ios-imagefile-megapixel/
// blob/master/src/megapix-image.js
_renderImageToCanvas: (function() {
// 如果不是ios, 不需要这么复杂!
if ( !Base.os.ios ) {
return function( canvas ) {
var args = Base.slice( arguments, 1 ),
ctx = canvas.getContext('2d');
ctx.drawImage.apply( ctx, args );
};
}
/**
* Detecting vertical squash in loaded image.
* Fixes a bug which squash image vertically while drawing into
* canvas for some images.
*/
function detectVerticalSquash( img, iw, ih ) {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
sy = 0,
ey = ih,
py = ih,
data, alpha, ratio;
canvas.width = 1;
canvas.height = ih;
ctx.drawImage( img, 0, 0 );
data = ctx.getImageData( 0, 0, 1, ih ).data;
// search image edge pixel position in case
// it is squashed vertically.
while ( py > sy ) {
alpha = data[ (py - 1) * 4 + 3 ];
if ( alpha === 0 ) {
ey = py;
} else {
sy = py;
}
py = (ey + sy) >> 1;
}
ratio = (py / ih);
return (ratio === 0) ? 1 : ratio;
}
// fix ie7 bug
// http://stackoverflow.com/questions/11929099/
// html5-canvas-drawimage-ratio-bug-ios
if ( Base.os.ios >= 7 ) {
return function( canvas, img, x, y, w, h ) {
var iw = img.naturalWidth,
ih = img.naturalHeight,
vertSquashRatio = detectVerticalSquash( img, iw, ih );
return canvas.getContext('2d').drawImage( img, 0, 0,
iw * vertSquashRatio, ih * vertSquashRatio,
x, y, w, h );
};
}
/**
* Detect subsampling in loaded image.
* In iOS, larger images than 2M pixels may be
* subsampled in rendering.
*/
function detectSubsampling( img ) {
var iw = img.naturalWidth,
ih = img.naturalHeight,
canvas, ctx;
// subsampling may happen overmegapixel image
if ( iw * ih > 1024 * 1024 ) {
canvas = document.createElement('canvas');
canvas.width = canvas.height = 1;
ctx = canvas.getContext('2d');
ctx.drawImage( img, -iw + 1, 0 );
// subsampled image becomes half smaller in rendering size.
// check alpha channel value to confirm image is covering
// edge pixel or not. if alpha value is 0
// image is not covering, hence subsampled.
return ctx.getImageData( 0, 0, 1, 1 ).data[ 3 ] === 0;
} else {
return false;
}
}
return function( canvas, img, x, y, width, height ) {
var iw = img.naturalWidth,
ih = img.naturalHeight,
ctx = canvas.getContext('2d'),
subsampled = detectSubsampling( img ),
doSquash = this.type === 'image/jpeg',
d = 1024,
sy = 0,
dy = 0,
tmpCanvas, tmpCtx, vertSquashRatio, dw, dh, sx, dx;
if ( subsampled ) {
iw /= 2;
ih /= 2;
}
ctx.save();
tmpCanvas = document.createElement('canvas');
tmpCanvas.width = tmpCanvas.height = d;
tmpCtx = tmpCanvas.getContext('2d');
vertSquashRatio = doSquash ?
detectVerticalSquash( img, iw, ih ) : 1;
dw = Math.ceil( d * width / iw );
dh = Math.ceil( d * height / ih / vertSquashRatio );
while ( sy < ih ) {
sx = 0;
dx = 0;
while ( sx < iw ) {
tmpCtx.clearRect( 0, 0, d, d );
tmpCtx.drawImage( img, -sx, -sy );
ctx.drawImage( tmpCanvas, 0, 0, d, d,
x + dx, y + dy, dw, dh );
sx += d;
dx += dw;
}
sy += d;
dy += dh;
}
ctx.restore();
tmpCanvas = tmpCtx = null;
};
})()
});
});
@@ -0,0 +1,131 @@
/**
* Terms:
*
* Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer
* @fileOverview Image控件
*/
define([
'./util'
], function( Util ) {
var api;
api = {
parsers: {
0xffe1: []
},
maxMetaDataSize: 262144,
parse: function( blob, cb ) {
var me = this,
fr = new FileReader();
fr.onload = function() {
cb( false, me._parse( this.result ) );
fr = fr.onload = fr.onerror = null;
};
fr.onerror = function( e ) {
cb( e.message );
fr = fr.onload = fr.onerror = null;
};
blob = blob.slice( 0, me.maxMetaDataSize );
fr.readAsArrayBuffer( blob.getSource() );
},
_parse: function( buffer, noParse ) {
if ( buffer.byteLength < 6 ) {
return;
}
var dataview = new DataView( buffer ),
offset = 2,
maxOffset = dataview.byteLength - 4,
headLength = offset,
ret = {},
markerBytes, markerLength, parsers, i;
if ( dataview.getUint16( 0 ) === 0xffd8 ) {
while ( offset < maxOffset ) {
markerBytes = dataview.getUint16( offset );
if ( markerBytes >= 0xffe0 && markerBytes <= 0xffef ||
markerBytes === 0xfffe ) {
markerLength = dataview.getUint16( offset + 2 ) + 2;
if ( offset + markerLength > dataview.byteLength ) {
break;
}
parsers = api.parsers[ markerBytes ];
if ( !noParse && parsers ) {
for ( i = 0; i < parsers.length; i += 1 ) {
parsers[ i ].call( api, dataview, offset,
markerLength, ret );
}
}
offset += markerLength;
headLength = offset;
} else {
break;
}
}
if ( headLength > 6 ) {
if ( buffer.slice ) {
ret.imageHead = buffer.slice( 2, headLength );
} else {
// Workaround for IE10, which does not yet
// support ArrayBuffer.slice:
ret.imageHead = new Uint8Array( buffer )
.subarray( 2, headLength );
}
}
}
return ret;
},
updateImageHead: function( buffer, head ) {
var data = this._parse( buffer, true ),
buf1, buf2, bodyoffset;
bodyoffset = 2;
if ( data.imageHead ) {
bodyoffset = 2 + data.imageHead.byteLength;
}
if ( buffer.slice ) {
buf2 = buffer.slice( bodyoffset );
} else {
buf2 = new Uint8Array( buffer ).subarray( bodyoffset );
}
buf1 = new Uint8Array( head.byteLength + 2 + buf2.byteLength );
buf1[ 0 ] = 0xFF;
buf1[ 1 ] = 0xD8;
buf1.set( new Uint8Array( head ), 2 );
buf1.set( new Uint8Array( buf2 ), head.byteLength + 2 );
return buf1.buffer;
}
};
Util.parseMeta = function() {
return api.parse.apply( api, arguments );
};
Util.updateImageHead = function() {
return api.updateImageHead.apply( api, arguments );
};
return api;
});
@@ -0,0 +1,310 @@
/**
* 代码来自于:https://github.com/blueimp/JavaScript-Load-Image
* 暂时项目中只用了orientation.
*
* 去除了 Exif Sub IFD Pointer, GPS Info IFD Pointer, Exif Thumbnail.
* @fileOverview EXIF解析
*/
// Sample
// ====================================
// Make : Apple
// Model : iPhone 4S
// Orientation : 1
// XResolution : 72 [72/1]
// YResolution : 72 [72/1]
// ResolutionUnit : 2
// Software : QuickTime 7.7.1
// DateTime : 2013:09:01 22:53:55
// ExifIFDPointer : 190
// ExposureTime : 0.058823529411764705 [1/17]
// FNumber : 2.4 [12/5]
// ExposureProgram : Normal program
// ISOSpeedRatings : 800
// ExifVersion : 0220
// DateTimeOriginal : 2013:09:01 22:52:51
// DateTimeDigitized : 2013:09:01 22:52:51
// ComponentsConfiguration : YCbCr
// ShutterSpeedValue : 4.058893515764426
// ApertureValue : 2.5260688216892597 [4845/1918]
// BrightnessValue : -0.3126686601998395
// MeteringMode : Pattern
// Flash : Flash did not fire, compulsory flash mode
// FocalLength : 4.28 [107/25]
// SubjectArea : [4 values]
// FlashpixVersion : 0100
// ColorSpace : 1
// PixelXDimension : 2448
// PixelYDimension : 3264
// SensingMethod : One-chip color area sensor
// ExposureMode : 0
// WhiteBalance : Auto white balance
// FocalLengthIn35mmFilm : 35
// SceneCaptureType : Standard
define([
'../../../base',
'../imagemeta'
], function( Base, ImageMeta ) {
var EXIF = {};
EXIF.ExifMap = function() {
return this;
};
EXIF.ExifMap.prototype.map = {
'Orientation': 0x0112
};
EXIF.ExifMap.prototype.get = function( id ) {
return this[ id ] || this[ this.map[ id ] ];
};
EXIF.exifTagTypes = {
// byte, 8-bit unsigned int:
1: {
getValue: function( dataView, dataOffset ) {
return dataView.getUint8( dataOffset );
},
size: 1
},
// ascii, 8-bit byte:
2: {
getValue: function( dataView, dataOffset ) {
return String.fromCharCode( dataView.getUint8( dataOffset ) );
},
size: 1,
ascii: true
},
// short, 16 bit int:
3: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getUint16( dataOffset, littleEndian );
},
size: 2
},
// long, 32 bit int:
4: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getUint32( dataOffset, littleEndian );
},
size: 4
},
// rational = two long values,
// first is numerator, second is denominator:
5: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getUint32( dataOffset, littleEndian ) /
dataView.getUint32( dataOffset + 4, littleEndian );
},
size: 8
},
// slong, 32 bit signed int:
9: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getInt32( dataOffset, littleEndian );
},
size: 4
},
// srational, two slongs, first is numerator, second is denominator:
10: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getInt32( dataOffset, littleEndian ) /
dataView.getInt32( dataOffset + 4, littleEndian );
},
size: 8
}
};
// undefined, 8-bit byte, value depending on field:
EXIF.exifTagTypes[ 7 ] = EXIF.exifTagTypes[ 1 ];
EXIF.getExifValue = function( dataView, tiffOffset, offset, type, length,
littleEndian ) {
var tagType = EXIF.exifTagTypes[ type ],
tagSize, dataOffset, values, i, str, c;
if ( !tagType ) {
Base.log('Invalid Exif data: Invalid tag type.');
return;
}
tagSize = tagType.size * length;
// Determine if the value is contained in the dataOffset bytes,
// or if the value at the dataOffset is a pointer to the actual data:
dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32( offset + 8,
littleEndian ) : (offset + 8);
if ( dataOffset + tagSize > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid data offset.');
return;
}
if ( length === 1 ) {
return tagType.getValue( dataView, dataOffset, littleEndian );
}
values = [];
for ( i = 0; i < length; i += 1 ) {
values[ i ] = tagType.getValue( dataView,
dataOffset + i * tagType.size, littleEndian );
}
if ( tagType.ascii ) {
str = '';
// Concatenate the chars:
for ( i = 0; i < values.length; i += 1 ) {
c = values[ i ];
// Ignore the terminating NULL byte(s):
if ( c === '\u0000' ) {
break;
}
str += c;
}
return str;
}
return values;
};
EXIF.parseExifTag = function( dataView, tiffOffset, offset, littleEndian,
data ) {
var tag = dataView.getUint16( offset, littleEndian );
data.exif[ tag ] = EXIF.getExifValue( dataView, tiffOffset, offset,
dataView.getUint16( offset + 2, littleEndian ), // tag type
dataView.getUint32( offset + 4, littleEndian ), // tag length
littleEndian );
};
EXIF.parseExifTags = function( dataView, tiffOffset, dirOffset,
littleEndian, data ) {
var tagsNumber, dirEndOffset, i;
if ( dirOffset + 6 > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid directory offset.');
return;
}
tagsNumber = dataView.getUint16( dirOffset, littleEndian );
dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
if ( dirEndOffset + 4 > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid directory size.');
return;
}
for ( i = 0; i < tagsNumber; i += 1 ) {
this.parseExifTag( dataView, tiffOffset,
dirOffset + 2 + 12 * i, // tag offset
littleEndian, data );
}
// Return the offset to the next directory:
return dataView.getUint32( dirEndOffset, littleEndian );
};
// EXIF.getExifThumbnail = function(dataView, offset, length) {
// var hexData,
// i,
// b;
// if (!length || offset + length > dataView.byteLength) {
// Base.log('Invalid Exif data: Invalid thumbnail data.');
// return;
// }
// hexData = [];
// for (i = 0; i < length; i += 1) {
// b = dataView.getUint8(offset + i);
// hexData.push((b < 16 ? '0' : '') + b.toString(16));
// }
// return 'data:image/jpeg,%' + hexData.join('%');
// };
EXIF.parseExifData = function( dataView, offset, length, data ) {
var tiffOffset = offset + 10,
littleEndian, dirOffset;
// Check for the ASCII code for "Exif" (0x45786966):
if ( dataView.getUint32( offset + 4 ) !== 0x45786966 ) {
// No Exif data, might be XMP data instead
return;
}
if ( tiffOffset + 8 > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid segment size.');
return;
}
// Check for the two null bytes:
if ( dataView.getUint16( offset + 8 ) !== 0x0000 ) {
Base.log('Invalid Exif data: Missing byte alignment offset.');
return;
}
// Check the byte alignment:
switch ( dataView.getUint16( tiffOffset ) ) {
case 0x4949:
littleEndian = true;
break;
case 0x4D4D:
littleEndian = false;
break;
default:
Base.log('Invalid Exif data: Invalid byte alignment marker.');
return;
}
// Check for the TIFF tag marker (0x002A):
if ( dataView.getUint16( tiffOffset + 2, littleEndian ) !== 0x002A ) {
Base.log('Invalid Exif data: Missing TIFF marker.');
return;
}
// Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
dirOffset = dataView.getUint32( tiffOffset + 4, littleEndian );
// Create the exif object to store the tags:
data.exif = new EXIF.ExifMap();
// Parse the tags of the main image directory and retrieve the
// offset to the next directory, usually the thumbnail directory:
dirOffset = EXIF.parseExifTags( dataView, tiffOffset,
tiffOffset + dirOffset, littleEndian, data );
// 尝试读取缩略图
// if ( dirOffset ) {
// thumbnailData = {exif: {}};
// dirOffset = EXIF.parseExifTags(
// dataView,
// tiffOffset,
// tiffOffset + dirOffset,
// littleEndian,
// thumbnailData
// );
// // Check for JPEG Thumbnail offset:
// if (thumbnailData.exif[0x0201]) {
// data.exif.Thumbnail = EXIF.getExifThumbnail(
// dataView,
// tiffOffset + thumbnailData.exif[0x0201],
// thumbnailData.exif[0x0202] // Thumbnail data length
// );
// }
// }
};
ImageMeta.parsers[ 0xffe1 ].push( EXIF.parseExifData );
return EXIF;
});
@@ -0,0 +1,752 @@
/**
* 这个方式性能不行,但是可以解决android里面的toDataUrl的bug
* android里面toDataUrl('image/jpege')得到的结果却是png.
*
* 所以这里没辙,只能借助这个工具
* @fileOverview jpeg encoder
*/
define([], function( require, exports, module ) {
/*
Copyright (c) 2008, Adobe Systems Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems Incorporated nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
JPEG encoder ported to JavaScript and optimized by Andreas Ritter, www.bytestrom.eu, 11/2009
Basic GUI blocking jpeg encoder
*/
function JPEGEncoder(quality) {
var self = this;
var fround = Math.round;
var ffloor = Math.floor;
var YTable = new Array(64);
var UVTable = new Array(64);
var fdtbl_Y = new Array(64);
var fdtbl_UV = new Array(64);
var YDC_HT;
var UVDC_HT;
var YAC_HT;
var UVAC_HT;
var bitcode = new Array(65535);
var category = new Array(65535);
var outputfDCTQuant = new Array(64);
var DU = new Array(64);
var byteout = [];
var bytenew = 0;
var bytepos = 7;
var YDU = new Array(64);
var UDU = new Array(64);
var VDU = new Array(64);
var clt = new Array(256);
var RGB_YUV_TABLE = new Array(2048);
var currentQuality;
var ZigZag = [
0, 1, 5, 6,14,15,27,28,
2, 4, 7,13,16,26,29,42,
3, 8,12,17,25,30,41,43,
9,11,18,24,31,40,44,53,
10,19,23,32,39,45,52,54,
20,22,33,38,46,51,55,60,
21,34,37,47,50,56,59,61,
35,36,48,49,57,58,62,63
];
var std_dc_luminance_nrcodes = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];
var std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11];
var std_ac_luminance_nrcodes = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];
var std_ac_luminance_values = [
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,
0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,
0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,
0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,
0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
0xf9,0xfa
];
var std_dc_chrominance_nrcodes = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];
var std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11];
var std_ac_chrominance_nrcodes = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];
var std_ac_chrominance_values = [
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,
0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,
0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,
0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,
0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,
0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,
0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,
0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,
0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,
0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
0xf9,0xfa
];
function initQuantTables(sf){
var YQT = [
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68,109,103, 77,
24, 35, 55, 64, 81,104,113, 92,
49, 64, 78, 87,103,121,120,101,
72, 92, 95, 98,112,100,103, 99
];
for (var i = 0; i < 64; i++) {
var t = ffloor((YQT[i]*sf+50)/100);
if (t < 1) {
t = 1;
} else if (t > 255) {
t = 255;
}
YTable[ZigZag[i]] = t;
}
var UVQT = [
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
];
for (var j = 0; j < 64; j++) {
var u = ffloor((UVQT[j]*sf+50)/100);
if (u < 1) {
u = 1;
} else if (u > 255) {
u = 255;
}
UVTable[ZigZag[j]] = u;
}
var aasf = [
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
];
var k = 0;
for (var row = 0; row < 8; row++)
{
for (var col = 0; col < 8; col++)
{
fdtbl_Y[k] = (1.0 / (YTable [ZigZag[k]] * aasf[row] * aasf[col] * 8.0));
fdtbl_UV[k] = (1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0));
k++;
}
}
}
function computeHuffmanTbl(nrcodes, std_table){
var codevalue = 0;
var pos_in_table = 0;
var HT = new Array();
for (var k = 1; k <= 16; k++) {
for (var j = 1; j <= nrcodes[k]; j++) {
HT[std_table[pos_in_table]] = [];
HT[std_table[pos_in_table]][0] = codevalue;
HT[std_table[pos_in_table]][1] = k;
pos_in_table++;
codevalue++;
}
codevalue*=2;
}
return HT;
}
function initHuffmanTbl()
{
YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);
UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);
YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);
UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);
}
function initCategoryNumber()
{
var nrlower = 1;
var nrupper = 2;
for (var cat = 1; cat <= 15; cat++) {
//Positive numbers
for (var nr = nrlower; nr<nrupper; nr++) {
category[32767+nr] = cat;
bitcode[32767+nr] = [];
bitcode[32767+nr][1] = cat;
bitcode[32767+nr][0] = nr;
}
//Negative numbers
for (var nrneg =-(nrupper-1); nrneg<=-nrlower; nrneg++) {
category[32767+nrneg] = cat;
bitcode[32767+nrneg] = [];
bitcode[32767+nrneg][1] = cat;
bitcode[32767+nrneg][0] = nrupper-1+nrneg;
}
nrlower <<= 1;
nrupper <<= 1;
}
}
function initRGBYUVTable() {
for(var i = 0; i < 256;i++) {
RGB_YUV_TABLE[i] = 19595 * i;
RGB_YUV_TABLE[(i+ 256)>>0] = 38470 * i;
RGB_YUV_TABLE[(i+ 512)>>0] = 7471 * i + 0x8000;
RGB_YUV_TABLE[(i+ 768)>>0] = -11059 * i;
RGB_YUV_TABLE[(i+1024)>>0] = -21709 * i;
RGB_YUV_TABLE[(i+1280)>>0] = 32768 * i + 0x807FFF;
RGB_YUV_TABLE[(i+1536)>>0] = -27439 * i;
RGB_YUV_TABLE[(i+1792)>>0] = - 5329 * i;
}
}
// IO functions
function writeBits(bs)
{
var value = bs[0];
var posval = bs[1]-1;
while ( posval >= 0 ) {
if (value & (1 << posval) ) {
bytenew |= (1 << bytepos);
}
posval--;
bytepos--;
if (bytepos < 0) {
if (bytenew == 0xFF) {
writeByte(0xFF);
writeByte(0);
}
else {
writeByte(bytenew);
}
bytepos=7;
bytenew=0;
}
}
}
function writeByte(value)
{
byteout.push(clt[value]); // write char directly instead of converting later
}
function writeWord(value)
{
writeByte((value>>8)&0xFF);
writeByte((value )&0xFF);
}
// DCT & quantization core
function fDCTQuant(data, fdtbl)
{
var d0, d1, d2, d3, d4, d5, d6, d7;
/* Pass 1: process rows. */
var dataOff=0;
var i;
var I8 = 8;
var I64 = 64;
for (i=0; i<I8; ++i)
{
d0 = data[dataOff];
d1 = data[dataOff+1];
d2 = data[dataOff+2];
d3 = data[dataOff+3];
d4 = data[dataOff+4];
d5 = data[dataOff+5];
d6 = data[dataOff+6];
d7 = data[dataOff+7];
var tmp0 = d0 + d7;
var tmp7 = d0 - d7;
var tmp1 = d1 + d6;
var tmp6 = d1 - d6;
var tmp2 = d2 + d5;
var tmp5 = d2 - d5;
var tmp3 = d3 + d4;
var tmp4 = d3 - d4;
/* Even part */
var tmp10 = tmp0 + tmp3; /* phase 2 */
var tmp13 = tmp0 - tmp3;
var tmp11 = tmp1 + tmp2;
var tmp12 = tmp1 - tmp2;
data[dataOff] = tmp10 + tmp11; /* phase 3 */
data[dataOff+4] = tmp10 - tmp11;
var z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */
data[dataOff+2] = tmp13 + z1; /* phase 5 */
data[dataOff+6] = tmp13 - z1;
/* Odd part */
tmp10 = tmp4 + tmp5; /* phase 2 */
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
/* The rotator is modified from fig 4-8 to avoid extra negations. */
var z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */
var z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */
var z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */
var z3 = tmp11 * 0.707106781; /* c4 */
var z11 = tmp7 + z3; /* phase 5 */
var z13 = tmp7 - z3;
data[dataOff+5] = z13 + z2; /* phase 6 */
data[dataOff+3] = z13 - z2;
data[dataOff+1] = z11 + z4;
data[dataOff+7] = z11 - z4;
dataOff += 8; /* advance pointer to next row */
}
/* Pass 2: process columns. */
dataOff = 0;
for (i=0; i<I8; ++i)
{
d0 = data[dataOff];
d1 = data[dataOff + 8];
d2 = data[dataOff + 16];
d3 = data[dataOff + 24];
d4 = data[dataOff + 32];
d5 = data[dataOff + 40];
d6 = data[dataOff + 48];
d7 = data[dataOff + 56];
var tmp0p2 = d0 + d7;
var tmp7p2 = d0 - d7;
var tmp1p2 = d1 + d6;
var tmp6p2 = d1 - d6;
var tmp2p2 = d2 + d5;
var tmp5p2 = d2 - d5;
var tmp3p2 = d3 + d4;
var tmp4p2 = d3 - d4;
/* Even part */
var tmp10p2 = tmp0p2 + tmp3p2; /* phase 2 */
var tmp13p2 = tmp0p2 - tmp3p2;
var tmp11p2 = tmp1p2 + tmp2p2;
var tmp12p2 = tmp1p2 - tmp2p2;
data[dataOff] = tmp10p2 + tmp11p2; /* phase 3 */
data[dataOff+32] = tmp10p2 - tmp11p2;
var z1p2 = (tmp12p2 + tmp13p2) * 0.707106781; /* c4 */
data[dataOff+16] = tmp13p2 + z1p2; /* phase 5 */
data[dataOff+48] = tmp13p2 - z1p2;
/* Odd part */
tmp10p2 = tmp4p2 + tmp5p2; /* phase 2 */
tmp11p2 = tmp5p2 + tmp6p2;
tmp12p2 = tmp6p2 + tmp7p2;
/* The rotator is modified from fig 4-8 to avoid extra negations. */
var z5p2 = (tmp10p2 - tmp12p2) * 0.382683433; /* c6 */
var z2p2 = 0.541196100 * tmp10p2 + z5p2; /* c2-c6 */
var z4p2 = 1.306562965 * tmp12p2 + z5p2; /* c2+c6 */
var z3p2 = tmp11p2 * 0.707106781; /* c4 */
var z11p2 = tmp7p2 + z3p2; /* phase 5 */
var z13p2 = tmp7p2 - z3p2;
data[dataOff+40] = z13p2 + z2p2; /* phase 6 */
data[dataOff+24] = z13p2 - z2p2;
data[dataOff+ 8] = z11p2 + z4p2;
data[dataOff+56] = z11p2 - z4p2;
dataOff++; /* advance pointer to next column */
}
// Quantize/descale the coefficients
var fDCTQuant;
for (i=0; i<I64; ++i)
{
// Apply the quantization and scaling factor & Round to nearest integer
fDCTQuant = data[i]*fdtbl[i];
outputfDCTQuant[i] = (fDCTQuant > 0.0) ? ((fDCTQuant + 0.5)|0) : ((fDCTQuant - 0.5)|0);
//outputfDCTQuant[i] = fround(fDCTQuant);
}
return outputfDCTQuant;
}
function writeAPP0()
{
writeWord(0xFFE0); // marker
writeWord(16); // length
writeByte(0x4A); // J
writeByte(0x46); // F
writeByte(0x49); // I
writeByte(0x46); // F
writeByte(0); // = "JFIF",'\0'
writeByte(1); // versionhi
writeByte(1); // versionlo
writeByte(0); // xyunits
writeWord(1); // xdensity
writeWord(1); // ydensity
writeByte(0); // thumbnwidth
writeByte(0); // thumbnheight
}
function writeSOF0(width, height)
{
writeWord(0xFFC0); // marker
writeWord(17); // length, truecolor YUV JPG
writeByte(8); // precision
writeWord(height);
writeWord(width);
writeByte(3); // nrofcomponents
writeByte(1); // IdY
writeByte(0x11); // HVY
writeByte(0); // QTY
writeByte(2); // IdU
writeByte(0x11); // HVU
writeByte(1); // QTU
writeByte(3); // IdV
writeByte(0x11); // HVV
writeByte(1); // QTV
}
function writeDQT()
{
writeWord(0xFFDB); // marker
writeWord(132); // length
writeByte(0);
for (var i=0; i<64; i++) {
writeByte(YTable[i]);
}
writeByte(1);
for (var j=0; j<64; j++) {
writeByte(UVTable[j]);
}
}
function writeDHT()
{
writeWord(0xFFC4); // marker
writeWord(0x01A2); // length
writeByte(0); // HTYDCinfo
for (var i=0; i<16; i++) {
writeByte(std_dc_luminance_nrcodes[i+1]);
}
for (var j=0; j<=11; j++) {
writeByte(std_dc_luminance_values[j]);
}
writeByte(0x10); // HTYACinfo
for (var k=0; k<16; k++) {
writeByte(std_ac_luminance_nrcodes[k+1]);
}
for (var l=0; l<=161; l++) {
writeByte(std_ac_luminance_values[l]);
}
writeByte(1); // HTUDCinfo
for (var m=0; m<16; m++) {
writeByte(std_dc_chrominance_nrcodes[m+1]);
}
for (var n=0; n<=11; n++) {
writeByte(std_dc_chrominance_values[n]);
}
writeByte(0x11); // HTUACinfo
for (var o=0; o<16; o++) {
writeByte(std_ac_chrominance_nrcodes[o+1]);
}
for (var p=0; p<=161; p++) {
writeByte(std_ac_chrominance_values[p]);
}
}
function writeSOS()
{
writeWord(0xFFDA); // marker
writeWord(12); // length
writeByte(3); // nrofcomponents
writeByte(1); // IdY
writeByte(0); // HTY
writeByte(2); // IdU
writeByte(0x11); // HTU
writeByte(3); // IdV
writeByte(0x11); // HTV
writeByte(0); // Ss
writeByte(0x3f); // Se
writeByte(0); // Bf
}
function processDU(CDU, fdtbl, DC, HTDC, HTAC){
var EOB = HTAC[0x00];
var M16zeroes = HTAC[0xF0];
var pos;
var I16 = 16;
var I63 = 63;
var I64 = 64;
var DU_DCT = fDCTQuant(CDU, fdtbl);
//ZigZag reorder
for (var j=0;j<I64;++j) {
DU[ZigZag[j]]=DU_DCT[j];
}
var Diff = DU[0] - DC; DC = DU[0];
//Encode DC
if (Diff==0) {
writeBits(HTDC[0]); // Diff might be 0
} else {
pos = 32767+Diff;
writeBits(HTDC[category[pos]]);
writeBits(bitcode[pos]);
}
//Encode ACs
var end0pos = 63; // was const... which is crazy
for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) {};
//end0pos = first element in reverse order !=0
if ( end0pos == 0) {
writeBits(EOB);
return DC;
}
var i = 1;
var lng;
while ( i <= end0pos ) {
var startpos = i;
for (; (DU[i]==0) && (i<=end0pos); ++i) {}
var nrzeroes = i-startpos;
if ( nrzeroes >= I16 ) {
lng = nrzeroes>>4;
for (var nrmarker=1; nrmarker <= lng; ++nrmarker)
writeBits(M16zeroes);
nrzeroes = nrzeroes&0xF;
}
pos = 32767+DU[i];
writeBits(HTAC[(nrzeroes<<4)+category[pos]]);
writeBits(bitcode[pos]);
i++;
}
if ( end0pos != I63 ) {
writeBits(EOB);
}
return DC;
}
function initCharLookupTable(){
var sfcc = String.fromCharCode;
for(var i=0; i < 256; i++){ ///// ACHTUNG // 255
clt[i] = sfcc(i);
}
}
this.encode = function(image,quality) // image data object
{
// var time_start = new Date().getTime();
if(quality) setQuality(quality);
// Initialize bit writer
byteout = new Array();
bytenew=0;
bytepos=7;
// Add JPEG headers
writeWord(0xFFD8); // SOI
writeAPP0();
writeDQT();
writeSOF0(image.width,image.height);
writeDHT();
writeSOS();
// Encode 8x8 macroblocks
var DCY=0;
var DCU=0;
var DCV=0;
bytenew=0;
bytepos=7;
this.encode.displayName = "_encode_";
var imageData = image.data;
var width = image.width;
var height = image.height;
var quadWidth = width*4;
var tripleWidth = width*3;
var x, y = 0;
var r, g, b;
var start,p, col,row,pos;
while(y < height){
x = 0;
while(x < quadWidth){
start = quadWidth * y + x;
p = start;
col = -1;
row = 0;
for(pos=0; pos < 64; pos++){
row = pos >> 3;// /8
col = ( pos & 7 ) * 4; // %8
p = start + ( row * quadWidth ) + col;
if(y+row >= height){ // padding bottom
p-= (quadWidth*(y+1+row-height));
}
if(x+col >= quadWidth){ // padding right
p-= ((x+col) - quadWidth +4)
}
r = imageData[ p++ ];
g = imageData[ p++ ];
b = imageData[ p++ ];
/* // calculate YUV values dynamically
YDU[pos]=((( 0.29900)*r+( 0.58700)*g+( 0.11400)*b))-128; //-0x80
UDU[pos]=(((-0.16874)*r+(-0.33126)*g+( 0.50000)*b));
VDU[pos]=((( 0.50000)*r+(-0.41869)*g+(-0.08131)*b));
*/
// use lookup table (slightly faster)
YDU[pos] = ((RGB_YUV_TABLE[r] + RGB_YUV_TABLE[(g + 256)>>0] + RGB_YUV_TABLE[(b + 512)>>0]) >> 16)-128;
UDU[pos] = ((RGB_YUV_TABLE[(r + 768)>>0] + RGB_YUV_TABLE[(g + 1024)>>0] + RGB_YUV_TABLE[(b + 1280)>>0]) >> 16)-128;
VDU[pos] = ((RGB_YUV_TABLE[(r + 1280)>>0] + RGB_YUV_TABLE[(g + 1536)>>0] + RGB_YUV_TABLE[(b + 1792)>>0]) >> 16)-128;
}
DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
x+=32;
}
y+=8;
}
////////////////////////////////////////////////////////////////
// Do the bit alignment of the EOI marker
if ( bytepos >= 0 ) {
var fillbits = [];
fillbits[1] = bytepos+1;
fillbits[0] = (1<<(bytepos+1))-1;
writeBits(fillbits);
}
writeWord(0xFFD9); //EOI
var jpegDataUri = 'data:image/jpeg;base64,' + btoa(byteout.join(''));
byteout = [];
// benchmarking
// var duration = new Date().getTime() - time_start;
// console.log('Encoding time: '+ currentQuality + 'ms');
//
return jpegDataUri
}
function setQuality(quality){
if (quality <= 0) {
quality = 1;
}
if (quality > 100) {
quality = 100;
}
if(currentQuality == quality) return // don't recalc if unchanged
var sf = 0;
if (quality < 50) {
sf = Math.floor(5000 / quality);
} else {
sf = Math.floor(200 - quality*2);
}
initQuantTables(sf);
currentQuality = quality;
// console.log('Quality set to: '+quality +'%');
}
function init(){
// var time_start = new Date().getTime();
if(!quality) quality = 50;
// Create tables
initCharLookupTable()
initHuffmanTbl();
initCategoryNumber();
initRGBYUVTable();
setQuality(quality);
// var duration = new Date().getTime() - time_start;
// console.log('Initialization '+ duration + 'ms');
}
init();
};
JPEGEncoder.encode = function( data, quality ) {
var encoder = new JPEGEncoder( quality );
return encoder.encode( data );
}
return JPEGEncoder;
});
+635
View File
@@ -0,0 +1,635 @@
/**
* @fileOverview Transport flash实现
*/
define([
'./runtime'
], function( FlashRuntime ) {
/*
* Fastest md5 implementation around (JKM md5)
* Credits: Joseph Myers
*
* @see http://www.myersdaily.org/joseph/javascript/md5-text.html
* @see http://jsperf.com/md5-shootout/7
*/
/* this function is much faster,
so if possible we use it. Some IEs
are the only ones I know of that
need the idiotic second function,
generated by an if clause. */
var add32 = function (a, b) {
return (a + b) & 0xFFFFFFFF;
},
cmn = function (q, a, b, x, s, t) {
a = add32(add32(a, q), add32(x, t));
return add32((a << s) | (a >>> (32 - s)), b);
},
ff = function (a, b, c, d, x, s, t) {
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
},
gg = function (a, b, c, d, x, s, t) {
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
},
hh = function (a, b, c, d, x, s, t) {
return cmn(b ^ c ^ d, a, b, x, s, t);
},
ii = function (a, b, c, d, x, s, t) {
return cmn(c ^ (b | (~d)), a, b, x, s, t);
},
md5cycle = function (x, k) {
var a = x[0],
b = x[1],
c = x[2],
d = x[3];
a = ff(a, b, c, d, k[0], 7, -680876936);
d = ff(d, a, b, c, k[1], 12, -389564586);
c = ff(c, d, a, b, k[2], 17, 606105819);
b = ff(b, c, d, a, k[3], 22, -1044525330);
a = ff(a, b, c, d, k[4], 7, -176418897);
d = ff(d, a, b, c, k[5], 12, 1200080426);
c = ff(c, d, a, b, k[6], 17, -1473231341);
b = ff(b, c, d, a, k[7], 22, -45705983);
a = ff(a, b, c, d, k[8], 7, 1770035416);
d = ff(d, a, b, c, k[9], 12, -1958414417);
c = ff(c, d, a, b, k[10], 17, -42063);
b = ff(b, c, d, a, k[11], 22, -1990404162);
a = ff(a, b, c, d, k[12], 7, 1804603682);
d = ff(d, a, b, c, k[13], 12, -40341101);
c = ff(c, d, a, b, k[14], 17, -1502002290);
b = ff(b, c, d, a, k[15], 22, 1236535329);
a = gg(a, b, c, d, k[1], 5, -165796510);
d = gg(d, a, b, c, k[6], 9, -1069501632);
c = gg(c, d, a, b, k[11], 14, 643717713);
b = gg(b, c, d, a, k[0], 20, -373897302);
a = gg(a, b, c, d, k[5], 5, -701558691);
d = gg(d, a, b, c, k[10], 9, 38016083);
c = gg(c, d, a, b, k[15], 14, -660478335);
b = gg(b, c, d, a, k[4], 20, -405537848);
a = gg(a, b, c, d, k[9], 5, 568446438);
d = gg(d, a, b, c, k[14], 9, -1019803690);
c = gg(c, d, a, b, k[3], 14, -187363961);
b = gg(b, c, d, a, k[8], 20, 1163531501);
a = gg(a, b, c, d, k[13], 5, -1444681467);
d = gg(d, a, b, c, k[2], 9, -51403784);
c = gg(c, d, a, b, k[7], 14, 1735328473);
b = gg(b, c, d, a, k[12], 20, -1926607734);
a = hh(a, b, c, d, k[5], 4, -378558);
d = hh(d, a, b, c, k[8], 11, -2022574463);
c = hh(c, d, a, b, k[11], 16, 1839030562);
b = hh(b, c, d, a, k[14], 23, -35309556);
a = hh(a, b, c, d, k[1], 4, -1530992060);
d = hh(d, a, b, c, k[4], 11, 1272893353);
c = hh(c, d, a, b, k[7], 16, -155497632);
b = hh(b, c, d, a, k[10], 23, -1094730640);
a = hh(a, b, c, d, k[13], 4, 681279174);
d = hh(d, a, b, c, k[0], 11, -358537222);
c = hh(c, d, a, b, k[3], 16, -722521979);
b = hh(b, c, d, a, k[6], 23, 76029189);
a = hh(a, b, c, d, k[9], 4, -640364487);
d = hh(d, a, b, c, k[12], 11, -421815835);
c = hh(c, d, a, b, k[15], 16, 530742520);
b = hh(b, c, d, a, k[2], 23, -995338651);
a = ii(a, b, c, d, k[0], 6, -198630844);
d = ii(d, a, b, c, k[7], 10, 1126891415);
c = ii(c, d, a, b, k[14], 15, -1416354905);
b = ii(b, c, d, a, k[5], 21, -57434055);
a = ii(a, b, c, d, k[12], 6, 1700485571);
d = ii(d, a, b, c, k[3], 10, -1894986606);
c = ii(c, d, a, b, k[10], 15, -1051523);
b = ii(b, c, d, a, k[1], 21, -2054922799);
a = ii(a, b, c, d, k[8], 6, 1873313359);
d = ii(d, a, b, c, k[15], 10, -30611744);
c = ii(c, d, a, b, k[6], 15, -1560198380);
b = ii(b, c, d, a, k[13], 21, 1309151649);
a = ii(a, b, c, d, k[4], 6, -145523070);
d = ii(d, a, b, c, k[11], 10, -1120210379);
c = ii(c, d, a, b, k[2], 15, 718787259);
b = ii(b, c, d, a, k[9], 21, -343485551);
x[0] = add32(a, x[0]);
x[1] = add32(b, x[1]);
x[2] = add32(c, x[2]);
x[3] = add32(d, x[3]);
},
/* there needs to be support for Unicode here,
* unless we pretend that we can redefine the MD-5
* algorithm for multi-byte characters (perhaps
* by adding every four 16-bit characters and
* shortening the sum to 32 bits). Otherwise
* I suggest performing MD-5 as if every character
* was two bytes--e.g., 0040 0025 = @%--but then
* how will an ordinary MD-5 sum be matched?
* There is no way to standardize text to something
* like UTF-8 before transformation; speed cost is
* utterly prohibitive. The JavaScript standard
* itself needs to look at this: it should start
* providing access to strings as preformed UTF-8
* 8-bit unsigned value arrays.
*/
md5blk = function (s) {
var md5blks = [],
i; /* Andy King said do it this way. */
for (i = 0; i < 64; i += 4) {
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
}
return md5blks;
},
md5blk_array = function (a) {
var md5blks = [],
i; /* Andy King said do it this way. */
for (i = 0; i < 64; i += 4) {
md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
}
return md5blks;
},
md51 = function (s) {
var n = s.length,
state = [1732584193, -271733879, -1732584194, 271733878],
i,
length,
tail,
tmp,
lo,
hi;
for (i = 64; i <= n; i += 64) {
md5cycle(state, md5blk(s.substring(i - 64, i)));
}
s = s.substring(i - 64);
length = s.length;
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
}
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i = 0; i < 16; i += 1) {
tail[i] = 0;
}
}
// Beware that the final length might not fit in 32 bits so we take care of that
tmp = n * 8;
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
lo = parseInt(tmp[2], 16);
hi = parseInt(tmp[1], 16) || 0;
tail[14] = lo;
tail[15] = hi;
md5cycle(state, tail);
return state;
},
md51_array = function (a) {
var n = a.length,
state = [1732584193, -271733879, -1732584194, 271733878],
i,
length,
tail,
tmp,
lo,
hi;
for (i = 64; i <= n; i += 64) {
md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
}
// Not sure if it is a bug, however IE10 will always produce a sub array of length 1
// containing the last element of the parent array if the sub array specified starts
// beyond the length of the parent array - weird.
// https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);
length = a.length;
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= a[i] << ((i % 4) << 3);
}
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i = 0; i < 16; i += 1) {
tail[i] = 0;
}
}
// Beware that the final length might not fit in 32 bits so we take care of that
tmp = n * 8;
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
lo = parseInt(tmp[2], 16);
hi = parseInt(tmp[1], 16) || 0;
tail[14] = lo;
tail[15] = hi;
md5cycle(state, tail);
return state;
},
hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'],
rhex = function (n) {
var s = '',
j;
for (j = 0; j < 4; j += 1) {
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
}
return s;
},
hex = function (x) {
var i;
for (i = 0; i < x.length; i += 1) {
x[i] = rhex(x[i]);
}
return x.join('');
},
md5 = function (s) {
return hex(md51(s));
},
////////////////////////////////////////////////////////////////////////////
/**
* SparkMD5 OOP implementation.
*
* Use this class to perform an incremental md5, otherwise use the
* static methods instead.
*/
SparkMD5 = function () {
// call reset to init the instance
this.reset();
};
// In some cases the fast add32 function cannot be used..
if (md5('hello') !== '5d41402abc4b2a76b9719d911017c592') {
add32 = function (x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF),
msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
};
}
/**
* Appends a string.
* A conversion will be applied if an utf8 string is detected.
*
* @param {String} str The string to be appended
*
* @return {SparkMD5} The instance itself
*/
SparkMD5.prototype.append = function (str) {
// converts the string to utf8 bytes if necessary
if (/[\u0080-\uFFFF]/.test(str)) {
str = unescape(encodeURIComponent(str));
}
// then append as binary
this.appendBinary(str);
return this;
};
/**
* Appends a binary string.
*
* @param {String} contents The binary string to be appended
*
* @return {SparkMD5} The instance itself
*/
SparkMD5.prototype.appendBinary = function (contents) {
this._buff += contents;
this._length += contents.length;
var length = this._buff.length,
i;
for (i = 64; i <= length; i += 64) {
md5cycle(this._state, md5blk(this._buff.substring(i - 64, i)));
}
this._buff = this._buff.substr(i - 64);
return this;
};
/**
* Finishes the incremental computation, reseting the internal state and
* returning the result.
* Use the raw parameter to obtain the raw result instead of the hex one.
*
* @param {Boolean} raw True to get the raw result, false to get the hex result
*
* @return {String|Array} The result
*/
SparkMD5.prototype.end = function (raw) {
var buff = this._buff,
length = buff.length,
i,
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
ret;
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
}
this._finish(tail, length);
ret = !!raw ? this._state : hex(this._state);
this.reset();
return ret;
};
/**
* Finish the final calculation based on the tail.
*
* @param {Array} tail The tail (will be modified)
* @param {Number} length The length of the remaining buffer
*/
SparkMD5.prototype._finish = function (tail, length) {
var i = length,
tmp,
lo,
hi;
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(this._state, tail);
for (i = 0; i < 16; i += 1) {
tail[i] = 0;
}
}
// Do the final computation based on the tail and length
// Beware that the final length may not fit in 32 bits so we take care of that
tmp = this._length * 8;
tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
lo = parseInt(tmp[2], 16);
hi = parseInt(tmp[1], 16) || 0;
tail[14] = lo;
tail[15] = hi;
md5cycle(this._state, tail);
};
/**
* Resets the internal state of the computation.
*
* @return {SparkMD5} The instance itself
*/
SparkMD5.prototype.reset = function () {
this._buff = "";
this._length = 0;
this._state = [1732584193, -271733879, -1732584194, 271733878];
return this;
};
/**
* Releases memory used by the incremental buffer and other aditional
* resources. If you plan to use the instance again, use reset instead.
*/
SparkMD5.prototype.destroy = function () {
delete this._state;
delete this._buff;
delete this._length;
};
/**
* Performs the md5 hash on a string.
* A conversion will be applied if utf8 string is detected.
*
* @param {String} str The string
* @param {Boolean} raw True to get the raw result, false to get the hex result
*
* @return {String|Array} The result
*/
SparkMD5.hash = function (str, raw) {
// converts the string to utf8 bytes if necessary
if (/[\u0080-\uFFFF]/.test(str)) {
str = unescape(encodeURIComponent(str));
}
var hash = md51(str);
return !!raw ? hash : hex(hash);
};
/**
* Performs the md5 hash on a binary string.
*
* @param {String} content The binary string
* @param {Boolean} raw True to get the raw result, false to get the hex result
*
* @return {String|Array} The result
*/
SparkMD5.hashBinary = function (content, raw) {
var hash = md51(content);
return !!raw ? hash : hex(hash);
};
/**
* SparkMD5 OOP implementation for array buffers.
*
* Use this class to perform an incremental md5 ONLY for array buffers.
*/
SparkMD5.ArrayBuffer = function () {
// call reset to init the instance
this.reset();
};
////////////////////////////////////////////////////////////////////////////
/**
* Appends an array buffer.
*
* @param {ArrayBuffer} arr The array to be appended
*
* @return {SparkMD5.ArrayBuffer} The instance itself
*/
SparkMD5.ArrayBuffer.prototype.append = function (arr) {
// TODO: we could avoid the concatenation here but the algorithm would be more complex
// if you find yourself needing extra performance, please make a PR.
var buff = this._concatArrayBuffer(this._buff, arr),
length = buff.length,
i;
this._length += arr.byteLength;
for (i = 64; i <= length; i += 64) {
md5cycle(this._state, md5blk_array(buff.subarray(i - 64, i)));
}
// Avoids IE10 weirdness (documented above)
this._buff = (i - 64) < length ? buff.subarray(i - 64) : new Uint8Array(0);
return this;
};
/**
* Finishes the incremental computation, reseting the internal state and
* returning the result.
* Use the raw parameter to obtain the raw result instead of the hex one.
*
* @param {Boolean} raw True to get the raw result, false to get the hex result
*
* @return {String|Array} The result
*/
SparkMD5.ArrayBuffer.prototype.end = function (raw) {
var buff = this._buff,
length = buff.length,
tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
i,
ret;
for (i = 0; i < length; i += 1) {
tail[i >> 2] |= buff[i] << ((i % 4) << 3);
}
this._finish(tail, length);
ret = !!raw ? this._state : hex(this._state);
this.reset();
return ret;
};
SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
/**
* Resets the internal state of the computation.
*
* @return {SparkMD5.ArrayBuffer} The instance itself
*/
SparkMD5.ArrayBuffer.prototype.reset = function () {
this._buff = new Uint8Array(0);
this._length = 0;
this._state = [1732584193, -271733879, -1732584194, 271733878];
return this;
};
/**
* Releases memory used by the incremental buffer and other aditional
* resources. If you plan to use the instance again, use reset instead.
*/
SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
/**
* Concats two array buffers, returning a new one.
*
* @param {ArrayBuffer} first The first array buffer
* @param {ArrayBuffer} second The second array buffer
*
* @return {ArrayBuffer} The new array buffer
*/
SparkMD5.ArrayBuffer.prototype._concatArrayBuffer = function (first, second) {
var firstLength = first.length,
result = new Uint8Array(firstLength + second.byteLength);
result.set(first);
result.set(new Uint8Array(second), firstLength);
return result;
};
/**
* Performs the md5 hash on an array buffer.
*
* @param {ArrayBuffer} arr The array buffer
* @param {Boolean} raw True to get the raw result, false to get the hex result
*
* @return {String|Array} The result
*/
SparkMD5.ArrayBuffer.hash = function (arr, raw) {
var hash = md51_array(new Uint8Array(arr));
return !!raw ? hash : hex(hash);
};
return FlashRuntime.register( 'Md5', {
init: function() {
// do nothing.
},
loadFromBlob: function( file ) {
var blob = file.getSource(),
chunkSize = 2 * 1024 * 1024,
chunks = Math.ceil( blob.size / chunkSize ),
chunk = 0,
owner = this.owner,
spark = new SparkMD5.ArrayBuffer(),
me = this,
blobSlice = blob.mozSlice || blob.webkitSlice || blob.slice,
loadNext, fr;
fr = new FileReader();
loadNext = function() {
var start, end;
start = chunk * chunkSize;
end = Math.min( start + chunkSize, blob.size );
fr.onload = function( e ) {
spark.append( e.target.result );
owner.trigger( 'progress', {
total: file.size,
loaded: end
});
};
fr.onloadend = function() {
fr.onloadend = fr.onload = null;
if ( ++chunk < chunks ) {
setTimeout( loadNext, 1 );
} else {
setTimeout(function(){
owner.trigger('load');
me.result = spark.end();
loadNext = file = blob = spark = null;
owner.trigger('complete');
}, 50 );
}
};
fr.readAsArrayBuffer( blobSlice.call( blob, start, end ) );
};
loadNext();
},
getResult: function() {
return this.result;
}
});
});
@@ -0,0 +1,71 @@
/**
* @fileOverview Html5Runtime
*/
define([
'../../base',
'../runtime',
'../compbase'
], function( Base, Runtime, CompBase ) {
var type = 'html5',
components = {};
function Html5Runtime() {
var pool = {},
me = this,
destroy = this.destroy;
Runtime.apply( me, arguments );
me.type = type;
// 这个方法的调用者,实际上是RuntimeClient
me.exec = function( comp, fn/*, args...*/) {
var client = this,
uid = client.uid,
args = Base.slice( arguments, 2 ),
instance;
if ( components[ comp ] ) {
instance = pool[ uid ] = pool[ uid ] ||
new components[ comp ]( client, me );
if ( instance[ fn ] ) {
return instance[ fn ].apply( instance, args );
}
}
};
me.destroy = function() {
// @todo 删除池子中的所有实例
return destroy && destroy.apply( this, arguments );
};
}
Base.inherits( Runtime, {
constructor: Html5Runtime,
// 不需要连接其他程序,直接执行callback
init: function() {
var me = this;
setTimeout(function() {
me.trigger('ready');
}, 1 );
}
});
// 注册Components
Html5Runtime.register = function( name, component ) {
var klass = components[ name ] = Base.inherits( CompBase, component );
return klass;
};
// 注册html5运行时。
// 只有在支持的前提下注册。
if ( window.Blob && window.FileReader && window.DataView ) {
Runtime.addRuntime( type, Html5Runtime );
}
return Html5Runtime;
});
@@ -0,0 +1,172 @@
/**
* @fileOverview Transport
* @todo 支持chunked传输,优势:
* 可以将大文件分成小块,挨个传输,可以提高大文件成功率,当失败的时候,也只需要重传那小部分,
* 而不需要重头再传一次。另外断点续传也需要用chunked方式。
*/
define([
'../../base',
'./runtime'
], function( Base, Html5Runtime ) {
var noop = Base.noop,
$ = Base.$;
return Html5Runtime.register( 'Transport', {
init: function() {
this._status = 0;
this._response = null;
},
send: function() {
var owner = this.owner,
opts = this.options,
xhr = this._initAjax(),
blob = owner._blob,
server = opts.server,
formData, binary, fr;
if ( opts.sendAsBinary ) {
server += (/\?/.test( server ) ? '&' : '?') +
$.param( owner._formData );
binary = blob.getSource();
} else {
formData = new FormData();
$.each( owner._formData, function( k, v ) {
formData.append( k, v );
});
formData.append( opts.fileVal, blob.getSource(),
opts.filename || owner._formData.name || '' );
}
if ( opts.withCredentials && 'withCredentials' in xhr ) {
xhr.open( opts.method, server, true );
xhr.withCredentials = true;
} else {
xhr.open( opts.method, server );
}
this._setRequestHeader( xhr, opts.headers );
if ( binary ) {
// 强制设置成 content-type 为文件流。
xhr.overrideMimeType &&
xhr.overrideMimeType('application/octet-stream');
// android直接发送blob会导致服务端接收到的是空文件。
// bug详情。
// https://code.google.com/p/android/issues/detail?id=39882
// 所以先用fileReader读取出来再通过arraybuffer的方式发送。
if ( Base.os.android ) {
fr = new FileReader();
fr.onload = function() {
xhr.send( this.result );
fr = fr.onload = null;
};
fr.readAsArrayBuffer( binary );
} else {
xhr.send( binary );
}
} else {
xhr.send( formData );
}
},
getResponse: function() {
return this._response;
},
getResponseAsJson: function() {
return this._parseJson( this._response );
},
getStatus: function() {
return this._status;
},
abort: function() {
var xhr = this._xhr;
if ( xhr ) {
xhr.upload.onprogress = noop;
xhr.onreadystatechange = noop;
xhr.abort();
this._xhr = xhr = null;
}
},
destroy: function() {
this.abort();
},
_initAjax: function() {
var me = this,
xhr = new XMLHttpRequest(),
opts = this.options;
if ( opts.withCredentials && !('withCredentials' in xhr) &&
typeof XDomainRequest !== 'undefined' ) {
xhr = new XDomainRequest();
}
xhr.upload.onprogress = function( e ) {
var percentage = 0;
if ( e.lengthComputable ) {
percentage = e.loaded / e.total;
}
return me.trigger( 'progress', percentage );
};
xhr.onreadystatechange = function() {
if ( xhr.readyState !== 4 ) {
return;
}
xhr.upload.onprogress = noop;
xhr.onreadystatechange = noop;
me._xhr = null;
me._status = xhr.status;
if ( xhr.status >= 200 && xhr.status < 300 ) {
me._response = xhr.responseText;
return me.trigger('load');
} else if ( xhr.status >= 500 && xhr.status < 600 ) {
me._response = xhr.responseText;
return me.trigger( 'error', 'server-'+status );
}
return me.trigger( 'error', me._status ? 'http-'+status : 'abort' );
};
me._xhr = xhr;
return xhr;
},
_setRequestHeader: function( xhr, headers ) {
$.each( headers, function( key, val ) {
xhr.setRequestHeader( key, val );
});
},
_parseJson: function( str ) {
var json;
try {
json = JSON.parse( str );
} catch ( ex ) {
json = {};
}
return json;
}
});
});
+106
View File
@@ -0,0 +1,106 @@
/**
* Terms:
*
* Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer
* @fileOverview Image控件
*/
define([
'../../base'
], function( Base ) {
var urlAPI = window.createObjectURL && window ||
window.URL && URL.revokeObjectURL && URL ||
window.webkitURL,
createObjectURL = Base.noop,
revokeObjectURL = createObjectURL;
if ( urlAPI ) {
// 更安全的方式调用,比如android里面就能把context改成其他的对象。
createObjectURL = function() {
return urlAPI.createObjectURL.apply( urlAPI, arguments );
};
revokeObjectURL = function() {
return urlAPI.revokeObjectURL.apply( urlAPI, arguments );
};
}
return {
createObjectURL: createObjectURL,
revokeObjectURL: revokeObjectURL,
dataURL2Blob: function( dataURI ) {
var byteStr, intArray, ab, i, mimetype, parts;
parts = dataURI.split(',');
if ( ~parts[ 0 ].indexOf('base64') ) {
byteStr = atob( parts[ 1 ] );
} else {
byteStr = decodeURIComponent( parts[ 1 ] );
}
ab = new ArrayBuffer( byteStr.length );
intArray = new Uint8Array( ab );
for ( i = 0; i < byteStr.length; i++ ) {
intArray[ i ] = byteStr.charCodeAt( i );
}
mimetype = parts[ 0 ].split(':')[ 1 ].split(';')[ 0 ];
return this.arrayBufferToBlob( ab, mimetype );
},
dataURL2ArrayBuffer: function( dataURI ) {
var byteStr, intArray, i, parts;
parts = dataURI.split(',');
if ( ~parts[ 0 ].indexOf('base64') ) {
byteStr = atob( parts[ 1 ] );
} else {
byteStr = decodeURIComponent( parts[ 1 ] );
}
intArray = new Uint8Array( byteStr.length );
for ( i = 0; i < byteStr.length; i++ ) {
intArray[ i ] = byteStr.charCodeAt( i );
}
return intArray.buffer;
},
arrayBufferToBlob: function( buffer, type ) {
var builder = window.BlobBuilder || window.WebKitBlobBuilder,
bb;
// android不支持直接new Blob, 只能借助blobbuilder.
if ( builder ) {
bb = new builder();
bb.append( buffer );
return bb.getBlob( type );
}
return new Blob([ buffer ], type ? { type: type } : {} );
},
// 抽出来主要是为了解决android下面canvas.toDataUrl不支持jpeg.
// 你得到的结果是png.
canvasToDataUrl: function( canvas, type, quality ) {
return canvas.toDataURL( type, quality / 100 );
},
// imagemeat会复写这个方法,如果用户选择加载那个文件了的话。
parseMeta: function( blob, callback ) {
callback( false, {});
},
// imagemeat会复写这个方法,如果用户选择加载那个文件了的话。
updateImageHead: function( data ) {
return data;
}
};
});