@reekon-tools/react-native-pdf-canvas 0.1.1 → 0.2.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.
Files changed (121) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +57 -0
  3. package/PdfCanvas.podspec +77 -40
  4. package/README.md +218 -1316
  5. package/android/build.gradle +67 -54
  6. package/android/consumer-rules.pro +7 -0
  7. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasNativeTest.java +254 -0
  8. package/android/src/androidTest/java/tools/reekon/pdfcanvas/TestPdfs.java +60 -468
  9. package/android/src/main/cpp/CMakeLists.txt +54 -0
  10. package/android/src/main/cpp/pdfcanvas-jni.cpp +262 -0
  11. package/android/src/main/java/tools/reekon/pdfcanvas/PdfCanvasNative.java +167 -0
  12. package/android/src/main/java/tools/reekon/pdfcanvas/PdfErrorCode.java +14 -4
  13. package/android/src/main/java/tools/reekon/pdfcanvas/PdfRasterException.java +10 -4
  14. package/android/src/reactnative/java/tools/reekon/pdfcanvas/rn/PdfCanvasModule.java +160 -376
  15. package/android/tools/compile-gate.sh +81 -101
  16. package/dist/controller.d.ts +14 -0
  17. package/dist/controller.js +4 -3
  18. package/dist/rasterizer/index.native.d.ts +8 -12
  19. package/dist/rasterizer/index.native.js +15 -21
  20. package/dist/rasterizer/native-bridge.d.ts +51 -75
  21. package/dist/rasterizer/native-bridge.js +49 -33
  22. package/dist/rasterizer/native.d.ts +45 -0
  23. package/dist/rasterizer/native.js +123 -0
  24. package/dist/react/usePdfDocument.d.ts +5 -5
  25. package/dist/react/usePdfLayer.d.ts +10 -1
  26. package/dist/react/usePdfLayer.js +10 -2
  27. package/dist/testing/scenes.d.ts +3 -3
  28. package/dist/testing/scenes.js +4 -4
  29. package/dist/types.d.ts +36 -42
  30. package/ios/Sources/PdfCanvasBridge/PdfCanvasModule.mm +234 -536
  31. package/native/.clangd +5 -0
  32. package/native/CMakeLists.txt +89 -0
  33. package/native/core/include/pdfcanvas/document.h +90 -0
  34. package/native/core/include/pdfcanvas/error.h +47 -0
  35. package/native/core/include/pdfcanvas/jsi.h +18 -0
  36. package/native/core/include/pdfcanvas/jsi_config.h +30 -0
  37. package/native/core/include/pdfcanvas/library.h +28 -0
  38. package/native/core/include/pdfcanvas/pixels.h +92 -0
  39. package/native/core/include/pdfcanvas/service.h +87 -0
  40. package/native/core/include/pdfcanvas/slots.h +113 -0
  41. package/native/core/include/pdfcanvas/types.h +110 -0
  42. package/native/core/pdfcanvas-core.cmake +22 -0
  43. package/native/core/src/document.cpp +516 -0
  44. package/native/core/src/error.cpp +29 -0
  45. package/native/core/src/jsi.cpp +66 -0
  46. package/native/core/src/library.cpp +52 -0
  47. package/native/core/src/pixels.cpp +45 -0
  48. package/native/core/src/service.cpp +156 -0
  49. package/native/core/src/slots.cpp +139 -0
  50. package/native/tests/fixtures.cpp +451 -0
  51. package/native/tests/fixtures.h +96 -0
  52. package/native/tests/harness.h +122 -0
  53. package/native/tests/main.cpp +64 -0
  54. package/native/tests/pixels_util.h +126 -0
  55. package/native/tests/test_document.cpp +485 -0
  56. package/native/tests/test_service.cpp +130 -0
  57. package/native/tests/test_slots.cpp +250 -0
  58. package/package.json +27 -7
  59. package/react-native.config.js +5 -2
  60. package/scripts/fetch-pdfium.mjs +559 -0
  61. package/scripts/pdfium-manifest.json +48 -0
  62. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasCancellationTest.java +0 -226
  63. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasConcurrencyTest.java +0 -239
  64. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasDeviceTimingTest.java +0 -251
  65. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasFailureTest.java +0 -221
  66. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasJsiTransportTest.java +0 -783
  67. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPhaseTimingTest.java +0 -1388
  68. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPoisonGuardTest.java +0 -98
  69. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasQuirksTest.java +0 -324
  70. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasRasterizerTest.java +0 -775
  71. package/android/src/androidTest/java/tools/reekon/pdfcanvas/PoisonsTheProcess.java +0 -20
  72. package/android/src/jsi/cpp/CMakeLists.txt +0 -33
  73. package/android/src/jsi/cpp/pdfcanvas-jsi.cpp +0 -469
  74. package/android/src/jsi/java/tools/reekon/pdfcanvas/jsi/PdfCanvasPixelBridge.java +0 -140
  75. package/android/src/main/java/tools/reekon/pdfcanvas/PageGeometry.java +0 -45
  76. package/android/src/main/java/tools/reekon/pdfcanvas/PdfCanvasRasterizer.java +0 -564
  77. package/android/src/main/java/tools/reekon/pdfcanvas/PdfPlatformQuirks.java +0 -277
  78. package/android/src/main/java/tools/reekon/pdfcanvas/PdfPreflight.java +0 -214
  79. package/android/src/main/java/tools/reekon/pdfcanvas/PdfRendererPool.java +0 -234
  80. package/android/src/main/java/tools/reekon/pdfcanvas/RasterCancellation.java +0 -47
  81. package/android/src/main/java/tools/reekon/pdfcanvas/RasterPixels.java +0 -143
  82. package/android/src/main/java/tools/reekon/pdfcanvas/RasterRequest.java +0 -95
  83. package/dist/rasterizer/android.d.ts +0 -121
  84. package/dist/rasterizer/android.js +0 -126
  85. package/dist/rasterizer/ios.d.ts +0 -84
  86. package/dist/rasterizer/ios.js +0 -155
  87. package/ios/Package.swift +0 -58
  88. package/ios/Sources/PdfCanvasCore/PdfCanvasCancellation.m +0 -38
  89. package/ios/Sources/PdfCanvasCore/PdfCanvasDocumentPool.m +0 -389
  90. package/ios/Sources/PdfCanvasCore/PdfCanvasErrorCode.m +0 -57
  91. package/ios/Sources/PdfCanvasCore/PdfCanvasPageGeometry.m +0 -44
  92. package/ios/Sources/PdfCanvasCore/PdfCanvasPageTransform.m +0 -82
  93. package/ios/Sources/PdfCanvasCore/PdfCanvasPixelSink.m +0 -37
  94. package/ios/Sources/PdfCanvasCore/PdfCanvasPreflight.m +0 -158
  95. package/ios/Sources/PdfCanvasCore/PdfCanvasRasterPixels.m +0 -80
  96. package/ios/Sources/PdfCanvasCore/PdfCanvasRasterRequest.m +0 -65
  97. package/ios/Sources/PdfCanvasCore/PdfCanvasRasterizer.m +0 -548
  98. package/ios/Sources/PdfCanvasCore/include/PdfCanvasCancellation.h +0 -48
  99. package/ios/Sources/PdfCanvasCore/include/PdfCanvasCore.h +0 -26
  100. package/ios/Sources/PdfCanvasCore/include/PdfCanvasDocumentPool.h +0 -122
  101. package/ios/Sources/PdfCanvasCore/include/PdfCanvasErrorCode.h +0 -80
  102. package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageGeometry.h +0 -79
  103. package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageTransform.h +0 -129
  104. package/ios/Sources/PdfCanvasCore/include/PdfCanvasPixelSink.h +0 -100
  105. package/ios/Sources/PdfCanvasCore/include/PdfCanvasPreflight.h +0 -65
  106. package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterPixels.h +0 -111
  107. package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterRequest.h +0 -85
  108. package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterizer.h +0 -163
  109. package/ios/Sources/PdfCanvasSlots/PdfCanvasSlots.mm +0 -297
  110. package/ios/Sources/PdfCanvasSlots/include/PdfCanvasSlots.h +0 -140
  111. package/ios/Tests/PdfCanvasCoreTests/ConcurrencyTests.swift +0 -358
  112. package/ios/Tests/PdfCanvasCoreTests/FailureTests.swift +0 -262
  113. package/ios/Tests/PdfCanvasCoreTests/GeometryTests.swift +0 -173
  114. package/ios/Tests/PdfCanvasCoreTests/PreviewTests.swift +0 -114
  115. package/ios/Tests/PdfCanvasCoreTests/RasterAssertions.swift +0 -158
  116. package/ios/Tests/PdfCanvasCoreTests/RasterizerTests.swift +0 -544
  117. package/ios/Tests/PdfCanvasCoreTests/SinkTests.swift +0 -287
  118. package/ios/Tests/PdfCanvasCoreTests/SlotsTests.swift +0 -396
  119. package/ios/Tests/PdfCanvasCoreTests/TestPdfs.swift +0 -639
  120. package/ios/Tests/PdfCanvasCoreTests/TimingTests.swift +0 -179
  121. package/ios/Tests/PdfCanvasCoreTests/TransformTests.swift +0 -283
@@ -1,158 +0,0 @@
1
- #import "PdfCanvasPreflight.h"
2
-
3
- /**
4
- * How far into a file to look for `%PDF-`.
5
- *
6
- * 1024 bytes, which is Acrobat's own documented tolerance for junk before the
7
- * header. Smaller would reject files every other reader accepts; larger would
8
- * start reading a meaningful chunk of a file this method is supposed to be cheap
9
- * about.
10
- */
11
- static const NSUInteger kPdfCanvasHeaderWindow = 1024;
12
-
13
- static BOOL HasPdfHeader(const uint8_t *bytes, NSUInteger length) {
14
- static const char kHeader[] = "%PDF-";
15
- const NSUInteger headerLength = sizeof(kHeader) - 1;
16
- if (length < headerLength) {
17
- return NO;
18
- }
19
- const NSUInteger last = length - headerLength;
20
- for (NSUInteger i = 0; i <= last; i++) {
21
- if (memcmp(bytes + i, kHeader, headerLength) == 0) {
22
- return YES;
23
- }
24
- }
25
- return NO;
26
- }
27
-
28
- @implementation PdfCanvasPreflight
29
-
30
- + (BOOL)checkFileURL:(NSURL *)url error:(NSError *_Nullable *_Nullable)error {
31
- if (url == nil || url.path.length == 0) {
32
- PdfCanvasFail(error, PdfCanvasErrorCodeNotFound, @"No document url was given.",
33
- nil);
34
- return NO;
35
- }
36
- if (!url.isFileURL) {
37
- PdfCanvasFail(
38
- error, PdfCanvasErrorCodeNotFound,
39
- [NSString stringWithFormat:
40
- @"Only file URLs can be opened, got scheme '%@'. A remote "
41
- @"document has to be downloaded first — this backend does "
42
- @"no networking.",
43
- url.scheme ?: @"(none)"],
44
- nil);
45
- return NO;
46
- }
47
-
48
- NSFileManager *files = NSFileManager.defaultManager;
49
- BOOL isDirectory = NO;
50
- if (![files fileExistsAtPath:url.path isDirectory:&isDirectory]) {
51
- PdfCanvasFail(
52
- error, PdfCanvasErrorCodeNotFound,
53
- [NSString stringWithFormat:@"No file at %@.", url.path], nil);
54
- return NO;
55
- }
56
- if (isDirectory) {
57
- PdfCanvasFail(
58
- error, PdfCanvasErrorCodeNotFound,
59
- [NSString stringWithFormat:@"%@ is a directory, not a PDF.", url.path],
60
- nil);
61
- return NO;
62
- }
63
- if (![files isReadableFileAtPath:url.path]) {
64
- // The likeliest cause on iOS is a security-scoped URL whose access was never
65
- // started, or was already stopped — which is a real and common host mistake,
66
- // so it is named rather than reported as a generic failure.
67
- PdfCanvasFail(
68
- error, PdfCanvasErrorCodeNotFound,
69
- [NSString stringWithFormat:
70
- @"No permission to read %@. If this came from a document "
71
- @"picker or an iCloud container, the URL is "
72
- @"security-scoped and the host must hold "
73
- @"startAccessingSecurityScopedResource for the whole "
74
- @"lifetime of the document, or copy the file first.",
75
- url.path],
76
- nil);
77
- return NO;
78
- }
79
-
80
- NSError *attributesError = nil;
81
- NSDictionary<NSFileAttributeKey, id> *attributes =
82
- [files attributesOfItemAtPath:url.path error:&attributesError];
83
- if (attributes == nil) {
84
- PdfCanvasFail(
85
- error, PdfCanvasErrorCodeNotFound,
86
- [NSString stringWithFormat:@"Could not stat %@.", url.path],
87
- attributesError);
88
- return NO;
89
- }
90
- const unsigned long long size = attributes.fileSize;
91
- if (size == 0) {
92
- PdfCanvasFail(
93
- error, PdfCanvasErrorCodeCorrupt,
94
- [NSString stringWithFormat:@"%@ is empty (0 bytes).", url.path], nil);
95
- return NO;
96
- }
97
-
98
- // The header window only, and mapped rather than read: a `dataWithContentsOfFile`
99
- // on an ARCH-E scan would pull tens of megabytes through a method whose whole
100
- // job is to be cheap. `NSFileHandle` reads exactly the window.
101
- NSError *openError = nil;
102
- NSFileHandle *handle = [NSFileHandle fileHandleForReadingFromURL:url
103
- error:&openError];
104
- if (handle == nil) {
105
- PdfCanvasFail(
106
- error, PdfCanvasErrorCodeNotFound,
107
- [NSString stringWithFormat:@"Could not open %@ for reading.", url.path],
108
- openError);
109
- return NO;
110
- }
111
- NSData *head = nil;
112
- @try {
113
- head = [handle readDataOfLength:kPdfCanvasHeaderWindow];
114
- } @catch (NSException *exception) {
115
- // `readDataOfLength:` raises rather than returning nil on an I/O error. The
116
- // non-raising `readDataUpToLength:error:` is iOS 13+/macOS 10.15+, which this
117
- // library's floor clears — but it is also documented to be usable only on
118
- // handles created with the error-returning initialisers, so the @try covers
119
- // the case either way.
120
- head = nil;
121
- }
122
- [handle closeFile];
123
-
124
- if (head == nil || !HasPdfHeader((const uint8_t *)head.bytes, head.length)) {
125
- PdfCanvasFail(
126
- error, PdfCanvasErrorCodeCorrupt,
127
- [NSString
128
- stringWithFormat:@"%@ has no %%PDF- header in its first %lu bytes "
129
- @"(%llu bytes total), so it is not a PDF.",
130
- url.path, (unsigned long)kPdfCanvasHeaderWindow,
131
- size],
132
- nil);
133
- return NO;
134
- }
135
- return YES;
136
- }
137
-
138
- + (BOOL)checkData:(NSData *)data error:(NSError *_Nullable *_Nullable)error {
139
- if (data.length == 0) {
140
- PdfCanvasFail(error, PdfCanvasErrorCodeCorrupt, @"Document data is empty.",
141
- nil);
142
- return NO;
143
- }
144
- const NSUInteger window = MIN(data.length, kPdfCanvasHeaderWindow);
145
- if (!HasPdfHeader((const uint8_t *)data.bytes, window)) {
146
- PdfCanvasFail(
147
- error, PdfCanvasErrorCodeCorrupt,
148
- [NSString stringWithFormat:
149
- @"The document data has no %%PDF- header in its first "
150
- @"%lu bytes (%lu bytes total), so it is not a PDF.",
151
- (unsigned long)window, (unsigned long)data.length],
152
- nil);
153
- return NO;
154
- }
155
- return YES;
156
- }
157
-
158
- @end
@@ -1,80 +0,0 @@
1
- #import "PdfCanvasRasterPixels.h"
2
-
3
- NSString *const PdfCanvasFormatRGBA8888 = @"rgba8888";
4
-
5
- @implementation PdfCanvasRasterPixels {
6
- id<PdfCanvasPixelSink> _sink;
7
- BOOL _released;
8
- }
9
-
10
- - (instancetype)initWithSink:(id<PdfCanvasPixelSink>)sink
11
- slot:(int64_t)slot
12
- bytes:(nullable NSData *)bytes
13
- width:(NSInteger)width
14
- height:(NSInteger)height
15
- rowBytes:(NSInteger)rowBytes
16
- format:(NSString *)format {
17
- self = [super init];
18
- if (self != nil) {
19
- // STRONG, and that is what makes `-releaseSlot` possible at all: the sink is
20
- // the only thing that knows how to give the buffer back, and the rasterizer's
21
- // stack frame — where it was created — is long gone by the time an abandon
22
- // path further up decides to.
23
- _sink = sink;
24
- _slot = slot;
25
- _bytes = bytes;
26
- _width = width;
27
- _height = height;
28
- _rowBytes = rowBytes;
29
- _format = [format copy];
30
- }
31
- return self;
32
- }
33
-
34
- - (BOOL)isInNativeSlot {
35
- return _slot != 0;
36
- }
37
-
38
- - (void)releaseSlot {
39
- if (_released || _slot == 0) {
40
- return;
41
- }
42
- _released = YES;
43
- [_sink pdfCanvasAbandon];
44
- }
45
-
46
- - (NSInteger)offsetOfX:(NSInteger)x y:(NSInteger)y {
47
- [self requireHeapBacked];
48
- return y * _rowBytes + x * 4;
49
- }
50
-
51
- - (NSInteger)channelAtX:(NSInteger)x y:(NSInteger)y channel:(NSInteger)channel {
52
- [self requireHeapBacked];
53
- const uint8_t *base = (const uint8_t *)_bytes.bytes;
54
- return base[y * _rowBytes + x * 4 + channel];
55
- }
56
-
57
- - (void)requireHeapBacked {
58
- if (_bytes != nil) {
59
- return;
60
- }
61
- [NSException
62
- raise:NSInternalInconsistencyException
63
- format:@"This raster's pixels are in native slot %lld, not on the heap, "
64
- @"so they cannot be read from here. Ask the rasterizer for a "
65
- @"heap-backed raster — pass a nil sink — instead of a slot sink.",
66
- _slot];
67
- }
68
-
69
- - (NSString *)description {
70
- return [NSString stringWithFormat:@"PdfCanvasRasterPixels{%ldx%ld rowBytes=%ld "
71
- @"%@ %@}",
72
- (long)_width, (long)_height, (long)_rowBytes,
73
- _format,
74
- self.isInNativeSlot
75
- ? [NSString stringWithFormat:@"slot=%lld",
76
- _slot]
77
- : @"heap"];
78
- }
79
-
80
- @end
@@ -1,65 +0,0 @@
1
- #import "PdfCanvasRasterRequest.h"
2
-
3
- #import <math.h>
4
-
5
- @implementation PdfCanvasRasterRequest
6
-
7
- - (instancetype)initWithPage:(NSInteger)page
8
- docX:(double)docX
9
- docY:(double)docY
10
- docWidth:(double)docWidth
11
- docHeight:(double)docHeight
12
- scale:(double)scale
13
- annotations:(BOOL)annotations
14
- background:(PdfCanvasBackground)background {
15
- self = [super init];
16
- if (self != nil) {
17
- _page = page;
18
- _docX = docX;
19
- _docY = docY;
20
- _docWidth = docWidth;
21
- _docHeight = docHeight;
22
- _scale = scale;
23
- _annotations = annotations;
24
- _background = background;
25
- }
26
- return self;
27
- }
28
-
29
- /**
30
- * `llround`, not `lround` and not `(NSInteger)(v + 0.5)`.
31
- *
32
- * `llround` is round-half-away-from-zero, which is what JavaScript's `Math.round`
33
- * is for positive values — and every value reaching here is positive, because a
34
- * non-positive extent is rejected before this is read. `(NSInteger)(v + 0.5)`
35
- * differs from both at exactly representable halves and is the version that
36
- * silently disagrees with the planner.
37
- */
38
- static NSInteger PixelExtent(double points, double scale) {
39
- if (!isfinite(points) || !isfinite(scale)) {
40
- return 1;
41
- }
42
- const long long rounded = llround(points * scale);
43
- return rounded < 1 ? 1 : (NSInteger)rounded;
44
- }
45
-
46
- - (NSInteger)pixelWidth {
47
- return PixelExtent(_docWidth, _scale);
48
- }
49
-
50
- - (NSInteger)pixelHeight {
51
- return PixelExtent(_docHeight, _scale);
52
- }
53
-
54
- - (NSString *)description {
55
- return [NSString
56
- stringWithFormat:@"PdfCanvasRasterRequest{p=%ld rect=%g,%g %gx%g @%g -> "
57
- @"%ldx%ld annotations=%@ bg=%@}",
58
- (long)_page, _docX, _docY, _docWidth, _docHeight, _scale,
59
- (long)self.pixelWidth, (long)self.pixelHeight,
60
- _annotations ? @"YES" : @"NO",
61
- _background == PdfCanvasBackgroundWhite ? @"white"
62
- : @"transparent"];
63
- }
64
-
65
- @end