feat: image pipeline with JPEG decode, resize, and Floyd-Steinberg dithering

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-03 10:56:12 -04:00
parent 458bcc5200
commit c87e3efdc8
4 changed files with 592 additions and 0 deletions

43
src/image_pipeline.h Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
#include <Arduino.h>
#include "config.h"
struct ProcessedImage {
uint8_t* framebuffer; // Palette indices, one byte per pixel
uint16_t width;
uint16_t height;
bool valid;
};
class ImagePipeline {
public:
// Process single landscape photo
ProcessedImage process(uint8_t* jpegData, size_t jpegSize);
// Process portrait pair (two photos side by side)
ProcessedImage processPortraitPair(uint8_t* jpeg1Data, size_t jpeg1Size,
uint8_t* jpeg2Data, size_t jpeg2Size);
void freeImage(ProcessedImage& img);
private:
// Decode JPEG into RGB888 buffer in PSRAM
uint8_t* decodeJpeg(uint8_t* data, size_t size, uint16_t* outWidth, uint16_t* outHeight);
// Resize RGB buffer to target dimensions (bilinear)
uint8_t* resize(uint8_t* rgb, uint16_t srcW, uint16_t srcH,
uint16_t dstW, uint16_t dstH);
// Center-crop to target aspect ratio
void centerCrop(uint8_t* rgb, uint16_t srcW, uint16_t srcH,
uint16_t targetW, uint16_t targetH,
uint16_t* cropX, uint16_t* cropY,
uint16_t* cropW, uint16_t* cropH);
// Floyd-Steinberg dither RGB888 to 6-color palette indices
uint8_t* dither(uint8_t* rgb, uint16_t width, uint16_t height);
// Find nearest palette color
uint8_t findNearest(int r, int g, int b);
};