feat: add core type definitions

- Device, ImageEntry, Dimensions types
- PipelineConfig with all processing steps
- Built-in pipeline presets (default, high-contrast, etc.)
- Validation constraints and utility functions

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-05-13 18:06:39 -04:00
parent 0cb43607ac
commit 496be2701f

216
src/lib/types.ts Normal file
View File

@@ -0,0 +1,216 @@
// Core type definitions for 2eInk
export type GreyLevel = 2 | 4 | 8 | 16 | 256;
export type OutputFormat = 'png' | 'jpeg';
export type ImageStatus = 'pending' | 'processing' | 'complete' | 'error';
export interface Dimensions {
readonly width: number;
readonly height: number;
}
export interface Device {
readonly id: string;
readonly name: string;
readonly brand: string;
readonly width: number;
readonly height: number;
readonly greyLevels: GreyLevel;
readonly outputFormat: OutputFormat;
}
export interface ImageEntry {
readonly id: string;
readonly file: File;
readonly filename: string;
originalDimensions: Dimensions | null;
originalDataUrl: string | null;
processedBlob: Blob | null;
processedDataUrl: string | null;
status: ImageStatus;
error: string | null;
pipelineOverride: PipelineConfig | null;
}
export interface CustomDeviceFormData {
name: string;
width: number;
height: number;
greyLevels: GreyLevel;
outputFormat: OutputFormat;
}
export const CONSTRAINTS = {
MAX_FILE_SIZE_MB: 25,
MAX_FILE_SIZE_BYTES: 25 * 1024 * 1024,
MIN_DIMENSION: 100,
MAX_DIMENSION: 5000,
MAX_DEVICE_NAME_LENGTH: 50,
SUPPORTED_FORMATS: ['image/jpeg', 'image/png', 'image/webp'],
GREY_LEVEL_OPTIONS: [2, 4, 8, 16, 256],
OUTPUT_FORMAT_OPTIONS: ['png', 'jpeg']
} as const;
export function isSupportedFormat(file: File): boolean {
return CONSTRAINTS.SUPPORTED_FORMATS.includes(
file.type as (typeof CONSTRAINTS.SUPPORTED_FORMATS)[number]
);
}
export function getExtension(format: OutputFormat): string {
return format === 'jpeg' ? 'jpg' : 'png';
}
// Pipeline Configuration
export type CropMode = 'center' | 'top' | 'bottom' | 'manual';
export type ResizeMode = 'cover' | 'contain' | 'stretch';
export type GreyscaleMethod = 'luminosity' | 'average' | 'lightness' | 'red' | 'green' | 'blue';
export type DitherAlgorithm = 'floyd-steinberg' | 'ordered' | 'atkinson';
export interface CropRegion {
x: number;
y: number;
width: number;
height: number;
}
export interface CropConfig {
enabled: boolean;
mode: CropMode;
region?: CropRegion;
}
export interface ResizeConfig {
enabled: boolean;
mode: ResizeMode;
}
export interface BrightnessConfig {
enabled: boolean;
value: number;
}
export interface ContrastConfig {
enabled: boolean;
value: number;
}
export interface GammaConfig {
enabled: boolean;
value: number;
}
export interface AutoLevelsConfig {
enabled: boolean;
clipPercent: number;
}
export interface GreyscaleConfig {
enabled: boolean;
method: GreyscaleMethod;
}
export interface SharpenConfig {
enabled: boolean;
amount: number;
}
export interface QuantizeConfig {
enabled: boolean;
levels: number;
}
export interface DitherConfig {
enabled: boolean;
algorithm: DitherAlgorithm;
}
export interface PipelineConfig {
crop: CropConfig;
resize: ResizeConfig;
brightness: BrightnessConfig;
contrast: ContrastConfig;
gamma: GammaConfig;
autoLevels: AutoLevelsConfig;
greyscale: GreyscaleConfig;
sharpen: SharpenConfig;
quantize: QuantizeConfig;
dither: DitherConfig;
}
export interface PipelinePreset {
id: string;
name: string;
config: PipelineConfig;
isBuiltIn: boolean;
}
export const DEFAULT_PIPELINE_CONFIG: PipelineConfig = {
crop: { enabled: true, mode: 'center' },
resize: { enabled: true, mode: 'cover' },
brightness: { enabled: false, value: 0 },
contrast: { enabled: true, value: 10 },
gamma: { enabled: false, value: 1.0 },
autoLevels: { enabled: false, clipPercent: 0.5 },
greyscale: { enabled: true, method: 'luminosity' },
sharpen: { enabled: false, amount: 0 },
quantize: { enabled: true, levels: 16 },
dither: { enabled: true, algorithm: 'floyd-steinberg' }
};
export const BUILT_IN_PRESETS: PipelinePreset[] = [
{
id: 'default',
name: 'Default',
config: DEFAULT_PIPELINE_CONFIG,
isBuiltIn: true
},
{
id: 'high-contrast',
name: 'High Contrast',
config: {
...DEFAULT_PIPELINE_CONFIG,
contrast: { enabled: true, value: 30 },
brightness: { enabled: true, value: 5 },
gamma: { enabled: true, value: 1.2 }
},
isBuiltIn: true
},
{
id: 'no-dither',
name: 'No Dither',
config: {
...DEFAULT_PIPELINE_CONFIG,
dither: { enabled: false, algorithm: 'floyd-steinberg' },
contrast: { enabled: false, value: 0 },
gamma: { enabled: false, value: 1.0 }
},
isBuiltIn: true
},
{
id: 'photo',
name: 'Photo (256 levels)',
config: {
...DEFAULT_PIPELINE_CONFIG,
quantize: { enabled: false, levels: 256 },
dither: { enabled: false, algorithm: 'floyd-steinberg' },
contrast: { enabled: true, value: 5 },
gamma: { enabled: true, value: 1.05 }
},
isBuiltIn: true
},
{
id: 'atkinson',
name: 'Atkinson Dither',
config: {
...DEFAULT_PIPELINE_CONFIG,
dither: { enabled: true, algorithm: 'atkinson' }
},
isBuiltIn: true
}
];
export function clonePipelineConfig(config: PipelineConfig): PipelineConfig {
return JSON.parse(JSON.stringify(config));
}