Allow writing image data to separate file to keep it out of memory

pull/1916/head
Martin Boonk 2022-02-27 14:12:54 +01:00
parent 7a62248f6b
commit fbc62eed03
4 changed files with 79 additions and 12 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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",