Skip to content

Commit b74d95f

Browse files
committed
feat: implement Phase 5.1 media processing foundation
- Add MediaProcessor class with lazy WASM loading - Implement WASM module wrapper with memory management - Create Canvas-based fallback for browsers without WASM - Add browser compatibility detection and strategy selection - Include comprehensive type definitions for media processing - Add 70 tests covering all media processing modules Part of Enhanced S5.js grant Phase 5: Media Processing Foundation
1 parent 4d1305a commit b74d95f

File tree

12 files changed

+1882
-6
lines changed

12 files changed

+1882
-6
lines changed

src/index.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,22 @@ export { JSCryptoImplementation } from './api/crypto/js.js';
1111
export { DirectoryWalker } from './fs/utils/walker.js';
1212
export { BatchOperations } from './fs/utils/batch.js';
1313

14+
// Export media processing classes
15+
export { MediaProcessor } from './media/index.js';
16+
export { CanvasMetadataExtractor } from './media/fallback/canvas.js';
17+
export { WASMModule } from './media/wasm/module.js';
18+
1419
// Export types
15-
export type {
16-
DirV1,
17-
FileRef,
18-
DirRef,
20+
export type {
21+
DirV1,
22+
FileRef,
23+
DirRef,
1924
DirLink,
2025
PutOptions,
2126
GetOptions,
2227
ListOptions,
2328
ListResult,
24-
CursorData
29+
CursorData
2530
} from './fs/dirv1/types.js';
2631

2732
// Export utility types
@@ -35,4 +40,12 @@ export type {
3540
BatchOptions,
3641
BatchProgress,
3742
BatchResult
38-
} from './fs/utils/batch.js';
43+
} from './fs/utils/batch.js';
44+
45+
// Export media types
46+
export type {
47+
ImageMetadata,
48+
MediaOptions,
49+
InitializeOptions,
50+
ImageFormat
51+
} from './media/types.js';

src/media/compat/browser.ts

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/**
2+
* Browser compatibility detection and strategy selection
3+
*/
4+
export class BrowserCompatibility {
5+
/**
6+
* Check if WebAssembly is supported
7+
*/
8+
static hasWebAssembly(): boolean {
9+
return typeof WebAssembly !== 'undefined' &&
10+
typeof WebAssembly.compile === 'function' &&
11+
typeof WebAssembly.instantiate === 'function';
12+
}
13+
14+
/**
15+
* Check if Canvas API is supported
16+
*/
17+
static hasCanvas(): boolean {
18+
if (typeof document === 'undefined') {
19+
return false;
20+
}
21+
22+
try {
23+
const canvas = document.createElement('canvas');
24+
const ctx = canvas.getContext('2d');
25+
return ctx !== null;
26+
} catch {
27+
return false;
28+
}
29+
}
30+
31+
/**
32+
* Check if Image constructor is available
33+
*/
34+
static hasImage(): boolean {
35+
return typeof Image !== 'undefined';
36+
}
37+
38+
/**
39+
* Check if Blob is supported
40+
*/
41+
static hasBlob(): boolean {
42+
return typeof Blob !== 'undefined';
43+
}
44+
45+
/**
46+
* Check if URL.createObjectURL is supported
47+
*/
48+
static hasObjectURL(): boolean {
49+
return typeof URL !== 'undefined' &&
50+
typeof URL.createObjectURL === 'function' &&
51+
typeof URL.revokeObjectURL === 'function';
52+
}
53+
54+
/**
55+
* Select the best strategy based on capabilities
56+
*/
57+
static selectStrategy(options: {
58+
hasWebAssembly?: boolean;
59+
hasCanvas?: boolean;
60+
hasImage?: boolean;
61+
preferredStrategy?: 'wasm' | 'canvas' | 'basic' | 'none';
62+
}): 'wasm' | 'canvas' | 'basic' | 'none' {
63+
const {
64+
hasWebAssembly = this.hasWebAssembly(),
65+
hasCanvas = this.hasCanvas(),
66+
hasImage = this.hasImage(),
67+
preferredStrategy
68+
} = options;
69+
70+
// If a preferred strategy is specified and available, use it
71+
if (preferredStrategy) {
72+
switch (preferredStrategy) {
73+
case 'wasm':
74+
if (hasWebAssembly) return 'wasm';
75+
break;
76+
case 'canvas':
77+
if (hasCanvas && hasImage) return 'canvas';
78+
break;
79+
case 'basic':
80+
if (hasImage) return 'basic';
81+
break;
82+
case 'none':
83+
return 'none';
84+
}
85+
}
86+
87+
// Auto-select based on capabilities
88+
if (hasWebAssembly) {
89+
return 'wasm';
90+
} else if (hasCanvas && hasImage) {
91+
return 'canvas';
92+
} else if (hasImage) {
93+
return 'basic';
94+
} else {
95+
return 'none';
96+
}
97+
}
98+
99+
/**
100+
* Get comprehensive capability report
101+
*/
102+
static checkCapabilities(): CapabilityReport {
103+
const hasWebAssembly = this.hasWebAssembly();
104+
const hasCanvas = this.hasCanvas();
105+
const hasImage = this.hasImage();
106+
const hasBlob = this.hasBlob();
107+
const hasObjectURL = this.hasObjectURL();
108+
109+
const recommendedStrategy = this.selectStrategy({
110+
hasWebAssembly,
111+
hasCanvas,
112+
hasImage
113+
});
114+
115+
return {
116+
hasWebAssembly,
117+
hasCanvas,
118+
hasImage,
119+
hasBlob,
120+
hasObjectURL,
121+
recommendedStrategy
122+
};
123+
}
124+
125+
/**
126+
* Detect browser type
127+
*/
128+
static detectBrowser(): BrowserType {
129+
// Check if we're in Node.js
130+
if (typeof window === 'undefined' && typeof process !== 'undefined') {
131+
return 'node';
132+
}
133+
134+
// Check for browser-specific features
135+
const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : '';
136+
137+
if (userAgent.includes('Chrome') && !userAgent.includes('Edg')) {
138+
return 'chrome';
139+
} else if (userAgent.includes('Firefox')) {
140+
return 'firefox';
141+
} else if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) {
142+
return 'safari';
143+
} else if (userAgent.includes('Edg')) {
144+
return 'edge';
145+
} else {
146+
return 'unknown';
147+
}
148+
}
149+
150+
/**
151+
* Get browser-specific recommendations
152+
*/
153+
static getRecommendations(): string[] {
154+
const browser = this.detectBrowser();
155+
const capabilities = this.checkCapabilities();
156+
const recommendations: string[] = [];
157+
158+
// General recommendations
159+
if (!capabilities.hasWebAssembly) {
160+
recommendations.push('WebAssembly not supported. Using Canvas fallback for image processing.');
161+
}
162+
163+
if (!capabilities.hasCanvas) {
164+
recommendations.push('Canvas API not available. Limited image processing capabilities.');
165+
}
166+
167+
// Browser-specific recommendations
168+
switch (browser) {
169+
case 'safari':
170+
recommendations.push('Safari detected. Some WASM features may have reduced performance.');
171+
break;
172+
case 'firefox':
173+
recommendations.push('Firefox detected. Optimal WASM performance available.');
174+
break;
175+
case 'chrome':
176+
case 'edge':
177+
recommendations.push('Chromium-based browser detected. All features supported.');
178+
break;
179+
case 'node':
180+
recommendations.push('Node.js environment detected. Limited image processing without Canvas libraries.');
181+
break;
182+
}
183+
184+
return recommendations;
185+
}
186+
187+
/**
188+
* Get performance hints based on capabilities
189+
*/
190+
static getPerformanceHints(options?: {
191+
hasWebAssembly?: boolean;
192+
hasCanvas?: boolean;
193+
}): PerformanceHints {
194+
const capabilities = options || this.checkCapabilities();
195+
196+
return {
197+
useWASM: capabilities.hasWebAssembly ?? false,
198+
maxImageSize: capabilities.hasWebAssembly
199+
? 50 * 1024 * 1024 // 50MB with WASM
200+
: 10 * 1024 * 1024, // 10MB with Canvas
201+
cacheStrategy: capabilities.hasWebAssembly ? 'aggressive' : 'conservative',
202+
parallelProcessing: capabilities.hasWebAssembly,
203+
preferredFormats: capabilities.hasWebAssembly
204+
? ['webp', 'jpeg', 'png']
205+
: ['jpeg', 'png']
206+
};
207+
}
208+
}
209+
210+
/**
211+
* Browser type enumeration
212+
*/
213+
export type BrowserType = 'chrome' | 'firefox' | 'safari' | 'edge' | 'node' | 'unknown';
214+
215+
/**
216+
* Capability report interface
217+
*/
218+
export interface CapabilityReport {
219+
hasWebAssembly: boolean;
220+
hasCanvas: boolean;
221+
hasImage: boolean;
222+
hasBlob: boolean;
223+
hasObjectURL: boolean;
224+
recommendedStrategy: 'wasm' | 'canvas' | 'basic' | 'none';
225+
}
226+
227+
/**
228+
* Performance hints interface
229+
*/
230+
export interface PerformanceHints {
231+
useWASM: boolean;
232+
maxImageSize: number;
233+
cacheStrategy: 'aggressive' | 'conservative';
234+
parallelProcessing?: boolean;
235+
preferredFormats?: string[];
236+
}

0 commit comments

Comments
 (0)