sppoky
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: update crop to ignore screenshare borders

+30 -25
+1 -1
glossa_loop.py
··· 335 335 336 336 img = Image.frombytes("RGBA", (1404, 1872), raw) 337 337 img_rgb = img.convert("RGB") 338 - img_rgb = img_rgb.crop((0, 80, img_rgb.width, img_rgb.height - 200)) 338 + img_rgb = img_rgb.crop((10, 80, img_rgb.width - 10, img_rgb.height - 200)) 339 339 return img_rgb 340 340 341 341
+29 -24
xovi-ext/glossad/glossad.c
··· 69 69 /* Crop parameters (match Python loop) */ 70 70 #define CROP_TOP 80 71 71 #define CROP_BOTTOM 200 72 + #define CROP_LEFT 10 73 + #define CROP_RIGHT 10 72 74 #define CROP_HEIGHT (FB_HEIGHT - CROP_TOP - CROP_BOTTOM) 75 + #define CROP_WIDTH (FB_WIDTH - CROP_LEFT - CROP_RIGHT) 73 76 74 77 /* Influence map constants */ 75 78 #define INFLUENCE_RADIUS 30 /* px around each stroke point */ ··· 92 95 static time_t g_safezone_until = 0; 93 96 static time_t g_last_activity = 0; 94 97 95 - /* Stroke influence map: CROP_HEIGHT x FB_WIDTH, uint8. 98 + /* Stroke influence map: CROP_HEIGHT x CROP_WIDTH, uint8. 96 99 * Tracks known content regions so we can mask them out of the AI crop 97 100 * and detect only genuinely new handwriting. Zeroed at startup, 98 101 * cleared on page turn. */ 99 - static unsigned char g_influence[CROP_HEIGHT][FB_WIDTH]; 102 + static unsigned char g_influence[CROP_HEIGHT][CROP_WIDTH]; 100 103 101 104 /* ─── logging ────────────────────────────────────────────────────── */ 102 105 ··· 251 254 float px = points[i * stride]; 252 255 float py = points[i * stride + 1]; 253 256 254 - /* Convert to crop-space */ 255 - int cx = (int)(px + 702.0f); /* rm x=0 is center, img x=702 is center */ 257 + /* Convert to crop-space (accounting for side margins) */ 258 + int cx = (int)(px + 702.0f) - CROP_LEFT; 256 259 int cy = (int)(py - CROP_TOP); 257 260 258 261 /* Bounding box in crop space, clamped */ 259 262 int x0 = cx - r; if (x0 < 0) x0 = 0; 260 263 int y0 = cy - r; if (y0 < 0) y0 = 0; 261 - int x1 = cx + r; if (x1 >= FB_WIDTH) x1 = FB_WIDTH - 1; 264 + int x1 = cx + r; if (x1 >= CROP_WIDTH) x1 = CROP_WIDTH - 1; 262 265 int y1 = cy + r; if (y1 >= CROP_HEIGHT) y1 = CROP_HEIGHT - 1; 263 266 264 267 for (int y = y0; y <= y1; y++) { ··· 316 319 * regions are blanked to white. Used before saving PNG for the AI. */ 317 320 static void apply_influence_mask(unsigned char *gray_crop) { 318 321 for (int y = 0; y < CROP_HEIGHT; y++) { 319 - for (int x = 0; x < FB_WIDTH; x++) { 322 + for (int x = 0; x < CROP_WIDTH; x++) { 320 323 if (g_influence[y][x] > INFLUENCE_THRESH) 321 - gray_crop[y * FB_WIDTH + x] = 255; 324 + gray_crop[y * CROP_WIDTH + x] = 255; 322 325 } 323 326 } 324 327 } ··· 333 336 for (int y = 0; y < CROP_HEIGHT; y++) { 334 337 int raw_y = y + CROP_TOP; 335 338 const unsigned char *row_ptr = fb + raw_y * FB_WIDTH * FB_BPP; 336 - for (int x = 0; x < FB_WIDTH; x++) { 339 + for (int x = 0; x < CROP_WIDTH; x++) { 337 340 if (g_influence[y][x] > INFLUENCE_THRESH) 338 341 continue; /* known region, skip */ 339 - if (rgba_to_gray(row_ptr + x * FB_BPP) < DARK_THRESHOLD) { 342 + int raw_x = x + CROP_LEFT; 343 + if (rgba_to_gray(row_ptr + raw_x * FB_BPP) < DARK_THRESHOLD) { 340 344 found = 1; 341 345 bottom_crop_y = y; /* keep scanning for lowest */ 342 346 break; /* one dark pixel in this row is enough */ ··· 480 484 } 481 485 482 486 png_init_io(png, fp); 483 - png_set_IHDR(png, info, FB_WIDTH, CROP_HEIGHT, 8, 487 + png_set_IHDR(png, info, CROP_WIDTH, CROP_HEIGHT, 8, 484 488 PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, 485 489 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 486 490 png_write_info(png, info); 487 491 488 492 /* Write row by row, converting RGBA to grayscale with influence mask */ 489 - unsigned char *row_buf = malloc(FB_WIDTH); 493 + unsigned char *row_buf = malloc(CROP_WIDTH); 490 494 if (!row_buf) { 491 495 png_destroy_write_struct(&png, &info); 492 496 fclose(fp); ··· 496 500 for (int y = 0; y < CROP_HEIGHT; y++) { 497 501 int raw_y = y + CROP_TOP; 498 502 const unsigned char *src = fb + raw_y * FB_WIDTH * FB_BPP; 499 - for (int x = 0; x < FB_WIDTH; x++) { 500 - unsigned char gray = rgba_to_gray(src + x * FB_BPP); 503 + for (int x = 0; x < CROP_WIDTH; x++) { 504 + int raw_x = x + CROP_LEFT; 505 + unsigned char gray = rgba_to_gray(src + raw_x * FB_BPP); 501 506 /* Blank out known content regions */ 502 507 if (g_influence[y][x] > INFLUENCE_THRESH) 503 508 gray = 255; ··· 1357 1362 1358 1363 /* 2. Despeckle: build a grayscale crop, remove isolated pixels, 1359 1364 * then use it for both detection and the AI PNG. */ 1360 - unsigned char *crop_gray = malloc(FB_WIDTH * CROP_HEIGHT); 1365 + unsigned char *crop_gray = malloc(CROP_WIDTH * CROP_HEIGHT); 1361 1366 if (!crop_gray) { free(fb); return; } 1362 1367 for (int y = 0; y < CROP_HEIGHT; y++) { 1363 1368 const unsigned char *src = fb + (y + CROP_TOP) * FB_WIDTH * FB_BPP; 1364 - for (int x = 0; x < FB_WIDTH; x++) 1365 - crop_gray[y * FB_WIDTH + x] = rgba_to_gray(src + x * FB_BPP); 1369 + for (int x = 0; x < CROP_WIDTH; x++) 1370 + crop_gray[y * CROP_WIDTH + x] = rgba_to_gray(src + (x + CROP_LEFT) * FB_BPP); 1366 1371 } 1367 - despeckle_crop(crop_gray, FB_WIDTH, CROP_HEIGHT); 1372 + despeckle_crop(crop_gray, CROP_WIDTH, CROP_HEIGHT); 1368 1373 1369 1374 /* 3. Detect new content outside known regions (using despeckled crop) */ 1370 1375 int content_bottom = 0; ··· 1372 1377 int found = 0; 1373 1378 int bottom_y = -1; 1374 1379 for (int y = 0; y < CROP_HEIGHT; y++) { 1375 - for (int x = 0; x < FB_WIDTH; x++) { 1380 + for (int x = 0; x < CROP_WIDTH; x++) { 1376 1381 if (g_influence[y][x] > INFLUENCE_THRESH) continue; 1377 - if (crop_gray[y * FB_WIDTH + x] < DARK_THRESHOLD) { 1382 + if (crop_gray[y * CROP_WIDTH + x] < DARK_THRESHOLD) { 1378 1383 found = 1; 1379 1384 bottom_y = y; 1380 1385 break; ··· 1404 1409 if (!info) { png_destroy_write_struct(&png, NULL); fclose(fp); free(crop_gray); free(fb); return; } 1405 1410 if (setjmp(png_jmpbuf(png))) { png_destroy_write_struct(&png, &info); fclose(fp); free(crop_gray); free(fb); return; } 1406 1411 png_init_io(png, fp); 1407 - png_set_IHDR(png, info, FB_WIDTH, CROP_HEIGHT, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 1412 + png_set_IHDR(png, info, CROP_WIDTH, CROP_HEIGHT, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 1408 1413 png_write_info(png, info); 1409 1414 for (int y = 0; y < CROP_HEIGHT; y++) 1410 - png_write_row(png, crop_gray + y * FB_WIDTH); 1415 + png_write_row(png, crop_gray + y * CROP_WIDTH); 1411 1416 png_write_end(png, NULL); 1412 1417 png_destroy_write_struct(&png, &info); 1413 1418 fclose(fp); ··· 1453 1458 history_add("assistant", answer); 1454 1459 1455 1460 /* 6. Calculate reply Y position */ 1456 - int reply_y = content_bottom + 80 + 60; 1461 + int reply_y = content_bottom + 40; 1457 1462 if (reply_y > 1750) reply_y = 1750; 1458 1463 log_msg("Pipeline: reply_y=%d\n", reply_y); 1459 1464 ··· 1548 1553 /* Start 5s safe zone */ 1549 1554 FILE *sf = fopen(SAFEZONE_PATH, "w"); 1550 1555 if (sf) { fputs("1\n", sf); fclose(sf); } 1551 - g_safezone_until = time(NULL) + 10; 1556 + g_safezone_until = time(NULL) + 4; 1552 1557 g_last_activity = time(NULL); 1553 - log_msg("Safe zone active for 10s\n"); 1558 + log_msg("Safe zone active for 4s\n"); 1554 1559 } else { 1555 1560 unlink(SAFEZONE_PATH); 1556 1561 g_safezone_until = 0;