@blueharford/scrypted-spatial-awareness 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.zip CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueharford/scrypted-spatial-awareness",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Cross-camera object tracking for Scrypted NVR with spatial awareness",
5
5
  "author": "Joshua Seidel <blueharford>",
6
6
  "license": "Apache-2.0",
package/src/main.ts CHANGED
@@ -1054,7 +1054,7 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
1054
1054
  if (!fs.existsSync(filesPath)) {
1055
1055
  fs.mkdirSync(filesPath, { recursive: true });
1056
1056
  }
1057
- return path.join(filesPath, 'floorplan.png');
1057
+ return path.join(filesPath, 'floorplan.jpg');
1058
1058
  }
1059
1059
 
1060
1060
  private async handleFloorPlanRequest(request: HttpRequest, response: HttpResponse): Promise<void> {
@@ -1064,7 +1064,7 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
1064
1064
  this.console.log('Loading floor plan from:', floorPlanPath, 'exists:', fs.existsSync(floorPlanPath));
1065
1065
  if (fs.existsSync(floorPlanPath)) {
1066
1066
  const imageBuffer = fs.readFileSync(floorPlanPath);
1067
- const imageData = 'data:image/png;base64,' + imageBuffer.toString('base64');
1067
+ const imageData = 'data:image/jpeg;base64,' + imageBuffer.toString('base64');
1068
1068
  this.console.log('Floor plan loaded, size:', imageBuffer.length);
1069
1069
  response.send(JSON.stringify({ imageData }), {
1070
1070
  headers: { 'Content-Type': 'application/json' },
@@ -986,25 +986,75 @@ export const EDITOR_HTML = `<!DOCTYPE html>
986
986
 
987
987
  function uploadFloorPlan() { document.getElementById('upload-modal').classList.add('active'); }
988
988
 
989
+ // Compress and resize image to avoid 413 errors
990
+ function compressImage(img, maxSize = 1600, quality = 0.8) {
991
+ return new Promise((resolve) => {
992
+ const canvas = document.createElement('canvas');
993
+ let width = img.width;
994
+ let height = img.height;
995
+
996
+ // Resize if larger than maxSize
997
+ if (width > maxSize || height > maxSize) {
998
+ if (width > height) {
999
+ height = Math.round(height * maxSize / width);
1000
+ width = maxSize;
1001
+ } else {
1002
+ width = Math.round(width * maxSize / height);
1003
+ height = maxSize;
1004
+ }
1005
+ }
1006
+
1007
+ canvas.width = width;
1008
+ canvas.height = height;
1009
+ const ctx = canvas.getContext('2d');
1010
+ ctx.drawImage(img, 0, 0, width, height);
1011
+
1012
+ // Convert to JPEG for better compression
1013
+ const compressed = canvas.toDataURL('image/jpeg', quality);
1014
+ console.log('Compressed image from', img.width, 'x', img.height, 'to', width, 'x', height, 'size:', Math.round(compressed.length / 1024), 'KB');
1015
+ resolve(compressed);
1016
+ });
1017
+ }
1018
+
989
1019
  async function handleFloorPlanUpload(event) {
990
1020
  const file = event.target.files[0];
991
1021
  if (!file) return;
992
1022
  const reader = new FileReader();
993
1023
  reader.onload = async (e) => {
994
- const imageData = e.target.result;
995
- await loadFloorPlanImage(imageData);
996
- // Store floor plan separately via API (not in topology JSON to avoid size issues)
997
- try {
998
- await fetch('../api/floor-plan', {
999
- method: 'POST',
1000
- headers: { 'Content-Type': 'application/json' },
1001
- body: JSON.stringify({ imageData })
1002
- });
1003
- } catch (err) { console.error('Failed to save floor plan:', err); }
1004
- // Store reference in topology (without the large imageData)
1005
- topology.floorPlan = { type: 'uploaded', width: floorPlanImage.width, height: floorPlanImage.height };
1006
- closeModal('upload-modal');
1007
- render();
1024
+ const originalData = e.target.result;
1025
+
1026
+ // Load image to get dimensions
1027
+ const img = new Image();
1028
+ img.onload = async () => {
1029
+ // Compress image to reduce size
1030
+ const imageData = await compressImage(img);
1031
+ await loadFloorPlanImage(imageData);
1032
+
1033
+ // Store floor plan separately via API
1034
+ try {
1035
+ setStatus('Uploading floor plan...', 'warning');
1036
+ const response = await fetch('../api/floor-plan', {
1037
+ method: 'POST',
1038
+ headers: { 'Content-Type': 'application/json' },
1039
+ body: JSON.stringify({ imageData })
1040
+ });
1041
+ if (response.ok) {
1042
+ setStatus('Floor plan saved', 'success');
1043
+ } else {
1044
+ setStatus('Failed to save floor plan: ' + response.status, 'error');
1045
+ console.error('Floor plan upload failed:', response.status, response.statusText);
1046
+ }
1047
+ } catch (err) {
1048
+ console.error('Failed to save floor plan:', err);
1049
+ setStatus('Failed to save floor plan', 'error');
1050
+ }
1051
+
1052
+ // Store reference in topology (without the large imageData)
1053
+ topology.floorPlan = { type: 'uploaded', width: floorPlanImage.width, height: floorPlanImage.height };
1054
+ closeModal('upload-modal');
1055
+ render();
1056
+ };
1057
+ img.src = originalData;
1008
1058
  };
1009
1059
  reader.readAsDataURL(file);
1010
1060
  }