roxify 1.7.6 → 1.8.1

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.
package/native/lib.rs ADDED
@@ -0,0 +1,464 @@
1
+ #![allow(dead_code, unused_imports)]
2
+ use napi::bindgen_prelude::*;
3
+ use napi_derive::napi;
4
+
5
+ #[global_allocator]
6
+ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
7
+
8
+ mod core;
9
+ #[cfg(feature = "gpu")]
10
+ mod gpu;
11
+ mod rans;
12
+ mod bwt;
13
+ mod context_mixing;
14
+ mod pool;
15
+ mod hybrid;
16
+ mod encoder;
17
+ mod packer;
18
+ mod crypto;
19
+ mod png_utils;
20
+ mod image_utils;
21
+ mod audio;
22
+ mod progress;
23
+ mod reconstitution;
24
+ mod archive;
25
+
26
+ pub use core::*;
27
+ #[cfg(feature = "gpu")]
28
+ pub use gpu::*;
29
+ #[cfg(not(feature = "gpu"))]
30
+ mod gpu {
31
+ pub fn gpu_available() -> bool {
32
+ false
33
+ }
34
+ }
35
+
36
+ pub use rans::*;
37
+ pub use bwt::*;
38
+ pub use context_mixing::*;
39
+ pub use pool::*;
40
+ pub use hybrid::*;
41
+
42
+ #[napi(object)]
43
+ pub struct ScanResult {
44
+ pub marker_positions: Vec<u32>,
45
+ pub magic_positions: Vec<u32>,
46
+ }
47
+
48
+ #[napi(object)]
49
+ pub struct CompressionReport {
50
+ pub original_size: f64,
51
+ pub compressed_size: f64,
52
+ pub ratio: f64,
53
+ pub entropy_bits: f64,
54
+ pub blocks_count: u32,
55
+ }
56
+
57
+ #[napi(object)]
58
+ pub struct GpuStatus {
59
+ pub available: bool,
60
+ pub adapter_info: Option<String>,
61
+ }
62
+
63
+ #[cfg(not(test))]
64
+ #[napi]
65
+ pub fn scan_pixels(buffer: Buffer, channels: u32, marker_bytes: Option<Buffer>) -> Result<ScanResult> {
66
+ let slice: &[u8] = &buffer;
67
+ let markers_slice: Option<&[u8]> = marker_bytes.as_ref().map(|b| &**b);
68
+ let res = core::scan_pixels_bytes(slice, channels as usize, markers_slice);
69
+ Ok(ScanResult { marker_positions: res.marker_positions, magic_positions: res.magic_positions })
70
+ }
71
+
72
+ #[cfg(not(test))]
73
+ #[napi]
74
+ pub fn native_crc32(buffer: Buffer) -> u32 {
75
+ core::crc32_bytes(&buffer)
76
+ }
77
+
78
+ #[cfg(not(test))]
79
+ #[napi]
80
+ pub fn native_adler32(buffer: Buffer) -> u32 {
81
+ core::adler32_bytes(&buffer)
82
+ }
83
+
84
+ #[cfg(not(test))]
85
+ #[napi]
86
+ pub fn native_delta_encode(buffer: Buffer) -> Vec<u8> {
87
+ core::delta_encode_bytes(&buffer)
88
+ }
89
+
90
+ #[cfg(not(test))]
91
+ #[napi]
92
+ pub fn native_delta_decode(buffer: Buffer) -> Vec<u8> {
93
+ core::delta_decode_bytes(&buffer)
94
+ }
95
+
96
+ #[cfg(not(test))]
97
+ #[napi]
98
+ pub fn native_zstd_compress(buffer: Buffer, level: i32) -> Result<Vec<u8>> {
99
+ core::zstd_compress_bytes(&buffer, level, None).map_err(|e| Error::from_reason(e))
100
+ }
101
+
102
+ #[cfg(not(test))]
103
+ #[napi]
104
+ pub fn native_zstd_compress_with_dict(buffer: Buffer, level: i32, dict: Buffer) -> Result<Vec<u8>> {
105
+ let dict_slice: &[u8] = &dict;
106
+ core::zstd_compress_bytes(&buffer, level, Some(dict_slice)).map_err(|e| Error::from_reason(e))
107
+ }
108
+
109
+ #[cfg(not(test))]
110
+ #[napi]
111
+ pub fn native_zstd_decompress(buffer: Buffer) -> Result<Vec<u8>> {
112
+ core::zstd_decompress_bytes(&buffer, None).map_err(|e| Error::from_reason(e))
113
+ }
114
+
115
+ #[cfg(not(test))]
116
+ #[napi]
117
+ pub fn native_zstd_decompress_with_dict(buffer: Buffer, dict: Buffer) -> Result<Vec<u8>> {
118
+ let dict_slice: &[u8] = &dict;
119
+ core::zstd_decompress_bytes(&buffer, Some(dict_slice)).map_err(|e| Error::from_reason(e))
120
+ }
121
+
122
+ #[cfg(not(test))]
123
+ #[napi]
124
+ pub fn check_gpu_status() -> GpuStatus {
125
+ GpuStatus {
126
+ available: gpu::gpu_available(),
127
+ adapter_info: None,
128
+ }
129
+ }
130
+
131
+ #[cfg(not(test))]
132
+ #[napi]
133
+ pub fn bwt_transform(buffer: Buffer) -> Result<Vec<u8>> {
134
+ match bwt::bwt_encode(&buffer) {
135
+ Ok(result) => {
136
+ let mut output = Vec::with_capacity(4 + result.transformed.len());
137
+ output.extend_from_slice(&result.primary_index.to_le_bytes());
138
+ output.extend_from_slice(&result.transformed);
139
+ Ok(output)
140
+ }
141
+ Err(e) => Err(Error::from_reason(e.to_string())),
142
+ }
143
+ }
144
+
145
+ #[cfg(not(test))]
146
+ #[napi]
147
+ pub fn entropy_estimate(buffer: Buffer) -> f32 {
148
+ context_mixing::analyze_entropy(&buffer)
149
+ }
150
+
151
+ #[cfg(not(test))]
152
+ #[napi]
153
+ pub fn hybrid_compress(buffer: Buffer) -> Result<Vec<u8>> {
154
+ match hybrid::compress_high_performance(&buffer) {
155
+ Ok((compressed, _stats)) => Ok(compressed),
156
+ Err(e) => Err(Error::from_reason(e.to_string())),
157
+ }
158
+ }
159
+
160
+ #[cfg(not(test))]
161
+ #[napi]
162
+ pub fn hybrid_decompress(buffer: Buffer) -> Result<Vec<u8>> {
163
+ hybrid::decompress_high_performance(&buffer)
164
+ .map_err(|e| Error::from_reason(e.to_string()))
165
+ }
166
+
167
+ #[cfg(not(test))]
168
+ #[napi]
169
+ pub fn get_compression_stats(buffer: Buffer) -> CompressionReport {
170
+ match hybrid::compress_high_performance(&buffer) {
171
+ Ok((_compressed, stats)) => CompressionReport {
172
+ original_size: stats.original_size as f64,
173
+ compressed_size: stats.compressed_size as f64,
174
+ ratio: stats.ratio,
175
+ entropy_bits: stats.entropy_bits as f64,
176
+ blocks_count: stats.blocks_count as u32,
177
+ },
178
+ Err(_) => CompressionReport {
179
+ original_size: buffer.len() as f64,
180
+ compressed_size: 0.0,
181
+ ratio: 0.0,
182
+ entropy_bits: 0.0,
183
+ blocks_count: 0,
184
+ },
185
+ }
186
+ }
187
+
188
+ #[cfg(test)]
189
+ mod tests {
190
+ use super::*;
191
+
192
+ #[test]
193
+ fn test_scan_magic() {
194
+ let data = b"xxxxROX1yyyyROX1".to_vec();
195
+ let res = core::scan_pixels_bytes(&data, 3, None);
196
+ assert_eq!(res.magic_positions.len(), 2);
197
+ }
198
+
199
+ #[test]
200
+ fn test_bwt() {
201
+ let data = b"banana".to_vec();
202
+ let enc = bwt::bwt_encode(&data).unwrap();
203
+ assert!(!enc.transformed.is_empty());
204
+ }
205
+
206
+ #[test]
207
+ fn test_entropy() {
208
+ let data = b"aaaaabbbcc";
209
+ let entropy = context_mixing::analyze_entropy(data);
210
+ assert!(entropy > 0.0 && entropy < 8.0);
211
+ }
212
+ }
213
+
214
+ #[cfg(not(test))]
215
+ #[napi]
216
+ pub fn native_encode_png(buffer: Buffer, compression_level: i32) -> Result<Vec<u8>> {
217
+ encoder::encode_to_png(&buffer, compression_level)
218
+ .map_err(|e| Error::from_reason(e.to_string()))
219
+ }
220
+
221
+ #[cfg(not(test))]
222
+ #[napi]
223
+ pub fn native_encode_png_raw(buffer: Buffer, compression_level: i32) -> Result<Vec<u8>> {
224
+ encoder::encode_to_png_raw(&buffer, compression_level)
225
+ .map_err(|e| Error::from_reason(e.to_string()))
226
+ }
227
+
228
+ #[cfg(not(test))]
229
+ #[napi]
230
+ pub fn native_encode_png_with_name_and_filelist(
231
+ buffer: Buffer,
232
+ compression_level: i32,
233
+ name: Option<String>,
234
+ file_list_json: Option<String>,
235
+ ) -> Result<Vec<u8>> {
236
+ encoder::encode_to_png_with_name_and_filelist(
237
+ &buffer,
238
+ compression_level,
239
+ name.as_deref(),
240
+ file_list_json.as_deref(),
241
+ )
242
+ .map_err(|e| Error::from_reason(e.to_string()))
243
+ }
244
+
245
+ #[cfg(not(test))]
246
+ #[napi]
247
+ pub fn native_encode_png_with_encryption_name_and_filelist(
248
+ buffer: Buffer,
249
+ compression_level: i32,
250
+ passphrase: Option<String>,
251
+ encrypt_type: Option<String>,
252
+ name: Option<String>,
253
+ file_list_json: Option<String>,
254
+ ) -> Result<Vec<u8>> {
255
+ encoder::encode_to_png_with_encryption_name_and_filelist(
256
+ &buffer,
257
+ compression_level,
258
+ passphrase.as_deref(),
259
+ encrypt_type.as_deref(),
260
+ name.as_deref(),
261
+ file_list_json.as_deref(),
262
+ )
263
+ .map_err(|e| Error::from_reason(e.to_string()))
264
+ }
265
+
266
+ #[napi(object)]
267
+ pub struct PngChunkData {
268
+ pub name: String,
269
+ pub data: Vec<u8>,
270
+ }
271
+
272
+ #[cfg(not(test))]
273
+ #[napi]
274
+ pub fn extract_png_chunks(png_buffer: Buffer) -> Result<Vec<PngChunkData>> {
275
+ let chunks = png_utils::extract_png_chunks(&png_buffer)
276
+ .map_err(|e| Error::from_reason(e))?;
277
+
278
+ Ok(chunks.into_iter().map(|c| PngChunkData {
279
+ name: c.name,
280
+ data: c.data,
281
+ }).collect())
282
+ }
283
+
284
+ #[cfg(not(test))]
285
+ #[napi]
286
+ pub fn encode_png_chunks(chunks: Vec<PngChunkData>) -> Result<Vec<u8>> {
287
+ let native_chunks: Vec<png_utils::PngChunk> = chunks.into_iter()
288
+ .map(|c| png_utils::PngChunk {
289
+ name: c.name,
290
+ data: c.data,
291
+ })
292
+ .collect();
293
+
294
+ png_utils::encode_png_chunks(&native_chunks)
295
+ .map_err(|e| Error::from_reason(e))
296
+ }
297
+
298
+ #[napi(object)]
299
+ pub struct PngMetadata {
300
+ pub width: u32,
301
+ pub height: u32,
302
+ pub bit_depth: u32,
303
+ pub color_type: u32,
304
+ }
305
+
306
+ #[cfg(not(test))]
307
+ #[napi]
308
+ pub fn get_png_metadata(png_buffer: Buffer) -> Result<PngMetadata> {
309
+ let (width, height, bit_depth, color_type) = png_utils::get_png_metadata(&png_buffer)
310
+ .map_err(|e| Error::from_reason(e))?;
311
+
312
+ Ok(PngMetadata {
313
+ width,
314
+ height,
315
+ bit_depth: bit_depth as u32,
316
+ color_type: color_type as u32,
317
+ })
318
+ }
319
+
320
+ #[napi(object)]
321
+ pub struct SharpMetadata {
322
+ pub width: u32,
323
+ pub height: u32,
324
+ pub format: String,
325
+ }
326
+
327
+ #[cfg(not(test))]
328
+ #[napi]
329
+ pub fn sharp_resize_image(
330
+ input_buffer: Buffer,
331
+ width: u32,
332
+ height: u32,
333
+ kernel: String,
334
+ ) -> Result<Vec<u8>> {
335
+ image_utils::sharp_resize(&input_buffer, width, height, &kernel)
336
+ .map_err(|e| Error::from_reason(e))
337
+ }
338
+
339
+ #[cfg(not(test))]
340
+ #[napi]
341
+ pub fn sharp_raw_pixels(input_buffer: Buffer) -> Result<Vec<u8>> {
342
+ let (pixels, _w, _h) = image_utils::sharp_raw_pixels(&input_buffer)
343
+ .map_err(|e| Error::from_reason(e))?;
344
+ Ok(pixels)
345
+ }
346
+
347
+ #[napi(object)]
348
+ pub struct RawPixelsWithDimensions {
349
+ pub pixels: Vec<u8>,
350
+ pub width: u32,
351
+ pub height: u32,
352
+ }
353
+
354
+ #[cfg(not(test))]
355
+ #[napi]
356
+ pub fn sharp_to_raw(input_buffer: Buffer) -> Result<RawPixelsWithDimensions> {
357
+ let (pixels, width, height) = image_utils::sharp_raw_pixels(&input_buffer)
358
+ .map_err(|e| Error::from_reason(e))?;
359
+ Ok(RawPixelsWithDimensions { pixels, width, height })
360
+ }
361
+
362
+ #[cfg(not(test))]
363
+ #[napi]
364
+ pub fn sharp_metadata(input_buffer: Buffer) -> Result<SharpMetadata> {
365
+ let (width, height, format) = image_utils::sharp_metadata(&input_buffer)
366
+ .map_err(|e| Error::from_reason(e))?;
367
+ Ok(SharpMetadata { width, height, format })
368
+ }
369
+
370
+ #[cfg(not(test))]
371
+ #[napi]
372
+ pub fn rgb_to_png(rgb_buffer: Buffer, width: u32, height: u32) -> Result<Vec<u8>> {
373
+ image_utils::rgb_to_png(&rgb_buffer, width, height)
374
+ .map_err(|e| Error::from_reason(e))
375
+ }
376
+
377
+ #[cfg(not(test))]
378
+ #[napi]
379
+ pub fn png_to_rgb(png_buffer: Buffer) -> Result<RawPixelsWithDimensions> {
380
+ let (pixels, width, height) = image_utils::png_to_rgb(&png_buffer)
381
+ .map_err(|e| Error::from_reason(e))?;
382
+ Ok(RawPixelsWithDimensions { pixels, width, height })
383
+ }
384
+
385
+ #[cfg(not(test))]
386
+ #[napi]
387
+ pub fn crop_and_reconstitute(png_buffer: Buffer) -> Result<Vec<u8>> {
388
+ reconstitution::crop_and_reconstitute(&png_buffer)
389
+ .map_err(|e| Error::from_reason(e))
390
+ }
391
+
392
+ // ─── WAV container NAPI exports ──────────────────────────────────────────────
393
+
394
+ #[cfg(not(test))]
395
+ #[napi]
396
+ pub fn native_encode_wav(buffer: Buffer, compression_level: i32) -> Result<Vec<u8>> {
397
+ encoder::encode_to_wav(&buffer, compression_level)
398
+ .map_err(|e| Error::from_reason(e.to_string()))
399
+ }
400
+
401
+ #[cfg(not(test))]
402
+ #[napi]
403
+ pub fn native_encode_wav_with_name_and_filelist(
404
+ buffer: Buffer,
405
+ compression_level: i32,
406
+ name: Option<String>,
407
+ file_list_json: Option<String>,
408
+ ) -> Result<Vec<u8>> {
409
+ encoder::encode_to_wav_with_name_and_filelist(
410
+ &buffer,
411
+ compression_level,
412
+ name.as_deref(),
413
+ file_list_json.as_deref(),
414
+ )
415
+ .map_err(|e| Error::from_reason(e.to_string()))
416
+ }
417
+
418
+ #[cfg(not(test))]
419
+ #[napi]
420
+ pub fn native_encode_wav_with_encryption_name_and_filelist(
421
+ buffer: Buffer,
422
+ compression_level: i32,
423
+ passphrase: Option<String>,
424
+ encrypt_type: Option<String>,
425
+ name: Option<String>,
426
+ file_list_json: Option<String>,
427
+ ) -> Result<Vec<u8>> {
428
+ encoder::encode_to_wav_with_encryption_name_and_filelist(
429
+ &buffer,
430
+ compression_level,
431
+ passphrase.as_deref(),
432
+ encrypt_type.as_deref(),
433
+ name.as_deref(),
434
+ file_list_json.as_deref(),
435
+ )
436
+ .map_err(|e| Error::from_reason(e.to_string()))
437
+ }
438
+
439
+ #[cfg(not(test))]
440
+ #[napi]
441
+ pub fn native_decode_wav_payload(wav_buffer: Buffer) -> Result<Vec<u8>> {
442
+ encoder::decode_wav_payload(&wav_buffer)
443
+ .map_err(|e| Error::from_reason(e.to_string()))
444
+ }
445
+
446
+ #[cfg(not(test))]
447
+ #[napi]
448
+ pub fn native_bytes_to_wav(buffer: Buffer) -> Vec<u8> {
449
+ audio::bytes_to_wav(&buffer)
450
+ }
451
+
452
+ #[cfg(not(test))]
453
+ #[napi]
454
+ pub fn native_wav_to_bytes(wav_buffer: Buffer) -> Result<Vec<u8>> {
455
+ audio::wav_to_bytes(&wav_buffer)
456
+ .map_err(|e| Error::from_reason(e))
457
+ }
458
+
459
+ #[cfg(not(test))]
460
+ #[napi]
461
+ pub fn native_is_wav(buffer: Buffer) -> bool {
462
+ audio::is_wav(&buffer)
463
+ }
464
+