@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.
- package/LICENSE +202 -0
- package/NOTICE +57 -0
- package/PdfCanvas.podspec +77 -40
- package/README.md +218 -1316
- package/android/build.gradle +67 -54
- package/android/consumer-rules.pro +7 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasNativeTest.java +254 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/TestPdfs.java +60 -468
- package/android/src/main/cpp/CMakeLists.txt +54 -0
- package/android/src/main/cpp/pdfcanvas-jni.cpp +262 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfCanvasNative.java +167 -0
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfErrorCode.java +14 -4
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfRasterException.java +10 -4
- package/android/src/reactnative/java/tools/reekon/pdfcanvas/rn/PdfCanvasModule.java +160 -376
- package/android/tools/compile-gate.sh +81 -101
- package/dist/controller.d.ts +14 -0
- package/dist/controller.js +4 -3
- package/dist/rasterizer/index.native.d.ts +8 -12
- package/dist/rasterizer/index.native.js +15 -21
- package/dist/rasterizer/native-bridge.d.ts +51 -75
- package/dist/rasterizer/native-bridge.js +49 -33
- package/dist/rasterizer/native.d.ts +45 -0
- package/dist/rasterizer/native.js +123 -0
- package/dist/react/usePdfDocument.d.ts +5 -5
- package/dist/react/usePdfLayer.d.ts +10 -1
- package/dist/react/usePdfLayer.js +10 -2
- package/dist/testing/scenes.d.ts +3 -3
- package/dist/testing/scenes.js +4 -4
- package/dist/types.d.ts +36 -42
- package/ios/Sources/PdfCanvasBridge/PdfCanvasModule.mm +234 -536
- package/native/.clangd +5 -0
- package/native/CMakeLists.txt +89 -0
- package/native/core/include/pdfcanvas/document.h +90 -0
- package/native/core/include/pdfcanvas/error.h +47 -0
- package/native/core/include/pdfcanvas/jsi.h +18 -0
- package/native/core/include/pdfcanvas/jsi_config.h +30 -0
- package/native/core/include/pdfcanvas/library.h +28 -0
- package/native/core/include/pdfcanvas/pixels.h +92 -0
- package/native/core/include/pdfcanvas/service.h +87 -0
- package/native/core/include/pdfcanvas/slots.h +113 -0
- package/native/core/include/pdfcanvas/types.h +110 -0
- package/native/core/pdfcanvas-core.cmake +22 -0
- package/native/core/src/document.cpp +516 -0
- package/native/core/src/error.cpp +29 -0
- package/native/core/src/jsi.cpp +66 -0
- package/native/core/src/library.cpp +52 -0
- package/native/core/src/pixels.cpp +45 -0
- package/native/core/src/service.cpp +156 -0
- package/native/core/src/slots.cpp +139 -0
- package/native/tests/fixtures.cpp +451 -0
- package/native/tests/fixtures.h +96 -0
- package/native/tests/harness.h +122 -0
- package/native/tests/main.cpp +64 -0
- package/native/tests/pixels_util.h +126 -0
- package/native/tests/test_document.cpp +485 -0
- package/native/tests/test_service.cpp +130 -0
- package/native/tests/test_slots.cpp +250 -0
- package/package.json +27 -7
- package/react-native.config.js +5 -2
- package/scripts/fetch-pdfium.mjs +559 -0
- package/scripts/pdfium-manifest.json +48 -0
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasCancellationTest.java +0 -226
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasConcurrencyTest.java +0 -239
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasDeviceTimingTest.java +0 -251
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasFailureTest.java +0 -221
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasJsiTransportTest.java +0 -783
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPhaseTimingTest.java +0 -1388
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasPoisonGuardTest.java +0 -98
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasQuirksTest.java +0 -324
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PdfCanvasRasterizerTest.java +0 -775
- package/android/src/androidTest/java/tools/reekon/pdfcanvas/PoisonsTheProcess.java +0 -20
- package/android/src/jsi/cpp/CMakeLists.txt +0 -33
- package/android/src/jsi/cpp/pdfcanvas-jsi.cpp +0 -469
- package/android/src/jsi/java/tools/reekon/pdfcanvas/jsi/PdfCanvasPixelBridge.java +0 -140
- package/android/src/main/java/tools/reekon/pdfcanvas/PageGeometry.java +0 -45
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfCanvasRasterizer.java +0 -564
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfPlatformQuirks.java +0 -277
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfPreflight.java +0 -214
- package/android/src/main/java/tools/reekon/pdfcanvas/PdfRendererPool.java +0 -234
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterCancellation.java +0 -47
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterPixels.java +0 -143
- package/android/src/main/java/tools/reekon/pdfcanvas/RasterRequest.java +0 -95
- package/dist/rasterizer/android.d.ts +0 -121
- package/dist/rasterizer/android.js +0 -126
- package/dist/rasterizer/ios.d.ts +0 -84
- package/dist/rasterizer/ios.js +0 -155
- package/ios/Package.swift +0 -58
- package/ios/Sources/PdfCanvasCore/PdfCanvasCancellation.m +0 -38
- package/ios/Sources/PdfCanvasCore/PdfCanvasDocumentPool.m +0 -389
- package/ios/Sources/PdfCanvasCore/PdfCanvasErrorCode.m +0 -57
- package/ios/Sources/PdfCanvasCore/PdfCanvasPageGeometry.m +0 -44
- package/ios/Sources/PdfCanvasCore/PdfCanvasPageTransform.m +0 -82
- package/ios/Sources/PdfCanvasCore/PdfCanvasPixelSink.m +0 -37
- package/ios/Sources/PdfCanvasCore/PdfCanvasPreflight.m +0 -158
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterPixels.m +0 -80
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterRequest.m +0 -65
- package/ios/Sources/PdfCanvasCore/PdfCanvasRasterizer.m +0 -548
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasCancellation.h +0 -48
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasCore.h +0 -26
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasDocumentPool.h +0 -122
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasErrorCode.h +0 -80
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageGeometry.h +0 -79
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPageTransform.h +0 -129
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPixelSink.h +0 -100
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasPreflight.h +0 -65
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterPixels.h +0 -111
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterRequest.h +0 -85
- package/ios/Sources/PdfCanvasCore/include/PdfCanvasRasterizer.h +0 -163
- package/ios/Sources/PdfCanvasSlots/PdfCanvasSlots.mm +0 -297
- package/ios/Sources/PdfCanvasSlots/include/PdfCanvasSlots.h +0 -140
- package/ios/Tests/PdfCanvasCoreTests/ConcurrencyTests.swift +0 -358
- package/ios/Tests/PdfCanvasCoreTests/FailureTests.swift +0 -262
- package/ios/Tests/PdfCanvasCoreTests/GeometryTests.swift +0 -173
- package/ios/Tests/PdfCanvasCoreTests/PreviewTests.swift +0 -114
- package/ios/Tests/PdfCanvasCoreTests/RasterAssertions.swift +0 -158
- package/ios/Tests/PdfCanvasCoreTests/RasterizerTests.swift +0 -544
- package/ios/Tests/PdfCanvasCoreTests/SinkTests.swift +0 -287
- package/ios/Tests/PdfCanvasCoreTests/SlotsTests.swift +0 -396
- package/ios/Tests/PdfCanvasCoreTests/TestPdfs.swift +0 -639
- package/ios/Tests/PdfCanvasCoreTests/TimingTests.swift +0 -179
- 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
|