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:
216
src/lib/types.ts
Normal file
216
src/lib/types.ts
Normal 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));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user