mirror of https://github.com/espruino/BangleApps
Allow writing image data to separate file to keep it out of memory
parent
7a62248f6b
commit
fbc62eed03
|
@ -1,3 +1,4 @@
|
|||
0.01: New App
|
||||
0.02: Allow drawing polys
|
||||
0.03: Allow partly importing Amazfit decompiler formatted watchfaces
|
||||
0.04: Allow writing all image data to separate file to save some RAM
|
||||
|
|
|
@ -4,29 +4,47 @@ var resources = require("Storage").readJSON("imageclock.resources.json");
|
|||
function prepareImg(resource){
|
||||
//print("prepareImg: ", resource);
|
||||
|
||||
var result = cacheBuffers ? resource : {
|
||||
width: resource.width,
|
||||
height: resource.height,
|
||||
bpp: resource.bpp
|
||||
};
|
||||
if (!cacheBuffers && resource.transparent) result.transparent = resource.transparent;
|
||||
|
||||
if (resource.img){
|
||||
resource.buffer = E.toArrayBuffer(atob(resource.img));
|
||||
resource.img = undefined;
|
||||
//print("buffer from img");
|
||||
result.buffer = E.toArrayBuffer(atob(resource.img));
|
||||
result.img = undefined;
|
||||
} else if (resource.file){
|
||||
resource.buffer = E.toArrayBuffer(atob(require("Storage").read(resource.file)));
|
||||
resource.file = undefined;
|
||||
//print("buffer from file");
|
||||
} else if (resource.compressed){
|
||||
resource.buffer = require("heatshrink").decompress(atob(resource.compressed));
|
||||
resource.compressed = undefined;
|
||||
result.buffer = E.toArrayBuffer(atob(require("Storage").read(resource.file)));
|
||||
result.file = undefined;
|
||||
} else if (resource.compressed && (resource.dataOffset == undefined)){
|
||||
//print("buffer from compressed");
|
||||
result.buffer = require("heatshrink").decompress(atob(resource.compressed));
|
||||
result.compressed = undefined;
|
||||
} else if (resource.buffer){
|
||||
//print("buffer cached");
|
||||
resource.buffer = resource.buffer;
|
||||
} else if (resource.dataOffset !== undefined){
|
||||
//print("buffer from data file");
|
||||
if (resource.compressed){
|
||||
result.buffer = require("heatshrink").decompress(atob(require("Storage").read("imageclock.resources.data", resource.dataOffset, resource.dataLength)));
|
||||
} else {
|
||||
result.buffer = E.toArrayBuffer(atob(require("Storage").read("imageclock.resources.data", resource.dataOffset, resource.dataLength)));
|
||||
}
|
||||
result.compressed = undefined;
|
||||
result.dataOffset = undefined;
|
||||
result.dataLength = undefined;
|
||||
} else {
|
||||
print("Could not get image data for resource", resource);
|
||||
}
|
||||
|
||||
if (resource.paletteData){
|
||||
if (result.paletteData){
|
||||
result.palette = new Uint16Array(resource.paletteData);
|
||||
result.paletteData = undefined;
|
||||
}
|
||||
|
||||
return resource;
|
||||
return result;
|
||||
}
|
||||
|
||||
function getByPath(object, path, lastElem){
|
||||
|
@ -609,6 +627,7 @@ var lockedRedraw = getByPath(face, ["Properties","Redraw","Locked"]) || 60000;
|
|||
var unlockedRedraw = getByPath(face, ["Properties","Redraw","Unlocked"]) || 1000;
|
||||
var defaultRedraw = getByPath(face, ["Properties","Redraw","Default"]) || "Always";
|
||||
var redrawEvents = getByPath(face, ["Properties","Redraw","Events"]);
|
||||
var cacheBuffers = getByPath(face, ["Properties","CacheBuffers"]) || false;
|
||||
var events = getByPath(face, ["Properties","Events"]);
|
||||
|
||||
var stepsgoal = 2000;
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
<label for="useAmazefit">ALPHA: Decompiled Amazfit</label></br>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Options:</br>
|
||||
<input type="checkbox" id="useAmazefit" name="mode" checked/>
|
||||
<label for="useDataFile">Use resource data file (image data not in RAM by default)</label></br>
|
||||
</p>
|
||||
|
||||
<p>Select watchface folder:</br><input type="file" id="fileLoader" name="files[]" multiple directory="" webkitdirectory="" moxdirectory="" /></p>
|
||||
<p><b>or</b></p>
|
||||
<p>Select watchface zip file: </br><input type="file" id="zipLoader" name="zip"/></p><br/>
|
||||
|
@ -38,6 +44,8 @@
|
|||
var resultJson = {};
|
||||
var infoJson;
|
||||
var faceJson;
|
||||
var resourceDataString = "";
|
||||
var resourceDataOffset = 0;
|
||||
var handledFiles = 0;
|
||||
var expectedFiles = 0;
|
||||
var rootZip = new JSZip();
|
||||
|
@ -586,12 +594,22 @@
|
|||
performFileChanges().then(()=>{
|
||||
rootZip.file("face.json", JSON.stringify(faceJson, null, 2));
|
||||
rootZip.file("info.json", JSON.stringify(infoJson, null, 2));
|
||||
|
||||
if (document.getElementById('useDataFile').checked){
|
||||
moveData(resultJson);
|
||||
console.log("Created data file", resourceDataString, resourceDataOffset, resultJson);
|
||||
}
|
||||
document.getElementById('btnSave').disabled = false;
|
||||
document.getElementById('btnSaveFace').disabled = false;
|
||||
document.getElementById('btnSaveZip').disabled = false;
|
||||
document.getElementById('btnUpload').disabled = false;
|
||||
});
|
||||
} else {
|
||||
|
||||
if (true){
|
||||
moveData(resultJson);
|
||||
console.log("Created data file", resourceDataString, resourceDataOffset, resultJson);
|
||||
}
|
||||
document.getElementById('btnSave').disabled = false;
|
||||
document.getElementById('btnSaveFace').disabled = false;
|
||||
document.getElementById('btnUpload').disabled = false;
|
||||
|
@ -706,6 +724,30 @@
|
|||
};
|
||||
document.getElementById('fileLoader').addEventListener('change', handleFileSelect, false);
|
||||
|
||||
function moveData(json){
|
||||
console.log("MoveData for", json);
|
||||
for (var k in json){
|
||||
var c = json[k];
|
||||
if (c.img){
|
||||
var currentData = c.img;
|
||||
delete c.img;
|
||||
c.dataOffset = resourceDataOffset;
|
||||
c.dataLength = currentData.length;
|
||||
resourceDataString += currentData;
|
||||
resourceDataOffset += currentData.length;
|
||||
} else if (c.compressed){
|
||||
var currentData = c.compressed;
|
||||
c.compressed = true;
|
||||
c.dataOffset = resourceDataOffset;
|
||||
c.dataLength = currentData.length;
|
||||
resourceDataString += currentData;
|
||||
resourceDataOffset += currentData.length;
|
||||
} else {
|
||||
moveData(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("btnSave").addEventListener("click", function() {
|
||||
var h = document.createElement('a');
|
||||
h.href = 'data:text/json;charset=utf-8,' + encodeURI(JSON.stringify(resultJson));
|
||||
|
@ -714,6 +756,7 @@
|
|||
h.click();
|
||||
});
|
||||
document.getElementById("btnUpload").addEventListener("click", function() {
|
||||
|
||||
var appDef = {
|
||||
id : "imageclock",
|
||||
storage:[
|
||||
|
@ -723,6 +766,10 @@
|
|||
{name:"imageclock.img", url:"app-icon.js", evaluate:true},
|
||||
]
|
||||
};
|
||||
if (resourceDataString.length > 0){
|
||||
appDef.storage.push({name:"imageclock.resources.data", content: resourceDataString});
|
||||
}
|
||||
|
||||
|
||||
console.log("Uploading app:", appDef);
|
||||
sendCustomizedApp(appDef);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "imageclock",
|
||||
"name": "Imageclock",
|
||||
"shortName": "imageclock",
|
||||
"version": "0.03",
|
||||
"version": "0.04",
|
||||
"type": "clock",
|
||||
"description": "BETA!!! File formats still subject to change --- This app is a highly customizable watchface. To use it, you need to select a watchface. You can build the watchfaces yourself without programming anything. All you need to do is write some json and create image files.",
|
||||
"icon": "app.png",
|
||||
|
|
Loading…
Reference in New Issue