nativescript-toolbox-sw
Version:
Fork of nativescript-toolbox - A NativeScript module that is a composition of useful classes, tools and helpers.
591 lines (479 loc) • 18.1 kB
JavaScript
// The MIT License (MIT)
//
// Copyright (c) Marcel Joachim Kloubert <marcel.kloubert@gmx.net>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
var Application = require('application');
var BitmapFactoryCommons = require('./BitmapFactory.commons');
var FS = require('file-system');
var ImageSource = require('image-source');
var TypeUtils = require("utils/types");
// default options
var defaultOptions;
function getDefaultOpts() {
return defaultOptions;
}
exports.getDefaultOpts = getDefaultOpts;
function setDefaultOpts(opts) {
defaultOptions = opts;
}
exports.setDefaultOpts = setDefaultOpts;
function AndroidBitmap(bitmap, opts) {
if (!(this instanceof AndroidBitmap)) {
return new AndroidBitmap(bitmap, opts);
}
this._isDisposed = false;
this._nativeObject = bitmap;
this._options = opts;
this._c = new android.graphics.Canvas(bitmap);
}
exports.BitmapClass = AndroidBitmap;
// [ANDROID INTERNAL] __canvas
Object.defineProperty(AndroidBitmap.prototype, '__canvas', {
get: function() { return this._c; }
});
// [ANDROID INTERNAL] __context
Object.defineProperty(AndroidBitmap.prototype, '__context', {
get: function() { return this.android.context; }
});
// [ANDROID INTERNAL] __createPaint()
AndroidBitmap.prototype.__createPaint = function(color) {
var paint = new android.graphics.Paint();
if (!TypeUtils.isNullOrUndefined(color)) {
paint.setARGB(color.a, color.r, color.g, color.b);
}
return paint;
};
// [INTERNAL] _clone()
AndroidBitmap.prototype._clone = function() {
return new AndroidBitmap(this._nativeObject
.copy(this._nativeObject.getConfig(), true));
};
// [INTERNAL] _crop()
AndroidBitmap.prototype._crop = function(leftTop, size) {
return android.graphics.Bitmap.createBitmap(this._nativeObject,
leftTop.x, leftTop.y,
size.width, size.height);
};
// [INTERNAL] _dispose()
AndroidBitmap.prototype._dispose = function(action, tag) {
this._nativeObject.recycle();
};
// [INTERNAL] _drawLine()
AndroidBitmap.prototype._drawLine = function(start, end, color) {
this.__canvas.drawLine(start.x, start.y,
end.x, end.y,
this.__createPaint(color));
};
// [INTERNAL] _drawOval()
AndroidBitmap.prototype._drawOval = function(size, leftTop, color, fillColor) {
var me = this;
var paintLine = this.__createPaint(color);
paintLine.setStyle(android.graphics.Paint.Style.STROKE);
var paints = [];
paints.push(paintLine);
if (null !== fillColor) {
var paintFill = this.__createPaint(fillColor);
paintFill.setStyle(android.graphics.Paint.Style.FILL);
paints.push(paintFill);
}
var drawer = function(r, p) {
me.__canvas.drawOval(r, p);
};
if (size.width == size.height) {
var drawer = function(r, p) {
var radius = (r.right - r.left) / 2.0;
me.__canvas.drawCircle(r.left + radius, r.top + radius,
radius,
p);
};
}
for (var i = paints.length; i > 0; i--) {
var left = leftTop.x;
var top = leftTop.y;
var right = left + size.width - 1;
var bottom = top + size.height - 1;
var rect = new android.graphics.RectF(left, top,
right, bottom);
drawer(rect, paints[i - 1]);
}
};
// [INTERNAL] _drawArc()
AndroidBitmap.prototype._drawArc = function(size, leftTop, startAngle, sweepAngle, color, fillColor) {
var me = this;
var paintLine = this.__createPaint(color);
paintLine.setStyle(android.graphics.Paint.Style.STROKE);
var paints = [];
paints.push(paintLine);
if (null !== fillColor) {
var paintFill = this.__createPaint(fillColor);
paintFill.setStyle(android.graphics.Paint.Style.FILL);
paints.push(paintFill);
}
var drawer = function(r, s, e, u, p) {
me.__canvas.drawArc(r, s, e, u, p);
};
for (var i = paints.length; i > 0; i--) {
var left = leftTop.x;
var top = leftTop.y;
var right = left + size.width - 1;
var bottom = top + size.height - 1;
var rect = new android.graphics.RectF(left, top,
right, bottom);
drawer(rect, startAngle, sweepAngle, true, paints[i - 1]);
}
};
// [INTERNAL] _drawRect()
AndroidBitmap.prototype._drawRect = function(size, leftTop, color, fillColor) {
var paintLine = this.__createPaint(color);
paintLine.setStyle(android.graphics.Paint.Style.STROKE);
var paints = [];
paints.push(paintLine);
if (null !== fillColor) {
var paintFill = this.__createPaint(fillColor);
paintFill.setStyle(android.graphics.Paint.Style.FILL);
paints.push(paintFill);
}
for (var i = paints.length; i > 0; i--) {
var left = leftTop.x;
var top = leftTop.y;
var right = left + size.width - 1;
var bottom = top + size.height - 1;
var rect = new android.graphics.RectF(left, top,
right, bottom);
this.__canvas
.drawRect(rect, paints[i - 1]);
}
};
// [INTERNAL] _getPoint()
AndroidBitmap.prototype._getPoint = function(coordinates) {
return this._nativeObject
.getPixel(coordinates.x, coordinates.y);
};
// [INTERNAL] _insert()
AndroidBitmap.prototype._insert = function(other, leftTop) {
var bmp = asBitmapObject(other);
if (false === bmp) {
throw "NO valid bitmap!";
}
this.__canvas.drawBitmap(bmp._nativeObject,
leftTop.x, leftTop.y,
null);
};
// [INTERNAL] _rotate()
AndroidBitmap.prototype._rotate = function(degrees) {
var matrix = new android.graphics.Matrix();
matrix.postRotate(degrees);
return android.graphics.Bitmap.createBitmap(
this._nativeObject,
0, 0,
this.width, this.height,
matrix,
true
);
};
// [INTERNAL] _resize()
AndroidBitmap.prototype._resize = function(newSize) {
var resizedImage = android.graphics.Bitmap.createScaledBitmap(this._nativeObject,
newSize.width, newSize.height,
false);
return new AndroidBitmap(resizedImage);
};
// [INTERNAL] _setPoint()
AndroidBitmap.prototype._setPoint = function(coordinates, color) {
this._nativeObject
.setPixel(coordinates.x, coordinates.y,
android.graphics.Color.argb(color.a, color.r, color.g, color.b));
};
// _toObject()
AndroidBitmap.prototype._toObject = function(format, quality) {
var bmpFormat;
var mime;
switch (format) {
case 1:
bmpFormat = android.graphics.Bitmap.CompressFormat.PNG;
mime = 'image/png';
break;
case 2:
bmpFormat = android.graphics.Bitmap.CompressFormat.JPEG;
mime = 'image/jpeg';
break;
}
if (TypeUtils.isNullOrUndefined(bmpFormat)) {
throw "Format '" + format + "' is NOT supported!";
}
var stream = new java.io.ByteArrayOutputStream();
try {
this._nativeObject
.compress(bmpFormat, quality, stream);
var bitmapData = {};
var base64 = android.util.Base64.encodeToString(stream.toByteArray(),
android.util.Base64.NO_WRAP);
// base64
Object.defineProperty(bitmapData, 'base64', {
get: function() { return base64; }
});
// mime
Object.defineProperty(bitmapData, 'mime', {
get: function() { return mime; }
});
return bitmapData;
}
finally {
stream.close();
}
}
// _writeText()
AndroidBitmap.prototype._writeText = function(txt, leftTop, font) {
var resources = this.__context.getResources();
var scale = resources.getDisplayMetrics().density;
var antiAlias;
var fontColor;
var fontSize = 10;
var fontName;
if (null !== font) {
fontColor = font.color;
fontSize = font.size;
fontName = font.name;
}
if (TypeUtils.isNullOrUndefined(antiAlias)) {
antiAlias = true;
}
var paint;
if (antiAlias) {
paint = new android.graphics.Paint(android.graphics.Paint.ANTI_ALIAS_FLAG);
}
else {
paint = new android.graphics.Paint();
}
fontColor = this.normalizeColor(fontColor);
if (!TypeUtils.isNullOrUndefined(fontColor)) {
paint.setARGB(fontColor.a, fontColor.r, fontColor.g, fontColor.b);
}
if (!TypeUtils.isNullOrUndefined(fontSize)) {
paint.setTextSize(fontSize * scale);
}
if (!TypeUtils.isNullOrUndefined(fontName)) {
fontName = ('' + fontName).trim();
var typeFace;
if ('' !== fontName) {
// based on code by Nick Iliev (https://github.com/NickIliev)
// s. https://github.com/mkloubert/nativescript-bitmap-factory/issues/7#issuecomment-275691248
try {
var fontAssetPath;
var basePath = FS.path.join(FS.knownFolders.currentApp().path, "fonts", fontName);
if (FS.File.exists(basePath + ".ttf")) {
fontAssetPath = "/fonts/" + fontName + ".ttf";
}
if (fontAssetPath) {
fontAssetPath = FS.path.join(FS.knownFolders.currentApp().path, fontAssetPath);
typeFace = android.graphics.Typeface.createFromFile(fontAssetPath);
}
}
catch (e) {
console.log('[nativescript-bitmap-factory] AndroidBitmap._writeText(): ' + e);
}
if (!typeFace) {
// fallback
typeFace = android.graphics.Typeface.create(fontName, android.graphics.Typeface.NORMAL);
}
}
if (typeFace) {
paint.setTypeface(typeFace);
}
}
paint.setXfermode(new android.graphics.PorterDuffXfermode(android.graphics.PorterDuff.Mode.SRC_OVER));
this.__canvas.drawText(txt,
leftTop.x, leftTop.y,
paint);
};
// height
Object.defineProperty(AndroidBitmap.prototype, 'height', {
get: function() { return this._nativeObject.getHeight(); }
});
// isDisposed
Object.defineProperty(AndroidBitmap.prototype, 'isDisposed', {
get: function() { return this._isDisposed; }
});
// nativeObject
Object.defineProperty(AndroidBitmap.prototype, 'nativeObject', {
get: function() { return this._nativeObject; }
});
// width
Object.defineProperty(AndroidBitmap.prototype, 'width', {
get: function() { return this._nativeObject.getWidth(); }
});
// setup common methods and properties
BitmapFactoryCommons.setupBitmapClass(AndroidBitmap);
function asBitmapObject(v) {
var bmp = BitmapFactoryCommons.tryGetBitmapObject(AndroidBitmap, v);
if (false !== bmp) {
return bmp;
}
var opts = defaultOptions;
if (!opts) {
opts = {};
}
if (typeof v === "string") {
var decodedBytes = android.util.Base64.decode(v, 0);
try {
var options = new android.graphics.BitmapFactory.Options();
options.inMutable = true;
var bmp = android.graphics.BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length,
options);
try {
return new AndroidBitmap(bmp, opts);
}
catch (e) {
bmp.recycle();
bmp = null;
throw e;
}
}
finally {
decodedBytes = null;
}
}
else if (v instanceof android.graphics.Bitmap) {
return new AndroidBitmap(v, opts);
}
else if (v instanceof ImageSource.ImageSource) {
return new AndroidBitmap(v.android, opts);
}
return false;
}
exports.asBitmapObject = asBitmapObject;
AndroidBitmap.asBitmap = asBitmapObject;
function createBitmap(width, height, opts) {
var newBitmap = android.graphics.Bitmap.createBitmap(width, height,
android.graphics.Bitmap.Config.ARGB_8888);
return new AndroidBitmap(newBitmap, opts);
}
exports.createBitmap = createBitmap;
function makeBitmapMutable(bitmap, opts) {
if (bitmap instanceof ImageSource.ImageSource) {
return new makeBitmapMutable(bitmap.android, opts);
}
if (bitmap instanceof AndroidBitmap) {
return new makeBitmapMutable(bitmap.nativeObject, opts);
}
if (!(bitmap instanceof android.graphics.Bitmap)) {
throw "No valid bitmap object!";
}
var ctx = Application.android.context;
var disposeCurrent = false;
if (!TypeUtils.isNullOrUndefined(opts.disposeCurrent)) {
disposeCurrent = opts.disposeCurrent;
}
var customCacheDir;
var stradegy = 1;
if (!TypeUtils.isNullOrUndefined(opts.temp)) {
if (!TypeUtils.isNullOrUndefined(opts.temp.directory)) {
customCacheDir = opts.temp.directory;
}
if (!TypeUtils.isNullOrUndefined(opts.temp.stradegy)) {
stradegy = parseInt(('' + opts.temp.stradegy).trim());
}
}
var mutable;
var disposeOldBitmap = function() {
if (!disposeCurrent) {
return;
}
try {
bitmap.recycle();
bitmap = null;
java.lang.System.gc();
}
catch (e) { /* ignore */ }
};
var createFromTempFile = function(dir) {
if (!dir.exists()) {
throw "'" + dir.getAbsolutePath() + "' does NOT exist!";
}
if (!dir.isDirectory()) {
throw "'" + dir.getAbsolutePath() + "' is no valid directory!";
}
var tempFile = java.io.File.createTempFile("nsbmpfac", "dat", dir);
try {
var randomAccessFile = new java.io.RandomAccessFile(tempFile, "rw");
try {
var width = bitmap.getWidth();
var height = bitmap.getHeight();
var cfg = bitmap.getConfig();
var channel = randomAccessFile.getChannel();
try {
var map = channel.map(java.nio.channels.FileChannel.MapMode.READ_WRITE, 0, bitmap.getRowBytes() * height);
bitmap.copyPixelsToBuffer(map);
disposeOldBitmap();
mutable = android.graphics.Bitmap.createBitmap(width, height, cfg);
map.position(0);
mutable.copyPixelsFromBuffer(map);
}
finally {
channel.close();
}
}
finally {
randomAccessFile.close();
}
}
finally {
try {
tempFile.delete();
}
catch (e) {
try {
tempFile.deleteOnExit();
}
catch (e) { /* ignore */ };
}
}
};
switch (stradegy) {
case 2:
// cache directory
var cacheDir = ctx.getCacheDir();
createFromTempFile(cacheDir);
break;
case 3:
// external cache directory
var extCacheDir = ctx.getExternalCacheDir();
createFromTempFile(extCacheDir);
break;
case 4:
// custom cache directory
var customDir = customCacheDir;
if (TypeUtils.isNullOrUndefined(customDir)) {
customDir = ctx.getCacheDir();
}
if (!(customDir instanceof java.io.File)) {
customDir = new java.io.File('' + customDir);
}
createFromTempFile(customDir);
break;
default:
// memory
mutable = bitmap.copy(bitmap.getConfig(), true);
disposeOldBitmap();
break;
}
return mutable;
}
exports.makeBitmapMutable = makeBitmapMutable;