roxify 1.13.4 → 1.13.6
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/Cargo.toml +2 -1
- package/README.md +30 -20
- package/dist/cli.js +36 -194
- package/dist/rox-macos-universal +0 -0
- package/dist/roxify_native +0 -0
- package/dist/roxify_native-macos-arm64 +0 -0
- package/dist/roxify_native-macos-x64 +0 -0
- package/dist/roxify_native.exe +0 -0
- package/dist/utils/decoder.d.ts +1 -21
- package/dist/utils/decoder.js +42 -1241
- package/dist/utils/encoder.d.ts +1 -13
- package/dist/utils/encoder.js +36 -559
- package/dist/utils/rust-cli-wrapper.d.ts +2 -2
- package/dist/utils/rust-cli-wrapper.js +8 -2
- package/native/encoder.rs +10 -22
- package/native/io_advice.rs +43 -0
- package/native/io_ntfs_optimized.rs +99 -0
- package/native/lib.rs +2 -0
- package/native/main.rs +329 -57
- package/native/packer.rs +188 -82
- package/native/png_chunk_writer.rs +146 -0
- package/native/png_utils.rs +70 -54
- package/native/streaming.rs +16 -39
- package/native/streaming_decode.rs +263 -110
- package/native/streaming_encode.rs +36 -59
- package/package.json +1 -1
- package/roxify_native-aarch64-apple-darwin.node +0 -0
- package/roxify_native-aarch64-pc-windows-msvc.node +0 -0
- package/roxify_native-aarch64-unknown-linux-gnu.node +0 -0
- package/roxify_native-i686-pc-windows-msvc.node +0 -0
- package/roxify_native-i686-unknown-linux-gnu.node +0 -0
- package/roxify_native-x86_64-apple-darwin.node +0 -0
- package/roxify_native-x86_64-pc-windows-msvc.node +0 -0
- package/roxify_native-x86_64-unknown-linux-gnu.node +0 -0
|
@@ -5,6 +5,8 @@ use rayon::prelude::*;
|
|
|
5
5
|
use serde::Serialize;
|
|
6
6
|
use walkdir::WalkDir;
|
|
7
7
|
|
|
8
|
+
use crate::png_chunk_writer::{ChunkedIdatWriter, write_png_chunk};
|
|
9
|
+
|
|
8
10
|
const PNG_HEADER: &[u8] = &[137, 80, 78, 71, 13, 10, 26, 10];
|
|
9
11
|
const PIXEL_MAGIC: &[u8] = b"PXL1";
|
|
10
12
|
const MARKER_START: [(u8, u8, u8); 3] = [(255, 0, 0), (0, 255, 0), (0, 0, 255)];
|
|
@@ -20,6 +22,7 @@ const PARALLEL_IO_FILE_THRESHOLD: u64 = MB;
|
|
|
20
22
|
const PARALLEL_IO_BATCH_BYTES: u64 = 128 * MB;
|
|
21
23
|
const PARALLEL_IO_BATCH_FILES: usize = 512;
|
|
22
24
|
const PARALLEL_IO_MIN_FILES: usize = 8;
|
|
25
|
+
const HEADER_VERSION_V2: u8 = 2;
|
|
23
26
|
|
|
24
27
|
pub type ProgressCallback = Box<dyn Fn(u64, u64, &str) + Send>;
|
|
25
28
|
|
|
@@ -313,14 +316,24 @@ fn estimate_zst_capacity(total_bytes: u64) -> usize {
|
|
|
313
316
|
|
|
314
317
|
fn select_zstd_threads(total_bytes: u64) -> u32 {
|
|
315
318
|
let max_threads = num_cpus::get().max(1) as u32;
|
|
316
|
-
|
|
319
|
+
let ram_mb = crate::parse_linux_mem_available_mb().unwrap_or(4096);
|
|
320
|
+
|
|
321
|
+
// Aggressive multi-threading for Pyxelze speed target (<10s)
|
|
322
|
+
if total_bytes <= 16 * MB {
|
|
323
|
+
// Small files: single thread to avoid overhead
|
|
317
324
|
1
|
|
318
|
-
} else if total_bytes <=
|
|
325
|
+
} else if total_bytes <= 64 * MB {
|
|
326
|
+
// Small-medium files: 2 threads
|
|
319
327
|
max_threads.min(2)
|
|
320
|
-
} else if total_bytes <=
|
|
328
|
+
} else if total_bytes <= 256 * MB || ram_mb >= 8192 {
|
|
329
|
+
// Medium files or high RAM: up to 4 threads
|
|
321
330
|
max_threads.min(4)
|
|
322
|
-
} else {
|
|
331
|
+
} else if total_bytes <= 1024 * MB || ram_mb >= 4096 {
|
|
332
|
+
// Large files or medium RAM: up to 8 threads
|
|
323
333
|
max_threads.min(8)
|
|
334
|
+
} else {
|
|
335
|
+
// Very large files: use all available cores up to 16
|
|
336
|
+
max_threads.min(16)
|
|
324
337
|
}
|
|
325
338
|
}
|
|
326
339
|
|
|
@@ -345,12 +358,12 @@ fn write_png_from_zst_mem(
|
|
|
345
358
|
|
|
346
359
|
let encrypted_payload_len = enc_header_len + zst_size + hmac_trailer_len;
|
|
347
360
|
|
|
348
|
-
let version =
|
|
361
|
+
let version = HEADER_VERSION_V2;
|
|
349
362
|
let name_bytes = name.map(|n| n.as_bytes()).unwrap_or(&[]);
|
|
350
363
|
let name_len = name_bytes.len().min(255) as u8;
|
|
351
|
-
let payload_len_bytes = (encrypted_payload_len as
|
|
364
|
+
let payload_len_bytes = (encrypted_payload_len as u64).to_be_bytes();
|
|
352
365
|
|
|
353
|
-
let mut meta_header = Vec::with_capacity(1 + 1 + name_len as usize +
|
|
366
|
+
let mut meta_header = Vec::with_capacity(1 + 1 + name_len as usize + 8);
|
|
354
367
|
meta_header.push(version);
|
|
355
368
|
meta_header.push(name_len);
|
|
356
369
|
if name_len > 0 {
|
|
@@ -398,13 +411,6 @@ fn write_png_from_zst_mem(
|
|
|
398
411
|
|
|
399
412
|
let header_bytes = build_header_bytes(&meta_header, &enc_header_bytes);
|
|
400
413
|
|
|
401
|
-
let stride = row_bytes + 1;
|
|
402
|
-
let scanlines_total = height * stride;
|
|
403
|
-
|
|
404
|
-
const MAX_BLOCK: usize = 65535;
|
|
405
|
-
let num_blocks = (scanlines_total + MAX_BLOCK - 1) / MAX_BLOCK;
|
|
406
|
-
let idat_len = 2 + num_blocks * 5 + scanlines_total + 4;
|
|
407
|
-
|
|
408
414
|
let out_file = File::create(output_path)?;
|
|
409
415
|
let buf_capacity = if total_data_bytes > 256 * 1024 * 1024 { 16 * 1024 * 1024 }
|
|
410
416
|
else if total_data_bytes > 16 * 1024 * 1024 { 8 * 1024 * 1024 }
|
|
@@ -418,7 +424,7 @@ fn write_png_from_zst_mem(
|
|
|
418
424
|
ihdr[4..8].copy_from_slice(&(height as u32).to_be_bytes());
|
|
419
425
|
ihdr[8] = 8;
|
|
420
426
|
ihdr[9] = 2;
|
|
421
|
-
|
|
427
|
+
write_png_chunk(&mut w, b"IHDR", &ihdr)?;
|
|
422
428
|
|
|
423
429
|
let mut zst_reader = std::io::Cursor::new(zst_buf);
|
|
424
430
|
|
|
@@ -433,15 +439,14 @@ fn write_png_from_zst_mem(
|
|
|
433
439
|
height,
|
|
434
440
|
row_bytes,
|
|
435
441
|
marker_end_pos,
|
|
436
|
-
idat_len,
|
|
437
442
|
total_data_bytes,
|
|
438
443
|
progress,
|
|
439
444
|
)?;
|
|
440
445
|
|
|
441
446
|
if let Some(fl) = file_list {
|
|
442
|
-
|
|
447
|
+
write_png_chunk(&mut w, b"rXFL", fl.as_bytes())?;
|
|
443
448
|
}
|
|
444
|
-
|
|
449
|
+
write_png_chunk(&mut w, b"IEND", &[])?;
|
|
445
450
|
w.flush()?;
|
|
446
451
|
|
|
447
452
|
Ok(())
|
|
@@ -470,22 +475,16 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
470
475
|
height: usize,
|
|
471
476
|
row_bytes: usize,
|
|
472
477
|
marker_end_pos: usize,
|
|
473
|
-
idat_len: usize,
|
|
474
478
|
total_data_bytes: usize,
|
|
475
479
|
progress: &Option<ProgressCallback>,
|
|
476
480
|
) -> anyhow::Result<()> {
|
|
477
|
-
|
|
478
|
-
w.write_all(b"IDAT")?;
|
|
479
|
-
|
|
480
|
-
let mut crc = crc32fast::Hasher::new();
|
|
481
|
-
crc.update(b"IDAT");
|
|
481
|
+
let mut idat = ChunkedIdatWriter::new(w);
|
|
482
482
|
|
|
483
483
|
let stride = row_bytes + 1;
|
|
484
484
|
let scanlines_total = height * stride;
|
|
485
485
|
|
|
486
486
|
let zlib = [0x78u8, 0x01];
|
|
487
|
-
|
|
488
|
-
crc.update(&zlib);
|
|
487
|
+
idat.write_all(&zlib)?;
|
|
489
488
|
|
|
490
489
|
let fl_chunk_data = file_list_chunk.unwrap_or(&[]);
|
|
491
490
|
let payload_total = header_bytes.len() + zst_size + hmac_trailer_len + fl_chunk_data.len();
|
|
@@ -524,14 +523,12 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
524
523
|
!block_size as u8,
|
|
525
524
|
(!(block_size >> 8)) as u8,
|
|
526
525
|
];
|
|
527
|
-
|
|
528
|
-
crc.update(&header);
|
|
526
|
+
idat.write_all(&header)?;
|
|
529
527
|
deflate_block_remaining = block_size;
|
|
530
528
|
}
|
|
531
529
|
|
|
532
530
|
let filter_byte = [0u8];
|
|
533
|
-
|
|
534
|
-
crc.update(&filter_byte);
|
|
531
|
+
idat.write_all(&filter_byte)?;
|
|
535
532
|
adler.write(&filter_byte);
|
|
536
533
|
scanline_pos += 1;
|
|
537
534
|
deflate_block_remaining -= 1;
|
|
@@ -549,8 +546,7 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
549
546
|
!block_size as u8,
|
|
550
547
|
(!(block_size >> 8)) as u8,
|
|
551
548
|
];
|
|
552
|
-
|
|
553
|
-
crc.update(&header);
|
|
549
|
+
idat.write_all(&header)?;
|
|
554
550
|
deflate_block_remaining = block_size;
|
|
555
551
|
}
|
|
556
552
|
|
|
@@ -567,8 +563,7 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
567
563
|
let me_remaining = 9 - me_offset;
|
|
568
564
|
let take = need.min(me_remaining);
|
|
569
565
|
let slice = &marker_end_bytes[me_offset..me_offset + take];
|
|
570
|
-
|
|
571
|
-
crc.update(slice);
|
|
566
|
+
idat.write_all(slice)?;
|
|
572
567
|
adler.write(slice);
|
|
573
568
|
flat_pos += take;
|
|
574
569
|
chunk_written += take;
|
|
@@ -582,8 +577,7 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
582
577
|
let avail = header_bytes.len() - header_pos;
|
|
583
578
|
let take = need.min(avail);
|
|
584
579
|
let slice = &header_bytes[header_pos..header_pos + take];
|
|
585
|
-
|
|
586
|
-
crc.update(slice);
|
|
580
|
+
idat.write_all(slice)?;
|
|
587
581
|
adler.write(slice);
|
|
588
582
|
header_pos += take;
|
|
589
583
|
flat_pos += take;
|
|
@@ -599,8 +593,7 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
599
593
|
if let Some(ref mut enc) = encryptor {
|
|
600
594
|
enc.encrypt_chunk(&mut transfer_buf[..got]);
|
|
601
595
|
}
|
|
602
|
-
|
|
603
|
-
crc.update(&transfer_buf[..got]);
|
|
596
|
+
idat.write_all(&transfer_buf[..got])?;
|
|
604
597
|
adler.write(&transfer_buf[..got]);
|
|
605
598
|
zst_remaining -= got;
|
|
606
599
|
flat_pos += got;
|
|
@@ -618,8 +611,7 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
618
611
|
let avail = hmac_trailer_len - hmac_pos;
|
|
619
612
|
let take = need.min(avail);
|
|
620
613
|
let slice = &hmac_bytes[hmac_pos..hmac_pos + take];
|
|
621
|
-
|
|
622
|
-
crc.update(slice);
|
|
614
|
+
idat.write_all(slice)?;
|
|
623
615
|
adler.write(slice);
|
|
624
616
|
hmac_pos += take;
|
|
625
617
|
flat_pos += take;
|
|
@@ -637,8 +629,7 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
637
629
|
let avail = fl_chunk_data.len() - fl_pos;
|
|
638
630
|
let take = need.min(avail);
|
|
639
631
|
let slice = &fl_chunk_data[fl_pos..fl_pos + take];
|
|
640
|
-
|
|
641
|
-
crc.update(slice);
|
|
632
|
+
idat.write_all(slice)?;
|
|
642
633
|
adler.write(slice);
|
|
643
634
|
fl_pos += take;
|
|
644
635
|
flat_pos += take;
|
|
@@ -654,8 +645,7 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
654
645
|
};
|
|
655
646
|
let take = need.min(zero_remaining).min(buf_size).min(max_before_marker);
|
|
656
647
|
if take == 0 { break; }
|
|
657
|
-
|
|
658
|
-
crc.update(&zero_buf[..take]);
|
|
648
|
+
idat.write_all(&zero_buf[..take])?;
|
|
659
649
|
adler.write(&zero_buf[..take]);
|
|
660
650
|
zero_remaining -= take;
|
|
661
651
|
flat_pos += take;
|
|
@@ -678,11 +668,8 @@ fn write_idat_streaming<W: Write, R: Read>(
|
|
|
678
668
|
|
|
679
669
|
let adler_val = adler.finish();
|
|
680
670
|
let adler_bytes = adler_val.to_be_bytes();
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
w.write_all(&crc.finalize().to_be_bytes())?;
|
|
685
|
-
Ok(())
|
|
671
|
+
idat.write_all(&adler_bytes)?;
|
|
672
|
+
idat.finish()
|
|
686
673
|
}
|
|
687
674
|
|
|
688
675
|
fn build_marker_end_bytes() -> [u8; 9] {
|
|
@@ -695,13 +682,3 @@ fn build_marker_end_bytes() -> [u8; 9] {
|
|
|
695
682
|
buf
|
|
696
683
|
}
|
|
697
684
|
|
|
698
|
-
fn write_chunk_hdr<W: Write>(w: &mut W, chunk_type: &[u8; 4], data: &[u8]) -> anyhow::Result<()> {
|
|
699
|
-
w.write_all(&(data.len() as u32).to_be_bytes())?;
|
|
700
|
-
w.write_all(chunk_type)?;
|
|
701
|
-
w.write_all(data)?;
|
|
702
|
-
let mut h = crc32fast::Hasher::new();
|
|
703
|
-
h.update(chunk_type);
|
|
704
|
-
h.update(data);
|
|
705
|
-
w.write_all(&h.finalize().to_be_bytes())?;
|
|
706
|
-
Ok(())
|
|
707
|
-
}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|