11-07-2021 08:43
11-07-2021 08:43
Hi,
I'm trying to send an image from settings panel on FitBit app to my app on the FitBit Sense, but I have a problem: I receive the file but I cannot read the content.
This is my code:
app/index.js:
import { inbox } from "file-transfer";
import * as document from "document";
import * as fs from "fs";
let imageShower = document.getElementById("image");
inbox.onnewfile = () => {
let fileName;
while (fileName = inbox.nextFile()) {
if(fileName) {
console.log(`${fileName} onnewfile`);
if(checkForFile(fileName)) {
applySettings(fileName);
}
}
}
};
function applySettings(fileName) {
console.log(`${fileName} start applySettings`);
let buff = fs.readFileSync(fileName, "cbor");
console.log(`content: ${buff}`);
//imageShower.href = "icon.png";
console.log(`${fileName} end applySettings`);
}
function checkForFile(fileName) {
var dirIter;
var listDir = fs.listDirSync("");
while((dirIter = listDir.next()) && !dirIter.done) {
if (dirIter.value === fileName) {
console.log(`fileName: ${dirIter.value}`);
console.log(`bytes: ${fs.statSync(fileName).size}`);
console.log(`exists?: ${fs.existsSync(fileName)}`);
return true;
}
}
return false;
}
companion/index.js:
import { settingsStorage } from "settings";
import { Image } from "image";
import { encode } from "cbor";
import { outbox } from "file-transfer";
settingsStorage.onchange = function(evt) {
if (evt.key === "background-image") {
compressAndTransferImage(evt.newValue);
}
};
function compressAndTransferImage(settingsValue) {
let base64 = "";
const imageData = JSON.parse(settingsValue);
Image.from(imageData.imageUri)
.then(image =>
image.export("image/jpeg", {
background: "#FFFFFF",
quality: 100
})
)
.then(buffer => outbox.enqueue(`${Date.now()}.txt`, encode("{ \"base64\" : \"" + arrayBufferToBase64(buffer) + "\" }")))
//.then(buffer => console.log("{ \"base64\" : \"" + arrayBufferToBase64(buffer) + "\" }"))
.then(fileTransfer => {
console.log(`Enqueued ${fileTransfer.name}`);
});
}
function arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[ i ]);
}
return btoa(binary);
}
function base64ToArrayBuffer(base64) {
var binary_string = atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array( len );
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
settings/index.jsx:
function mySettings(props) {
let screenWidth = 950;
let screenHeight = 950;
return (
<Page>
<ImagePicker
title="Background Image"
description="Pick an image to use as your background."
label="Pick a Background Image"
sublabel="Background image picker"
settingsKey="background-image"
imageWidth={ screenWidth }
imageHeight={ screenHeight }
/>
</Page>
);
}
registerSettingsPage(mySettings);
These are the logs:
11-07-2021 11:37
11-07-2021 11:37
It's possible that you're double-encoding your data. I think the API returns base64-encoded data by default. Have a look here.
11-07-2021 23:31
11-07-2021 23:31
Hi,
i resolved the problem of the empty file, adding "/private/data/" to the path; now I have the base64 on the app: how can I assign ths to the Image on the view? trying .href, .src, .image with no success.
Thank you.
11-07-2021 23:38
11-07-2021 23:38
href.
Your screenWidth and screenHeight may cause issues; the device doesn't like to resize images. Plus, sending over BT is slow, and there's little benefit to sending excess resolution unless you're planning panning.
11-07-2021 23:42
11-07-2021 23:42
Mmm the thing is that if I manually set the image (uploading on resource folder), it works; if the problem was the resize, I would see at least a part of the image, but instead seems that the image does not change.
11-07-2021 23:46
11-07-2021 23:46
Be sure to test on watch rather than sim (watch is more restricted).
Did you investigate the possibility of double-encoding? Checking file sizes might be a clue.
11-07-2021 23:58
11-07-2021 23:58
Yes, I'm using the device, not the simulator; The base64 sent and received are the same.
11-08-2021 00:02
11-08-2021 00:02
Compare file size with the file that you put directly into the resources folder. (This might be an apples-vs-oranges comparison if resizing is involved; try to avoid that.) I still worry that you're base64-encoding a base64-encoded stream.
11-11-2021 00:21
11-11-2021 00:21
The size is the same and the produced base64 (if I put it on a base64 converter) is correct.
It could be a problem utilizing a jpeg? I read in some thread about jpeg to txi conversion.
Thank you.
11-11-2021 00:27
11-11-2021 00:27
JPG doesn't get converted to TXI; only PNG does. However, there are some restrictions on JPG formats (eg, no progressive encoding). But if you can view the image when saved directly to resources, it's okay.
11-11-2021 03:39
11-11-2021 03:39
The problem is that the base64 is correct, but the image is not being showed in the Versa...
11-11-2021 11:53
11-11-2021 11:53
Have you tried setting imageWidth and imageHeight to the exact size of the <image>? The watch doesn't like resizing. If it can't resize something quickly, you'll see nothing rather than a partial image.
I'm still unclear why you're doing your own base64 encoding and decoding. The Fitbit API doesn't require it and the Fitbit example doesn't do it. It could just make the file transfer time slower and introduce another source of bugs.
11-15-2021 23:41
11-15-2021 23:41
Hi,
is there an example project to test and deploy on my Sense? So I'll try and debug how it works.
Thank you.