lightdrift-libraw 1.0.0-alpha.1 → 1.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,853 +0,0 @@
1
- #include "libraw_wrapper.h"
2
- #include <iostream>
3
- #include <sstream>
4
- #include <vector>
5
-
6
- Napi::FunctionReference LibRawWrapper::constructor;
7
-
8
- Napi::Object LibRawWrapper::Init(Napi::Env env, Napi::Object exports) {
9
- Napi::HandleScope scope(env);
10
-
11
- Napi::Function func = DefineClass(env, "LibRawWrapper", {
12
- // File Operations
13
- InstanceMethod("loadFile", &LibRawWrapper::LoadFile),
14
- InstanceMethod("loadBuffer", &LibRawWrapper::LoadBuffer),
15
- InstanceMethod("close", &LibRawWrapper::Close),
16
-
17
- // Metadata & Information
18
- InstanceMethod("getMetadata", &LibRawWrapper::GetMetadata),
19
- InstanceMethod("getImageSize", &LibRawWrapper::GetImageSize),
20
- InstanceMethod("getAdvancedMetadata", &LibRawWrapper::GetAdvancedMetadata),
21
- InstanceMethod("getLensInfo", &LibRawWrapper::GetLensInfo),
22
- InstanceMethod("getColorInfo", &LibRawWrapper::GetColorInfo),
23
-
24
- // Image Processing
25
- InstanceMethod("unpackThumbnail", &LibRawWrapper::UnpackThumbnail),
26
- InstanceMethod("processImage", &LibRawWrapper::ProcessImage),
27
- InstanceMethod("subtractBlack", &LibRawWrapper::SubtractBlack),
28
- InstanceMethod("raw2Image", &LibRawWrapper::Raw2Image),
29
- InstanceMethod("adjustMaximum", &LibRawWrapper::AdjustMaximum),
30
-
31
- // Memory Image Creation
32
- InstanceMethod("createMemoryImage", &LibRawWrapper::CreateMemoryImage),
33
- InstanceMethod("createMemoryThumbnail", &LibRawWrapper::CreateMemoryThumbnail),
34
-
35
- // File Writers
36
- InstanceMethod("writePPM", &LibRawWrapper::WritePPM),
37
- InstanceMethod("writeTIFF", &LibRawWrapper::WriteTIFF),
38
- InstanceMethod("writeThumbnail", &LibRawWrapper::WriteThumbnail),
39
-
40
- // Configuration & Settings
41
- InstanceMethod("setOutputParams", &LibRawWrapper::SetOutputParams),
42
- InstanceMethod("getOutputParams", &LibRawWrapper::GetOutputParams),
43
-
44
- // Utility Functions
45
- InstanceMethod("isFloatingPoint", &LibRawWrapper::IsFloatingPoint),
46
- InstanceMethod("isFujiRotated", &LibRawWrapper::IsFujiRotated),
47
- InstanceMethod("isSRAW", &LibRawWrapper::IsSRAW),
48
- InstanceMethod("isJPEGThumb", &LibRawWrapper::IsJPEGThumb),
49
- InstanceMethod("errorCount", &LibRawWrapper::ErrorCount),
50
-
51
- // Static Methods
52
- StaticMethod("getVersion", &LibRawWrapper::GetVersion),
53
- StaticMethod("getCapabilities", &LibRawWrapper::GetCapabilities),
54
- StaticMethod("getCameraList", &LibRawWrapper::GetCameraList),
55
- StaticMethod("getCameraCount", &LibRawWrapper::GetCameraCount)
56
- });
57
-
58
- constructor = Napi::Persistent(func);
59
- constructor.SuppressDestruct();
60
-
61
- exports.Set("LibRawWrapper", func);
62
- return exports;
63
- }
64
-
65
- LibRawWrapper::LibRawWrapper(const Napi::CallbackInfo& info)
66
- : Napi::ObjectWrap<LibRawWrapper>(info), isLoaded(false), isUnpacked(false), isProcessed(false) {
67
- Napi::Env env = info.Env();
68
- Napi::HandleScope scope(env);
69
-
70
- try {
71
- processor = std::make_unique<LibRaw>();
72
- } catch (const std::exception& e) {
73
- Napi::TypeError::New(env, "Failed to initialize LibRaw").ThrowAsJavaScriptException();
74
- }
75
- }
76
-
77
- LibRawWrapper::~LibRawWrapper() {
78
- if (processor && isLoaded) {
79
- processor->recycle();
80
- }
81
- }
82
-
83
- void LibRawWrapper::CheckLoaded(Napi::Env env) {
84
- if (!isLoaded) {
85
- Napi::Error::New(env, "No file loaded. Call loadFile() first.").ThrowAsJavaScriptException();
86
- }
87
- }
88
-
89
- // ============== FILE OPERATIONS ==============
90
-
91
- Napi::Value LibRawWrapper::LoadFile(const Napi::CallbackInfo& info) {
92
- Napi::Env env = info.Env();
93
-
94
- if (info.Length() < 1 || !info[0].IsString()) {
95
- Napi::TypeError::New(env, "Expected string filename").ThrowAsJavaScriptException();
96
- return env.Null();
97
- }
98
-
99
- std::string filename = info[0].As<Napi::String>().Utf8Value();
100
-
101
- try {
102
- int ret = processor->open_file(filename.c_str());
103
- if (ret != LIBRAW_SUCCESS) {
104
- std::string error = "Failed to open file: ";
105
- error += libraw_strerror(ret);
106
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
107
- return env.Null();
108
- }
109
-
110
- ret = processor->unpack();
111
- if (ret != LIBRAW_SUCCESS) {
112
- std::string error = "Failed to unpack file: ";
113
- error += libraw_strerror(ret);
114
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
115
- return env.Null();
116
- }
117
-
118
- isLoaded = true;
119
- isUnpacked = true;
120
- isProcessed = false;
121
- return Napi::Boolean::New(env, true);
122
- } catch (const std::exception& e) {
123
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
124
- return env.Null();
125
- }
126
- }
127
-
128
- Napi::Value LibRawWrapper::LoadBuffer(const Napi::CallbackInfo& info) {
129
- Napi::Env env = info.Env();
130
-
131
- if (info.Length() < 1 || !info[0].IsBuffer()) {
132
- Napi::TypeError::New(env, "Expected Buffer").ThrowAsJavaScriptException();
133
- return env.Null();
134
- }
135
-
136
- Napi::Buffer<uint8_t> buffer = info[0].As<Napi::Buffer<uint8_t>>();
137
-
138
- try {
139
- int ret = processor->open_buffer(buffer.Data(), buffer.Length());
140
- if (ret != LIBRAW_SUCCESS) {
141
- std::string error = "Failed to open buffer: ";
142
- error += libraw_strerror(ret);
143
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
144
- return env.Null();
145
- }
146
-
147
- ret = processor->unpack();
148
- if (ret != LIBRAW_SUCCESS) {
149
- std::string error = "Failed to unpack buffer: ";
150
- error += libraw_strerror(ret);
151
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
152
- return env.Null();
153
- }
154
-
155
- isLoaded = true;
156
- isUnpacked = true;
157
- isProcessed = false;
158
- return Napi::Boolean::New(env, true);
159
- } catch (const std::exception& e) {
160
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
161
- return env.Null();
162
- }
163
- }
164
-
165
- Napi::Value LibRawWrapper::Close(const Napi::CallbackInfo& info) {
166
- Napi::Env env = info.Env();
167
-
168
- if (processor && isLoaded) {
169
- processor->recycle();
170
- isLoaded = false;
171
- isUnpacked = false;
172
- isProcessed = false;
173
- }
174
-
175
- return Napi::Boolean::New(env, true);
176
- }
177
-
178
- // ============== METADATA & INFORMATION ==============
179
-
180
- Napi::Value LibRawWrapper::GetMetadata(const Napi::CallbackInfo& info) {
181
- Napi::Env env = info.Env();
182
- CheckLoaded(env);
183
-
184
- Napi::Object metadata = Napi::Object::New(env);
185
-
186
- try {
187
- // Camera info
188
- if (processor->imgdata.idata.make[0]) {
189
- metadata.Set("make", Napi::String::New(env, processor->imgdata.idata.make));
190
- }
191
- if (processor->imgdata.idata.model[0]) {
192
- metadata.Set("model", Napi::String::New(env, processor->imgdata.idata.model));
193
- }
194
- if (processor->imgdata.idata.software[0]) {
195
- metadata.Set("software", Napi::String::New(env, processor->imgdata.idata.software));
196
- }
197
-
198
- // Image dimensions
199
- metadata.Set("width", Napi::Number::New(env, processor->imgdata.sizes.width));
200
- metadata.Set("height", Napi::Number::New(env, processor->imgdata.sizes.height));
201
- metadata.Set("rawWidth", Napi::Number::New(env, processor->imgdata.sizes.raw_width));
202
- metadata.Set("rawHeight", Napi::Number::New(env, processor->imgdata.sizes.raw_height));
203
-
204
- // Color info
205
- metadata.Set("colors", Napi::Number::New(env, processor->imgdata.idata.colors));
206
- metadata.Set("filters", Napi::Number::New(env, processor->imgdata.idata.filters));
207
-
208
- // ISO and exposure
209
- if (processor->imgdata.other.iso_speed > 0) {
210
- metadata.Set("iso", Napi::Number::New(env, processor->imgdata.other.iso_speed));
211
- }
212
- if (processor->imgdata.other.shutter > 0) {
213
- metadata.Set("shutterSpeed", Napi::Number::New(env, processor->imgdata.other.shutter));
214
- }
215
- if (processor->imgdata.other.aperture > 0) {
216
- metadata.Set("aperture", Napi::Number::New(env, processor->imgdata.other.aperture));
217
- }
218
- if (processor->imgdata.other.focal_len > 0) {
219
- metadata.Set("focalLength", Napi::Number::New(env, processor->imgdata.other.focal_len));
220
- }
221
-
222
- // Timestamp
223
- if (processor->imgdata.other.timestamp > 0) {
224
- metadata.Set("timestamp", Napi::Number::New(env, processor->imgdata.other.timestamp));
225
- }
226
-
227
- return metadata;
228
- } catch (const std::exception& e) {
229
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
230
- return env.Null();
231
- }
232
- }
233
-
234
- Napi::Value LibRawWrapper::GetImageSize(const Napi::CallbackInfo& info) {
235
- Napi::Env env = info.Env();
236
- CheckLoaded(env);
237
-
238
- Napi::Object size = Napi::Object::New(env);
239
- size.Set("width", Napi::Number::New(env, processor->imgdata.sizes.width));
240
- size.Set("height", Napi::Number::New(env, processor->imgdata.sizes.height));
241
- size.Set("rawWidth", Napi::Number::New(env, processor->imgdata.sizes.raw_width));
242
- size.Set("rawHeight", Napi::Number::New(env, processor->imgdata.sizes.raw_height));
243
- size.Set("topMargin", Napi::Number::New(env, processor->imgdata.sizes.top_margin));
244
- size.Set("leftMargin", Napi::Number::New(env, processor->imgdata.sizes.left_margin));
245
- size.Set("iWidth", Napi::Number::New(env, processor->imgdata.sizes.iwidth));
246
- size.Set("iHeight", Napi::Number::New(env, processor->imgdata.sizes.iheight));
247
-
248
- return size;
249
- }
250
-
251
- Napi::Value LibRawWrapper::GetAdvancedMetadata(const Napi::CallbackInfo& info) {
252
- Napi::Env env = info.Env();
253
- CheckLoaded(env);
254
-
255
- Napi::Object metadata = Napi::Object::New(env);
256
-
257
- try {
258
- // Camera details
259
- if (processor->imgdata.idata.normalized_make[0]) {
260
- metadata.Set("normalizedMake", Napi::String::New(env, processor->imgdata.idata.normalized_make));
261
- }
262
- if (processor->imgdata.idata.normalized_model[0]) {
263
- metadata.Set("normalizedModel", Napi::String::New(env, processor->imgdata.idata.normalized_model));
264
- }
265
-
266
- metadata.Set("rawCount", Napi::Number::New(env, processor->imgdata.idata.raw_count));
267
- metadata.Set("dngVersion", Napi::Number::New(env, processor->imgdata.idata.dng_version));
268
- metadata.Set("is_foveon", Napi::Number::New(env, processor->imgdata.idata.is_foveon));
269
-
270
- // Color matrix and calibration
271
- Napi::Array colorMatrix = Napi::Array::New(env);
272
- for (int i = 0; i < 4; i++) {
273
- Napi::Array row = Napi::Array::New(env);
274
- for (int j = 0; j < 3; j++) {
275
- row.Set(j, Napi::Number::New(env, processor->imgdata.color.cmatrix[i][j]));
276
- }
277
- colorMatrix.Set(i, row);
278
- }
279
- metadata.Set("colorMatrix", colorMatrix);
280
-
281
- // White balance
282
- Napi::Array camMul = Napi::Array::New(env);
283
- for (int i = 0; i < 4; i++) {
284
- camMul.Set(i, Napi::Number::New(env, processor->imgdata.color.cam_mul[i]));
285
- }
286
- metadata.Set("camMul", camMul);
287
-
288
- Napi::Array preMul = Napi::Array::New(env);
289
- for (int i = 0; i < 4; i++) {
290
- preMul.Set(i, Napi::Number::New(env, processor->imgdata.color.pre_mul[i]));
291
- }
292
- metadata.Set("preMul", preMul);
293
-
294
- // Additional sensor info
295
- metadata.Set("blackLevel", Napi::Number::New(env, processor->imgdata.color.black));
296
- metadata.Set("dataMaximum", Napi::Number::New(env, processor->imgdata.color.data_maximum));
297
- metadata.Set("whiteLevel", Napi::Number::New(env, processor->imgdata.color.maximum));
298
-
299
- return metadata;
300
- } catch (const std::exception& e) {
301
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
302
- return env.Null();
303
- }
304
- }
305
-
306
- Napi::Value LibRawWrapper::GetLensInfo(const Napi::CallbackInfo& info) {
307
- Napi::Env env = info.Env();
308
- CheckLoaded(env);
309
-
310
- Napi::Object lensInfo = Napi::Object::New(env);
311
-
312
- try {
313
- if (processor->imgdata.lens.LensID) {
314
- lensInfo.Set("lensID", Napi::Number::New(env, processor->imgdata.lens.LensID));
315
- }
316
- if (processor->imgdata.lens.Lens[0]) {
317
- lensInfo.Set("lensName", Napi::String::New(env, processor->imgdata.lens.Lens));
318
- }
319
- if (processor->imgdata.lens.LensFormat) {
320
- lensInfo.Set("lensFormat", Napi::Number::New(env, processor->imgdata.lens.LensFormat));
321
- }
322
- if (processor->imgdata.lens.LensMount) {
323
- lensInfo.Set("lensMount", Napi::Number::New(env, processor->imgdata.lens.LensMount));
324
- }
325
- if (processor->imgdata.lens.CamID) {
326
- lensInfo.Set("camID", Napi::Number::New(env, processor->imgdata.lens.CamID));
327
- }
328
- if (processor->imgdata.lens.LensFeatures_pre && processor->imgdata.lens.LensFeatures_suf) {
329
- lensInfo.Set("lensFeaturesPre", Napi::String::New(env, processor->imgdata.lens.LensFeatures_pre));
330
- lensInfo.Set("lensFeaturesSuf", Napi::String::New(env, processor->imgdata.lens.LensFeatures_suf));
331
- }
332
-
333
- // Focal length info
334
- if (processor->imgdata.lens.MinFocal > 0) {
335
- lensInfo.Set("minFocal", Napi::Number::New(env, processor->imgdata.lens.MinFocal));
336
- }
337
- if (processor->imgdata.lens.MaxFocal > 0) {
338
- lensInfo.Set("maxFocal", Napi::Number::New(env, processor->imgdata.lens.MaxFocal));
339
- }
340
- if (processor->imgdata.lens.MaxAp4MinFocal > 0) {
341
- lensInfo.Set("maxAp4MinFocal", Napi::Number::New(env, processor->imgdata.lens.MaxAp4MinFocal));
342
- }
343
- if (processor->imgdata.lens.MaxAp4MaxFocal > 0) {
344
- lensInfo.Set("maxAp4MaxFocal", Napi::Number::New(env, processor->imgdata.lens.MaxAp4MaxFocal));
345
- }
346
-
347
- return lensInfo;
348
- } catch (const std::exception& e) {
349
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
350
- return env.Null();
351
- }
352
- }
353
-
354
- Napi::Value LibRawWrapper::GetColorInfo(const Napi::CallbackInfo& info) {
355
- Napi::Env env = info.Env();
356
- CheckLoaded(env);
357
-
358
- Napi::Object colorInfo = Napi::Object::New(env);
359
-
360
- try {
361
- // Basic color info
362
- colorInfo.Set("colors", Napi::Number::New(env, processor->imgdata.idata.colors));
363
- colorInfo.Set("filters", Napi::Number::New(env, processor->imgdata.idata.filters));
364
-
365
- // Color data
366
- colorInfo.Set("blackLevel", Napi::Number::New(env, processor->imgdata.color.black));
367
- colorInfo.Set("dataMaximum", Napi::Number::New(env, processor->imgdata.color.data_maximum));
368
- colorInfo.Set("whiteLevel", Napi::Number::New(env, processor->imgdata.color.maximum));
369
-
370
- // Color profile
371
- if (processor->imgdata.color.profile_length > 0) {
372
- colorInfo.Set("profileLength", Napi::Number::New(env, processor->imgdata.color.profile_length));
373
- }
374
-
375
- // Color matrices
376
- Napi::Array rgbCam = Napi::Array::New(env);
377
- for (int i = 0; i < 3; i++) {
378
- Napi::Array row = Napi::Array::New(env);
379
- for (int j = 0; j < 4; j++) {
380
- row.Set(j, Napi::Number::New(env, processor->imgdata.color.rgb_cam[i][j]));
381
- }
382
- rgbCam.Set(i, row);
383
- }
384
- colorInfo.Set("rgbCam", rgbCam);
385
-
386
- // Camera multipliers
387
- Napi::Array camMul = Napi::Array::New(env);
388
- for (int i = 0; i < 4; i++) {
389
- camMul.Set(i, Napi::Number::New(env, processor->imgdata.color.cam_mul[i]));
390
- }
391
- colorInfo.Set("camMul", camMul);
392
-
393
- return colorInfo;
394
- } catch (const std::exception& e) {
395
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
396
- return env.Null();
397
- }
398
- }
399
-
400
- // ============== IMAGE PROCESSING ==============
401
-
402
- Napi::Value LibRawWrapper::UnpackThumbnail(const Napi::CallbackInfo& info) {
403
- Napi::Env env = info.Env();
404
- CheckLoaded(env);
405
-
406
- try {
407
- int ret = processor->unpack_thumb();
408
- if (ret != LIBRAW_SUCCESS) {
409
- std::string error = "Failed to unpack thumbnail: ";
410
- error += libraw_strerror(ret);
411
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
412
- return env.Null();
413
- }
414
-
415
- return Napi::Boolean::New(env, true);
416
- } catch (const std::exception& e) {
417
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
418
- return env.Null();
419
- }
420
- }
421
-
422
- Napi::Value LibRawWrapper::ProcessImage(const Napi::CallbackInfo& info) {
423
- Napi::Env env = info.Env();
424
- CheckLoaded(env);
425
-
426
- try {
427
- int ret = processor->dcraw_process();
428
- if (ret != LIBRAW_SUCCESS) {
429
- std::string error = "Failed to process image: ";
430
- error += libraw_strerror(ret);
431
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
432
- return env.Null();
433
- }
434
-
435
- isProcessed = true;
436
- return Napi::Boolean::New(env, true);
437
- } catch (const std::exception& e) {
438
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
439
- return env.Null();
440
- }
441
- }
442
-
443
- Napi::Value LibRawWrapper::SubtractBlack(const Napi::CallbackInfo& info) {
444
- Napi::Env env = info.Env();
445
- CheckLoaded(env);
446
-
447
- try {
448
- int ret = processor->subtract_black();
449
- if (ret != LIBRAW_SUCCESS) {
450
- std::string error = "Failed to subtract black: ";
451
- error += libraw_strerror(ret);
452
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
453
- return env.Null();
454
- }
455
-
456
- return Napi::Boolean::New(env, true);
457
- } catch (const std::exception& e) {
458
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
459
- return env.Null();
460
- }
461
- }
462
-
463
- Napi::Value LibRawWrapper::Raw2Image(const Napi::CallbackInfo& info) {
464
- Napi::Env env = info.Env();
465
- CheckLoaded(env);
466
-
467
- try {
468
- int ret = processor->raw2image();
469
- if (ret != LIBRAW_SUCCESS) {
470
- std::string error = "Failed to convert raw to image: ";
471
- error += libraw_strerror(ret);
472
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
473
- return env.Null();
474
- }
475
-
476
- return Napi::Boolean::New(env, true);
477
- } catch (const std::exception& e) {
478
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
479
- return env.Null();
480
- }
481
- }
482
-
483
- Napi::Value LibRawWrapper::AdjustMaximum(const Napi::CallbackInfo& info) {
484
- Napi::Env env = info.Env();
485
- CheckLoaded(env);
486
-
487
- try {
488
- int ret = processor->adjust_maximum();
489
- if (ret != LIBRAW_SUCCESS) {
490
- std::string error = "Failed to adjust maximum: ";
491
- error += libraw_strerror(ret);
492
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
493
- return env.Null();
494
- }
495
-
496
- return Napi::Boolean::New(env, true);
497
- } catch (const std::exception& e) {
498
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
499
- return env.Null();
500
- }
501
- }
502
-
503
- // ============== MEMORY IMAGE CREATION ==============
504
-
505
- Napi::Object LibRawWrapper::CreateImageDataObject(Napi::Env env, libraw_processed_image_t* img) {
506
- Napi::Object result = Napi::Object::New(env);
507
-
508
- if (!img) {
509
- return result;
510
- }
511
-
512
- result.Set("type", Napi::Number::New(env, img->type));
513
- result.Set("height", Napi::Number::New(env, img->height));
514
- result.Set("width", Napi::Number::New(env, img->width));
515
- result.Set("colors", Napi::Number::New(env, img->colors));
516
- result.Set("bits", Napi::Number::New(env, img->bits));
517
- result.Set("dataSize", Napi::Number::New(env, img->data_size));
518
-
519
- // Create buffer with the image data
520
- Napi::Buffer<uint8_t> buffer = Napi::Buffer<uint8_t>::Copy(env, img->data, img->data_size);
521
- result.Set("data", buffer);
522
-
523
- return result;
524
- }
525
-
526
- Napi::Value LibRawWrapper::CreateMemoryImage(const Napi::CallbackInfo& info) {
527
- Napi::Env env = info.Env();
528
- CheckLoaded(env);
529
-
530
- try {
531
- int errcode = 0;
532
- libraw_processed_image_t* img = processor->dcraw_make_mem_image(&errcode);
533
-
534
- if (!img || errcode != LIBRAW_SUCCESS) {
535
- std::string error = "Failed to create memory image: ";
536
- if (errcode != LIBRAW_SUCCESS) {
537
- error += libraw_strerror(errcode);
538
- } else {
539
- error += "Unknown error";
540
- }
541
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
542
- return env.Null();
543
- }
544
-
545
- Napi::Object result = CreateImageDataObject(env, img);
546
- LibRaw::dcraw_clear_mem(img);
547
-
548
- return result;
549
- } catch (const std::exception& e) {
550
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
551
- return env.Null();
552
- }
553
- }
554
-
555
- Napi::Value LibRawWrapper::CreateMemoryThumbnail(const Napi::CallbackInfo& info) {
556
- Napi::Env env = info.Env();
557
- CheckLoaded(env);
558
-
559
- try {
560
- int errcode = 0;
561
- libraw_processed_image_t* img = processor->dcraw_make_mem_thumb(&errcode);
562
-
563
- if (!img || errcode != LIBRAW_SUCCESS) {
564
- std::string error = "Failed to create memory thumbnail: ";
565
- if (errcode != LIBRAW_SUCCESS) {
566
- error += libraw_strerror(errcode);
567
- } else {
568
- error += "Unknown error";
569
- }
570
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
571
- return env.Null();
572
- }
573
-
574
- Napi::Object result = CreateImageDataObject(env, img);
575
- LibRaw::dcraw_clear_mem(img);
576
-
577
- return result;
578
- } catch (const std::exception& e) {
579
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
580
- return env.Null();
581
- }
582
- }
583
-
584
- // ============== FILE WRITERS ==============
585
-
586
- Napi::Value LibRawWrapper::WritePPM(const Napi::CallbackInfo& info) {
587
- Napi::Env env = info.Env();
588
- CheckLoaded(env);
589
-
590
- if (info.Length() < 1 || !info[0].IsString()) {
591
- Napi::TypeError::New(env, "Expected string filename").ThrowAsJavaScriptException();
592
- return env.Null();
593
- }
594
-
595
- std::string filename = info[0].As<Napi::String>().Utf8Value();
596
-
597
- try {
598
- int ret = processor->dcraw_ppm_tiff_writer(filename.c_str());
599
- if (ret != LIBRAW_SUCCESS) {
600
- std::string error = "Failed to write PPM file: ";
601
- error += libraw_strerror(ret);
602
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
603
- return env.Null();
604
- }
605
-
606
- return Napi::Boolean::New(env, true);
607
- } catch (const std::exception& e) {
608
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
609
- return env.Null();
610
- }
611
- }
612
-
613
- Napi::Value LibRawWrapper::WriteTIFF(const Napi::CallbackInfo& info) {
614
- Napi::Env env = info.Env();
615
- CheckLoaded(env);
616
-
617
- if (info.Length() < 1 || !info[0].IsString()) {
618
- Napi::TypeError::New(env, "Expected string filename").ThrowAsJavaScriptException();
619
- return env.Null();
620
- }
621
-
622
- std::string filename = info[0].As<Napi::String>().Utf8Value();
623
-
624
- try {
625
- // Set output format to TIFF
626
- processor->imgdata.params.output_tiff = 1;
627
-
628
- int ret = processor->dcraw_ppm_tiff_writer(filename.c_str());
629
- if (ret != LIBRAW_SUCCESS) {
630
- std::string error = "Failed to write TIFF file: ";
631
- error += libraw_strerror(ret);
632
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
633
- return env.Null();
634
- }
635
-
636
- return Napi::Boolean::New(env, true);
637
- } catch (const std::exception& e) {
638
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
639
- return env.Null();
640
- }
641
- }
642
-
643
- Napi::Value LibRawWrapper::WriteThumbnail(const Napi::CallbackInfo& info) {
644
- Napi::Env env = info.Env();
645
- CheckLoaded(env);
646
-
647
- if (info.Length() < 1 || !info[0].IsString()) {
648
- Napi::TypeError::New(env, "Expected string filename").ThrowAsJavaScriptException();
649
- return env.Null();
650
- }
651
-
652
- std::string filename = info[0].As<Napi::String>().Utf8Value();
653
-
654
- try {
655
- int ret = processor->dcraw_thumb_writer(filename.c_str());
656
- if (ret != LIBRAW_SUCCESS) {
657
- std::string error = "Failed to write thumbnail: ";
658
- error += libraw_strerror(ret);
659
- Napi::Error::New(env, error).ThrowAsJavaScriptException();
660
- return env.Null();
661
- }
662
-
663
- return Napi::Boolean::New(env, true);
664
- } catch (const std::exception& e) {
665
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
666
- return env.Null();
667
- }
668
- }
669
-
670
- // ============== CONFIGURATION & SETTINGS ==============
671
-
672
- Napi::Value LibRawWrapper::SetOutputParams(const Napi::CallbackInfo& info) {
673
- Napi::Env env = info.Env();
674
- CheckLoaded(env);
675
-
676
- if (info.Length() < 1 || !info[0].IsObject()) {
677
- Napi::TypeError::New(env, "Expected object with output parameters").ThrowAsJavaScriptException();
678
- return env.Null();
679
- }
680
-
681
- Napi::Object params = info[0].As<Napi::Object>();
682
-
683
- try {
684
- // Gamma settings
685
- if (params.Has("gamma") && params.Get("gamma").IsArray()) {
686
- Napi::Array gamma = params.Get("gamma").As<Napi::Array>();
687
- if (gamma.Length() >= 2) {
688
- processor->imgdata.params.gamm[0] = gamma.Get(0u).As<Napi::Number>().DoubleValue();
689
- processor->imgdata.params.gamm[1] = gamma.Get(1u).As<Napi::Number>().DoubleValue();
690
- }
691
- }
692
-
693
- // Brightness
694
- if (params.Has("bright") && params.Get("bright").IsNumber()) {
695
- processor->imgdata.params.bright = params.Get("bright").As<Napi::Number>().FloatValue();
696
- }
697
-
698
- // Output color space
699
- if (params.Has("output_color") && params.Get("output_color").IsNumber()) {
700
- processor->imgdata.params.output_color = params.Get("output_color").As<Napi::Number>().Int32Value();
701
- }
702
-
703
- // Output bits per sample
704
- if (params.Has("output_bps") && params.Get("output_bps").IsNumber()) {
705
- processor->imgdata.params.output_bps = params.Get("output_bps").As<Napi::Number>().Int32Value();
706
- }
707
-
708
- // User multipliers
709
- if (params.Has("user_mul") && params.Get("user_mul").IsArray()) {
710
- Napi::Array userMul = params.Get("user_mul").As<Napi::Array>();
711
- for (uint32_t i = 0; i < 4 && i < userMul.Length(); i++) {
712
- processor->imgdata.params.user_mul[i] = userMul.Get(i).As<Napi::Number>().FloatValue();
713
- }
714
- }
715
-
716
- // Auto bright
717
- if (params.Has("no_auto_bright") && params.Get("no_auto_bright").IsBoolean()) {
718
- processor->imgdata.params.no_auto_bright = params.Get("no_auto_bright").As<Napi::Boolean>().Value() ? 1 : 0;
719
- }
720
-
721
- // Highlight mode
722
- if (params.Has("highlight") && params.Get("highlight").IsNumber()) {
723
- processor->imgdata.params.highlight = params.Get("highlight").As<Napi::Number>().Int32Value();
724
- }
725
-
726
- // Output TIFF
727
- if (params.Has("output_tiff") && params.Get("output_tiff").IsBoolean()) {
728
- processor->imgdata.params.output_tiff = params.Get("output_tiff").As<Napi::Boolean>().Value() ? 1 : 0;
729
- }
730
-
731
- return Napi::Boolean::New(env, true);
732
- } catch (const std::exception& e) {
733
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
734
- return env.Null();
735
- }
736
- }
737
-
738
- Napi::Value LibRawWrapper::GetOutputParams(const Napi::CallbackInfo& info) {
739
- Napi::Env env = info.Env();
740
- CheckLoaded(env);
741
-
742
- Napi::Object params = Napi::Object::New(env);
743
-
744
- try {
745
- // Gamma
746
- Napi::Array gamma = Napi::Array::New(env);
747
- gamma.Set(0u, Napi::Number::New(env, processor->imgdata.params.gamm[0]));
748
- gamma.Set(1u, Napi::Number::New(env, processor->imgdata.params.gamm[1]));
749
- params.Set("gamma", gamma);
750
-
751
- // Other parameters
752
- params.Set("bright", Napi::Number::New(env, processor->imgdata.params.bright));
753
- params.Set("output_color", Napi::Number::New(env, processor->imgdata.params.output_color));
754
- params.Set("output_bps", Napi::Number::New(env, processor->imgdata.params.output_bps));
755
- params.Set("no_auto_bright", Napi::Boolean::New(env, processor->imgdata.params.no_auto_bright));
756
- params.Set("highlight", Napi::Number::New(env, processor->imgdata.params.highlight));
757
- params.Set("output_tiff", Napi::Boolean::New(env, processor->imgdata.params.output_tiff));
758
-
759
- // User multipliers
760
- Napi::Array userMul = Napi::Array::New(env);
761
- for (int i = 0; i < 4; i++) {
762
- userMul.Set(i, Napi::Number::New(env, processor->imgdata.params.user_mul[i]));
763
- }
764
- params.Set("user_mul", userMul);
765
-
766
- return params;
767
- } catch (const std::exception& e) {
768
- Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
769
- return env.Null();
770
- }
771
- }
772
-
773
- // ============== UTILITY FUNCTIONS ==============
774
-
775
- Napi::Value LibRawWrapper::IsFloatingPoint(const Napi::CallbackInfo& info) {
776
- Napi::Env env = info.Env();
777
- CheckLoaded(env);
778
-
779
- bool isFloating = processor->is_floating_point();
780
- return Napi::Boolean::New(env, isFloating);
781
- }
782
-
783
- Napi::Value LibRawWrapper::IsFujiRotated(const Napi::CallbackInfo& info) {
784
- Napi::Env env = info.Env();
785
- CheckLoaded(env);
786
-
787
- bool isFuji = processor->is_fuji_rotated();
788
- return Napi::Boolean::New(env, isFuji);
789
- }
790
-
791
- Napi::Value LibRawWrapper::IsSRAW(const Napi::CallbackInfo& info) {
792
- Napi::Env env = info.Env();
793
- CheckLoaded(env);
794
-
795
- bool isSraw = processor->is_sraw();
796
- return Napi::Boolean::New(env, isSraw);
797
- }
798
-
799
- Napi::Value LibRawWrapper::IsJPEGThumb(const Napi::CallbackInfo& info) {
800
- Napi::Env env = info.Env();
801
- CheckLoaded(env);
802
-
803
- bool isJpeg = processor->is_jpeg_thumb();
804
- return Napi::Boolean::New(env, isJpeg);
805
- }
806
-
807
- Napi::Value LibRawWrapper::ErrorCount(const Napi::CallbackInfo& info) {
808
- Napi::Env env = info.Env();
809
- CheckLoaded(env);
810
-
811
- int errors = processor->error_count();
812
- return Napi::Number::New(env, errors);
813
- }
814
-
815
- // ============== STATIC METHODS ==============
816
-
817
- Napi::Value LibRawWrapper::GetVersion(const Napi::CallbackInfo& info) {
818
- Napi::Env env = info.Env();
819
-
820
- const char* version = LibRaw::version();
821
- return Napi::String::New(env, version ? version : "Unknown");
822
- }
823
-
824
- Napi::Value LibRawWrapper::GetCapabilities(const Napi::CallbackInfo& info) {
825
- Napi::Env env = info.Env();
826
-
827
- unsigned int caps = LibRaw::capabilities();
828
- return Napi::Number::New(env, caps);
829
- }
830
-
831
- Napi::Value LibRawWrapper::GetCameraList(const Napi::CallbackInfo& info) {
832
- Napi::Env env = info.Env();
833
-
834
- const char** cameras = LibRaw::cameraList();
835
- Napi::Array result = Napi::Array::New(env);
836
-
837
- if (cameras) {
838
- uint32_t index = 0;
839
- while (cameras[index] != nullptr) {
840
- result.Set(index, Napi::String::New(env, cameras[index]));
841
- index++;
842
- }
843
- }
844
-
845
- return result;
846
- }
847
-
848
- Napi::Value LibRawWrapper::GetCameraCount(const Napi::CallbackInfo& info) {
849
- Napi::Env env = info.Env();
850
-
851
- int count = LibRaw::cameraCount();
852
- return Napi::Number::New(env, count);
853
- }