summaryrefslogtreecommitdiff
path: root/www/js/EventCtrl.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/js/EventCtrl.js')
-rw-r--r--www/js/EventCtrl.js498
1 files changed, 456 insertions, 42 deletions
diff --git a/www/js/EventCtrl.js b/www/js/EventCtrl.js
index 22076b54..3ff6c1ce 100644
--- a/www/js/EventCtrl.js
+++ b/www/js/EventCtrl.js
@@ -1,6 +1,7 @@
/* jshint -W041 */
+/*jshint bitwise: false*/
/* jslint browser: true*/
-/* global saveAs, cordova,StatusBar,angular,console,moment, MobileAccessibility, gifshot, AnimatedGIF , LibraryHelper*/
+/* global saveAs, cordova,StatusBar,angular,console,moment, MobileAccessibility, gifshot, ReadableStream , LibraryHelper, GifWriter, NeuQuant, LocalFileSystem, FileError*/
// This is the controller for Event view. StateParams is if I recall the monitor ID.
// This was before I got access to the new APIs. FIXME: Revisit this code to see what I am doing with it
@@ -116,7 +117,7 @@ angular.module('zmApp.controllers')
//console.log ("********* BEFORE ENTER");
//
- $scope.gifshotSupported = gifshot.isExistingImagesGIFSupported();
+ $scope.gifshotSupported = true;
document.addEventListener("pause", onPause, false);
//console.log("I got STATE PARAM " + $stateParams.id);
$scope.id = parseInt($stateParams.id, 10);
@@ -532,77 +533,218 @@ angular.module('zmApp.controllers')
}
+
+
+
+ function writeFile2( path, file, blob, isAppend)
+ {
+ var csize = 4 * 1024 * 1024; // 4MB
+ var d = $q.defer();
+ NVRDataModel.debug ("Inside writeFile2 with blob size="+blob.size);
+
+ // nothing more to write, so all good?
+ if (!blob.size)
+ {
+ NVRDataModel.debug ("writeFile2 all done");
+ d.resolve(true);
+ return $q.resolve(true);
+ }
+
+
+ if (!isAppend)
+ {
+ // return the delegated promise, even if it fails
+ return $cordovaFile.writeFile(path, file, blob.slice(0,csize), true)
+ .then (function (succ) {
+ return writeFile2(path,file,blob.slice(csize),true);
+ });
+ }
+ else
+ {
+ // return the delegated promise, even if it fails
+ return $cordovaFile.writeExistingFile(path, file, blob.slice(0,csize))
+ .then (function (succ) {
+ return writeFile2(path,file,blob.slice(csize),true);
+ });
+ }
+
+
+ }
+
+ function writeFile(path, __filename, __data){
+ var d = $q.defer();
+ console.log ("inside write file");
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, __data.size+5000, onFileSystemSuccess, fail);
+
+ function fail(e)
+ {
+ var msg = '';
+
+ switch (e.code) {
+ case FileError.QUOTA_EXCEEDED_ERR:
+ msg = 'QUOTA_EXCEEDED_ERR';
+ break;
+ case FileError.NOT_FOUND_ERR:
+ msg = 'NOT_FOUND_ERR';
+ break;
+ case FileError.SECURITY_ERR:
+ msg = 'SECURITY_ERR';
+ break;
+ case FileError.INVALID_MODIFICATION_ERR:
+ msg = 'INVALID_MODIFICATION_ERR';
+ break;
+ case FileError.INVALID_STATE_ERR:
+ msg = 'INVALID_STATE_ERR';
+ break;
+ default:
+ msg = 'Unknown Error';
+ break;
+ }
+
+ console.log('Error: ' + msg);
+ }
+ function onFileSystemSuccess()
+ {
+ console.log ("Got temporary FS");
+ window.resolveLocalFileSystemURL(path, function(dir){
+ dir.getFile(__filename, {create:true}, function(file){
+ file.createWriter(function(fileWriter){
+ //var blob = new Blob([__data], {type:'text/plain'});
+ console.log ("about to write "+__data.size+" bytes");
+ //var blob = new Blob([__data], {type:'text/plain'});
+ fileWriter.write(__data);
+ fileWriter.onwrite = function(e) {
+ NVRDataModel.debug ("write complete");
+ d.resolve();
+ return d.promise;
+ };
+
+ fileWriter.onerror = function(e) {
+ NVRDataModel.debug ("write error in filewriter:"+JSON.stringify(e));
+ d.reject();
+ return d.promise;
+ };
+
+ });
+ });
+
+ },
+ function (err) {
+ d.reject(err);
+ return d.promise;
+ });
+ }
+ return d.promise;
+ }
+
+
+ function moveImageToGallery(fname)
+ {
+ // this is https://github.com/terikon/cordova-plugin-photo-library
+
+ NVRDataModel.debug("moveImageToGallery called with " + fname);
+ cordova.plugins.photoLibrary.saveImage(fname, "zmNinja",onSuccess, onError);
+ //LibraryHelper.saveImageToLibrary(onSuccess, onError, fname, "zmNinja");
+
+ function onSuccess(results)
+ {
+
+ NVRDataModel.debug("Removing temp file");
+
+ if ($rootScope.platformOS == 'ios') {
+ $cordovaFile.removeFile(cordova.file.documentsDirectory, "temp-file.gif");
+ }
+ else
+ $cordovaFile.removeFile(cordova.file.dataDirectory, "temp-file.gif");
+ $ionicLoading.show(
+ {
+ template: $translate.instant('kDone'),
+ noBackdrop: true,
+ duration: 2000
+ });
+
+
+ }
+
+ function onError(error)
+ {
+ console.log("Error: " + error);
+
+ }
+ }
+
$scope.downloadFileToDevice = function(path, eid)
{
-
+
NVRDataModel.setAwake(true);
var tp;
if ($rootScope.platformOS == 'ios')
- tp = cordova.file.documentsDirectory + "temp-video.mp4";
+ tp = cordova.file.documentsDirectory + "temp-video.mp4";
else
tp = cordova.file.dataDirectory + "temp-video.mp4";
var th = true;
var opt = {};
- //path = "http://techslides.com/demos/sample-videos/small.mp4";
+ //path = "http://techslides.com/demos/sample-videos/small.mp4";
- NVRDataModel.debug ("Saving temporary video to: "+tp);
+ NVRDataModel.debug("Saving temporary video to: " + tp);
$cordovaFileTransfer.download(path, tp, opt, th)
.then(function(result)
{
- NVRDataModel.debug ("Moving to gallery...");
- var ntp;
+ NVRDataModel.debug("Moving to gallery...");
+ var ntp;
ntp = tp.indexOf('file://') === 0 ? tp.slice(7) : tp;
- $timeout (function(){$ionicLoading.hide();});
- moveToGallery(ntp,eid+"-video");
+ $timeout(function()
+ {
+ $ionicLoading.hide();
+ });
+ moveToGallery(ntp, eid + "-video");
NVRDataModel.setAwake(false);
// Success!
}, function(err)
{
NVRDataModel.setAwake(false);
- NVRDataModel.log ("Error="+JSON.stringify(err));
-
- $timeout (function() {
+ NVRDataModel.log("Error=" + JSON.stringify(err));
+
+ $timeout(function()
+ {
$ionicLoading.show(
{
template: $translate.instant('kError'),
noBackdrop: true,
- duration:3000
+ duration: 3000
});
- });
+ });
// Error
}, function(progress)
{
var p = Math.round((progress.loaded / progress.total) * 100);
-
- $ionicLoading.show(
- {
- template: $translate.instant('kPleaseWait') + "...(" + p + "%)",
- noBackdrop: true
- });
-
-
+ $ionicLoading.show(
+ {
+
+ template: $translate.instant('kPleaseWait') + "...(" + p + "%)",
+ noBackdrop: true
+ });
+
});
- function moveToGallery(path,fname)
+ function moveToGallery(path, fname)
{
- NVRDataModel.debug ("moveToGallery called with "+path);
+ NVRDataModel.debug("moveToGallery called with " + path);
LibraryHelper.saveVideoToLibrary(onSuccess, onError, path, fname);
-
function onSuccess(results)
{
- NVRDataModel.debug ("Removing temp file");
+ NVRDataModel.debug("Removing temp file");
if ($rootScope.platformOS == 'ios')
$cordovaFile.removeFile(cordova.file.documentsDirectory, "temp-video.mp4");
else
- $cordovaFile.removeFile(cordova.file.dataDirectory, "temp-video.mp4");
-
+ $cordovaFile.removeFile(cordova.file.dataDirectory, "temp-video.mp4");
}
@@ -931,14 +1073,15 @@ angular.module('zmApp.controllers')
//if (1)
{
var rfp = padToN(data.event.Frame[i].FrameId, eventImageDigits) + "-capture.jpg";
- fname = e.Event.baseURL + "/index.php?view=image&width=800&path=" + e.Event.relativePath + rfp;
+ fname = e.Event.baseURL + "/index.php?view=image&width=" + zm.maxGifWidth + "&path=" + e.Event.relativePath + rfp;
}
else
{
- fname = e.Event.baseURL + "/index.php?view=image&width=800&fid=" + data.event.Frame[i].Id;
+ fname = e.Event.baseURL + "/index.php?view=image&width=" + zm.maxGifWidth + "&fid=" + data.event.Frame[i].Id;
}
if (data.event.Frame[i].TimeStamp != lastTime /*|| fps < 2*/ )
+
{
imglist.push(fname);
//fps = data.event.Frame[i].TimeStamp != lastTime ? 0 : fps+1;
@@ -951,17 +1094,18 @@ angular.module('zmApp.controllers')
// next up make sure we are not processing more than 100 images
- while (imglist.length > zm.maxGifCount)
+ while (imglist.length > zm.maxGifCount2)
{
- NVRDataModel.debug("Too many images: " + imglist.length + ", deleting alternate frames to keep it <=" + zm.maxGifCount);
+ NVRDataModel.debug("Too many images: " + imglist.length + ", deleting alternate frames to keep it <=" + zm.maxGifCount2);
for (var l = 0; l < imglist.length; l++)
{
imglist.splice(l + 1, 2);
- if (imglist.length <= zm.maxGifCount) break;
+ if (imglist.length <= zm.maxGifCount2) break;
}
}
+ NVRDataModel.debug("final image list length is:" + imglist.length);
d.resolve(imglist);
return d.promise;
@@ -974,12 +1118,12 @@ angular.module('zmApp.controllers')
return d.promise;
}
- // force image to be 800px. TBD: rotated foo
+ // force image to be of zm.maxGifWidth. TBD: rotated foo
function adjustAspect(e)
{
- var w = 800;
- var h = Math.round(e.Event.Height / e.Event.Width * 800.0);
+ var w = zm.maxGifWidth;
+ var h = Math.round(e.Event.Height / e.Event.Width * zm.maxGifWidth);
return {
w: w,
h: h
@@ -987,6 +1131,7 @@ angular.module('zmApp.controllers')
}
+ // for devices - handle permission before you download
$scope.permissionsDownload = function(e)
{
if ($rootScope.platformOS == 'desktop')
@@ -1031,16 +1176,285 @@ angular.module('zmApp.controllers')
}
};
+ // make sure the user knows the GIF is not full fps/all frames
function gifAlert(e)
{
- $ionicPopup.alert(
+ if(navigator.userAgent.toLowerCase().indexOf('crosswalk') == -1) {
+ $ionicPopup.confirm(
+ {
+ title: $translate.instant('kNote'),
+ template: "{{'kGifWarning' | translate }}"
+ }).then(function(res)
+ {
+ if (res)
+ {
+ downloadAsGif2(e);
+ }
+ else
+ NVRDataModel.debug ("User cancelled GIF");
+
+ });
+ }
+ else
{
- title: $translate.instant('kNote'),
- template: "{{'kGifWarning' | translate }}"
- }).then(function(){downloadAsGif(e);});
-
+ $ionicPopup.alert({
+ title:$translate.instant ('kNote'),
+ template:"{{'kGifNoCrosswalk' | translate}}"
+ });
+ }
+
+
+ }
+
+ // convert to base64 - devices need this to save to gallery
+ function blobToBase64(blob)
+ {
+ NVRDataModel.debug("converting blob to base64...");
+ var d = $q.defer();
+ var reader = new window.FileReader();
+ reader.readAsDataURL(blob);
+ reader.onloadend = function()
+ {
+ var base64data = reader.result;
+ //console.log(base64data );
+ d.resolve(base64data);
+ return d.promise;
+
+ };
+ return d.promise;
+ }
+
+ // part of neuquant conversion
+ function componentizedPaletteToArray(paletteRGB)
+ {
+ var paletteArray = [],
+ i, r, g, b;
+ for (i = 0; i < paletteRGB.length; i += 3)
+ {
+ r = paletteRGB[i];
+ g = paletteRGB[i + 1];
+ b = paletteRGB[i + 2];
+ paletteArray.push(r << 16 | g << 8 | b);
+ }
+ return paletteArray;
+ }
+
+ // part of neuquant conversion
+ function dataToRGB(data, width, height)
+ {
+ var i = 0,
+ length = width * height * 4,
+ rgb = [];
+ while (i < length)
+ {
+ rgb.push(data[i++]);
+ rgb.push(data[i++]);
+ rgb.push(data[i++]);
+ i++;
+ }
+ return rgb;
+ }
+
+ // credit Jimmy Warting
+ // https://github.com/jimmywarting/StreamSaver.js/issues/38
+ // he stream-ized and cleaned up the gif creation process
+ // using GifWriter.js
+ function createGif(files, w, h)
+ {
+
+ var cv = document.getElementById("canvas");
+ var ctx = cv.getContext("2d");
+ var pixels = new Uint8Array(w * h);
+ var totalImages = files.length;
+ var processedImages = 0;
+
+ cv.width = w;
+ cv.height = h;
+
+ var rs = new ReadableStream(
+ {
+ // Each time pull gets called you should get the pixel data and
+ // enqueue it as if it would be good old gif.addFrame()
+ pull: function pull(controller)
+ {
+ var frame = files.shift();
+ if (!frame) {controller.close(); return;}
+
+ return $http(
+ {
+ url: frame,
+ responseType: "blob"
+ })
+ .then(function(res)
+ {
+
+ return res.data.image();
+ })
+ .then(function(img)
+ {
+ processedImages++;
+
+ var p = Math.round(processedImages / totalImages * 100);
+ $ionicLoading.show(
+ {
+ template: $translate.instant('kPleaseWait') + "...(" + p + "%)",
+ noBackdrop: true
+ });
+
+ console.log("URL=" + frame);
+ URL.revokeObjectURL(img.src);
+ ctx.drawImage(img, 0, 0);
+
+ var data = ctx.getImageData(0, 0, w, h).data;
+ var rgbComponents = dataToRGB(data, w, h);
+ var nq = new NeuQuant(rgbComponents, rgbComponents.length, 15);
+ var paletteRGB = nq.process();
+ var paletteArray = new Uint32Array(componentizedPaletteToArray(paletteRGB));
+ var numberPixels = w * h;
+ var k = 0,
+ i, r, g, b;
+
+ for (i = 0; i < numberPixels; i++)
+ {
+ r = rgbComponents[k++];
+ g = rgbComponents[k++];
+ b = rgbComponents[k++];
+ pixels[i] = nq.map(r, g, b);
+ }
+
+ controller.enqueue([0, 0, w, h, pixels,
+ {
+ palette: paletteArray,
+ delay: 100, // 1 second
+ }]);
+ });
+ }
+ });
+
+ return new GifWriter(rs, w, h,
+ {
+ loop: null
+ });
+ }
+
+
+
+ function downloadAsGif2(e)
+ {
+ $rootScope.isDownloading = true;
+ $ionicLoading.show(
+ {
+ template: $translate.instant('kPleaseWait') + "...",
+ noBackdrop: true,
+ duration: 20000
+ });
+ NVRDataModel.setAwake(true);
+
+ prepareImages(e)
+ .then(function(files)
+ {
+ return $http(
+ {
+ url: files[0],
+ responseType: "blob"
+ })
+ .then(function(res)
+ {
+ return res.data.image();
+ })
+ .then(function(img)
+ {
+ URL.revokeObjectURL(img.src); // Revoke object URL to free memory
+ var stream = createGif(files, img.width, img.height);
+ //var fileStream = streamSaver.createWriteStream('image.gif');
+
+ var chunks = [];
+ var reader = stream.getReader();
+
+ function pull()
+ {
+ return reader.read().then(function(result)
+ {
+ chunks.push(result.value);
+ return result.done ? chunks : pull();
+ });
+ }
+
+ pull().then(function(chunks)
+ {
+ var blob = new Blob(chunks,
+ {
+ type: "image/gif"
+
+ });
+
+ //alert ("WE ARE DONE!");
+ if ($rootScope.platformOS == 'desktop')
+ {
+ saveAs(blob, e.Event.Id + "-video.gif");
+ $ionicLoading.hide();
+ }
+ else
+ {
+ // write blob to file
+ var tp;
+ if ($rootScope.platformOS == 'ios')
+ tp = cordova.file.documentsDirectory;
+ else
+ tp = cordova.file.dataDirectory;
+ var th = true, opt = {};
+
+ $ionicLoading.show(
+ {
+
+ template:"writing to file...",
+ noBackdrop: true,
+ });
+
+ //var bloburl = URL.createObjectURL(blob);
+ //NVRDataModel.debug ("blob-url is:"+bloburl);
+
+ writeFile2(tp,"temp-file.gif",blob,false)
+ .then (function (succ) {
+ NVRDataModel.debug ("write to file successful");
+ console.log( "write file successful");
+ $ionicLoading.hide();
+
+ var ntp = tp;
+ //ntp = tp.indexOf('file://') === 0 ? tp.slice(7) : tp;
+
+ ntp = ntp+"temp-file.gif";
+ console.log ("ntp="+ntp);
+
+ moveImageToGallery(ntp);
+ $rootScope.isDownloading = false;
+
+ }, function (err) {
+ $rootScope.isDownloading = false;
+ $ionicLoading.hide();
+ NVRDataModel.debug ("error writing to file "+JSON.stringify(err));
+
+
+ });
+ }
+
+ });
+ });
+
+ },
+ function(err)
+ {
+ $ionicLoading.hide();
+ NVRDataModel.setAwake(false);
+ NVRDataModel.log("Error getting frames");
+ $rootScope.isDownloading = false;
+ }
+
+ );
+
}
+ // NOT USED - WILL REMOVE AFTER TESTING OTHER METHOD MORE
function downloadAsGif(e)
{
$ionicLoading.show(