Merge pull request #16106 from bungeman/improve_color_stop_detection
Better approximate gradient color stops
This commit is contained in:
commit
a24e11a91c
@ -157,10 +157,9 @@ class RadialAxialShading extends BaseShading {
|
||||
const fnObj = dict.getRaw("Function");
|
||||
const fn = pdfFunctionFactory.createFromArray(fnObj);
|
||||
|
||||
// 10 samples seems good enough for now, but probably won't work
|
||||
// if there are sharp color changes. Ideally, we would implement
|
||||
// the spec faithfully and add lossless optimizations.
|
||||
const NUMBER_OF_SAMPLES = 10;
|
||||
// Use lcm(1,2,3,4,5,6,7,8,10) = 840 (including 9 increases this to 2520)
|
||||
// to catch evenly spaced stops. oeis.org/A003418
|
||||
const NUMBER_OF_SAMPLES = 840;
|
||||
const step = (t1 - t0) / NUMBER_OF_SAMPLES;
|
||||
|
||||
const colorStops = (this.colorStops = []);
|
||||
@ -176,13 +175,80 @@ class RadialAxialShading extends BaseShading {
|
||||
const color = new Float32Array(cs.numComps),
|
||||
ratio = new Float32Array(1);
|
||||
let rgbColor;
|
||||
for (let i = 0; i <= NUMBER_OF_SAMPLES; i++) {
|
||||
|
||||
let iBase = 0;
|
||||
ratio[0] = t0;
|
||||
fn(ratio, 0, color, 0);
|
||||
let rgbBase = cs.getRgb(color, 0);
|
||||
const cssColorBase = Util.makeHexColor(rgbBase[0], rgbBase[1], rgbBase[2]);
|
||||
colorStops.push([0, cssColorBase]);
|
||||
|
||||
let iPrev = 1;
|
||||
ratio[0] = t0 + step;
|
||||
fn(ratio, 0, color, 0);
|
||||
let rgbPrev = cs.getRgb(color, 0);
|
||||
|
||||
// Slopes are rise / run.
|
||||
// A max slope is from the least value the base component could have been
|
||||
// to the greatest value the current component could have been.
|
||||
// A min slope is from the greatest value the base component could have been
|
||||
// to the least value the current component could have been.
|
||||
// Each component could have been rounded up to .5 from its original value
|
||||
// so the conservative deltas are +-1 (+-.5 for base and -+.5 for current).
|
||||
|
||||
// The run is iPrev - iBase = 1, so omitted.
|
||||
let maxSlopeR = rgbPrev[0] - rgbBase[0] + 1;
|
||||
let maxSlopeG = rgbPrev[1] - rgbBase[1] + 1;
|
||||
let maxSlopeB = rgbPrev[2] - rgbBase[2] + 1;
|
||||
let minSlopeR = rgbPrev[0] - rgbBase[0] - 1;
|
||||
let minSlopeG = rgbPrev[1] - rgbBase[1] - 1;
|
||||
let minSlopeB = rgbPrev[2] - rgbBase[2] - 1;
|
||||
|
||||
for (let i = 2; i < NUMBER_OF_SAMPLES; i++) {
|
||||
ratio[0] = t0 + i * step;
|
||||
fn(ratio, 0, color, 0);
|
||||
rgbColor = cs.getRgb(color, 0);
|
||||
const cssColor = Util.makeHexColor(rgbColor[0], rgbColor[1], rgbColor[2]);
|
||||
colorStops.push([i / NUMBER_OF_SAMPLES, cssColor]);
|
||||
|
||||
// Keep going if the maximum minimum slope <= the minimum maximum slope.
|
||||
// Otherwise add a rgbPrev color stop and make it the new base.
|
||||
|
||||
const run = i - iBase;
|
||||
maxSlopeR = Math.min(maxSlopeR, (rgbColor[0] - rgbBase[0] + 1) / run);
|
||||
maxSlopeG = Math.min(maxSlopeG, (rgbColor[1] - rgbBase[1] + 1) / run);
|
||||
maxSlopeB = Math.min(maxSlopeB, (rgbColor[2] - rgbBase[2] + 1) / run);
|
||||
minSlopeR = Math.max(minSlopeR, (rgbColor[0] - rgbBase[0] - 1) / run);
|
||||
minSlopeG = Math.max(minSlopeG, (rgbColor[1] - rgbBase[1] - 1) / run);
|
||||
minSlopeB = Math.max(minSlopeB, (rgbColor[2] - rgbBase[2] - 1) / run);
|
||||
|
||||
const slopesExist =
|
||||
minSlopeR <= maxSlopeR &&
|
||||
minSlopeG <= maxSlopeG &&
|
||||
minSlopeB <= maxSlopeB;
|
||||
|
||||
if (!slopesExist) {
|
||||
const cssColor = Util.makeHexColor(rgbPrev[0], rgbPrev[1], rgbPrev[2]);
|
||||
colorStops.push([iPrev / NUMBER_OF_SAMPLES, cssColor]);
|
||||
|
||||
// TODO: When fn frequency is high (iPrev - iBase === 1 twice in a row),
|
||||
// send the color space and function to do the sampling display side.
|
||||
|
||||
// The run is i - iPrev = 1, so omitted.
|
||||
maxSlopeR = rgbColor[0] - rgbPrev[0] + 1;
|
||||
maxSlopeG = rgbColor[1] - rgbPrev[1] + 1;
|
||||
maxSlopeB = rgbColor[2] - rgbPrev[2] + 1;
|
||||
minSlopeR = rgbColor[0] - rgbPrev[0] - 1;
|
||||
minSlopeG = rgbColor[1] - rgbPrev[1] - 1;
|
||||
minSlopeB = rgbColor[2] - rgbPrev[2] - 1;
|
||||
|
||||
iBase = iPrev;
|
||||
rgbBase = rgbPrev;
|
||||
}
|
||||
|
||||
iPrev = i;
|
||||
rgbPrev = rgbColor;
|
||||
}
|
||||
const cssColor = Util.makeHexColor(rgbPrev[0], rgbPrev[1], rgbPrev[2]);
|
||||
colorStops.push([1, cssColor]);
|
||||
|
||||
let background = "transparent";
|
||||
if (dict.has("Background")) {
|
||||
|
2
test/pdfs/.gitignore
vendored
2
test/pdfs/.gitignore
vendored
@ -345,6 +345,7 @@
|
||||
!issue12810.pdf
|
||||
!bug866395.pdf
|
||||
!issue12010_reduced.pdf
|
||||
!issue10572.pdf
|
||||
!issue11718_reduced.pdf
|
||||
!bug1027533.pdf
|
||||
!bug1028735.pdf
|
||||
@ -534,6 +535,7 @@
|
||||
!issue15012.pdf
|
||||
!issue15150.pdf
|
||||
!poppler-395-0-fuzzed.pdf
|
||||
!issue14165.pdf
|
||||
!GHOSTSCRIPT-698804-1-fuzzed.pdf
|
||||
!issue14814.pdf
|
||||
!poppler-91414-0-53.pdf
|
||||
|
374
test/pdfs/issue10572.pdf
Normal file
374
test/pdfs/issue10572.pdf
Normal file
@ -0,0 +1,374 @@
|
||||
%PDF-1.5
|
||||
%¿÷¢þ
|
||||
%QDF-1.0
|
||||
|
||||
%% Original object ID: 20 0
|
||||
1 0 obj
|
||||
<<
|
||||
/Pages 3 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 19 0
|
||||
2 0 obj
|
||||
<<
|
||||
/Creator (cairo 1.9.5 \(http://cairographics.org\))
|
||||
/Producer (cairo 1.9.5 \(http://cairographics.org\))
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 1 0
|
||||
3 0 obj
|
||||
<<
|
||||
/Count 1
|
||||
/Kids [
|
||||
4 0 R
|
||||
]
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Page 1
|
||||
%% Original object ID: 7 0
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 5 0 R
|
||||
/Group <<
|
||||
/CS /DeviceRGB
|
||||
/S /Transparency
|
||||
/Type /Group
|
||||
>>
|
||||
/MediaBox [
|
||||
0
|
||||
0
|
||||
612
|
||||
792
|
||||
]
|
||||
/Parent 3 0 R
|
||||
/Resources 7 0 R
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Contents for page 1
|
||||
%% Original object ID: 3 0
|
||||
5 0 obj
|
||||
<<
|
||||
/Length 6 0 R
|
||||
>>
|
||||
stream
|
||||
q
|
||||
Q q
|
||||
54 738 504 -661.699 re W n
|
||||
1 1 1 rg /a0 gs
|
||||
54 738 504 -661.699 re f
|
||||
Q q
|
||||
61 716 225 -450 re W n
|
||||
q /Pattern cs /p5 scn /a0 gs
|
||||
61 716 225 -450 re f
|
||||
Q
|
||||
Q q
|
||||
54 738 504 -661.699 re W n
|
||||
0 0 0 RG /a0 gs
|
||||
1 w
|
||||
0 J
|
||||
0 j
|
||||
[] 0.0 d
|
||||
10 M 60.5 716.5 226 -451 re S
|
||||
56 736 424 -23 re W n
|
||||
Q q
|
||||
Q
|
||||
endstream
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
279
|
||||
endobj
|
||||
|
||||
%% Original object ID: 2 0
|
||||
7 0 obj
|
||||
<<
|
||||
/ExtGState <<
|
||||
/a0 <<
|
||||
/CA 1
|
||||
/ca 1
|
||||
>>
|
||||
>>
|
||||
/Pattern <<
|
||||
/p5 9 0 R
|
||||
>>
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 6 0
|
||||
8 0 obj
|
||||
<<
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 5 0
|
||||
9 0 obj
|
||||
<<
|
||||
/Matrix [
|
||||
1
|
||||
0
|
||||
0
|
||||
-1
|
||||
61
|
||||
716
|
||||
]
|
||||
/PatternType 2
|
||||
/Shading <<
|
||||
/ColorSpace /DeviceRGB
|
||||
/Coords [
|
||||
112.5
|
||||
-900
|
||||
112.5
|
||||
900
|
||||
]
|
||||
/Domain [
|
||||
-6
|
||||
6
|
||||
]
|
||||
/Extend [
|
||||
false
|
||||
false
|
||||
]
|
||||
/Function 13 0 R
|
||||
/ShadingType 2
|
||||
>>
|
||||
/Type /Pattern
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 18 0
|
||||
10 0 obj
|
||||
<<
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 15 0
|
||||
11 0 obj
|
||||
<<
|
||||
/Length 12 0 R
|
||||
>>
|
||||
stream
|
||||
endstream
|
||||
endobj
|
||||
|
||||
12 0 obj
|
||||
0
|
||||
endobj
|
||||
|
||||
%% Original object ID: 12 0
|
||||
13 0 obj
|
||||
<<
|
||||
/Bounds [
|
||||
-5
|
||||
-4
|
||||
-3
|
||||
-2
|
||||
-1
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
]
|
||||
/Domain [
|
||||
-6
|
||||
6
|
||||
]
|
||||
/Encode [
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
]
|
||||
/FunctionType 3
|
||||
/Functions [
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
15 0 R
|
||||
]
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 17 0
|
||||
14 0 obj
|
||||
<<
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 11 0
|
||||
15 0 obj
|
||||
<<
|
||||
/Bounds [
|
||||
0.5
|
||||
0.5
|
||||
]
|
||||
/Domain [
|
||||
0
|
||||
1
|
||||
]
|
||||
/Encode [
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
0
|
||||
1
|
||||
]
|
||||
/FunctionType 3
|
||||
/Functions [
|
||||
18 0 R
|
||||
19 0 R
|
||||
20 0 R
|
||||
]
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 13 0
|
||||
16 0 obj
|
||||
<<
|
||||
/Length1 9948
|
||||
/Length 17 0 R
|
||||
>>
|
||||
stream
|
||||
endstream
|
||||
endobj
|
||||
|
||||
%QDF: ignore_newline
|
||||
17 0 obj
|
||||
0
|
||||
endobj
|
||||
|
||||
%% Original object ID: 8 0
|
||||
18 0 obj
|
||||
<<
|
||||
/C0 [
|
||||
0
|
||||
1
|
||||
0
|
||||
]
|
||||
/C1 [
|
||||
0
|
||||
1
|
||||
0
|
||||
]
|
||||
/Domain [
|
||||
0
|
||||
1
|
||||
]
|
||||
/FunctionType 2
|
||||
/N 1
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 9 0
|
||||
19 0 obj
|
||||
<<
|
||||
/C0 [
|
||||
0
|
||||
1
|
||||
0
|
||||
]
|
||||
/C1 [
|
||||
0
|
||||
0
|
||||
1
|
||||
]
|
||||
/Domain [
|
||||
0
|
||||
1
|
||||
]
|
||||
/FunctionType 2
|
||||
/N 1
|
||||
>>
|
||||
endobj
|
||||
|
||||
%% Original object ID: 10 0
|
||||
20 0 obj
|
||||
<<
|
||||
/C0 [
|
||||
0
|
||||
0
|
||||
1
|
||||
]
|
||||
/C1 [
|
||||
0
|
||||
0
|
||||
1
|
||||
]
|
||||
/Domain [
|
||||
0
|
||||
1
|
||||
]
|
||||
/FunctionType 2
|
||||
/N 1
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 21
|
||||
0000000000 65535 f
|
||||
0000000053 00000 n
|
||||
0000000135 00000 n
|
||||
0000000293 00000 n
|
||||
0000000402 00000 n
|
||||
0000000661 00000 n
|
||||
0000000995 00000 n
|
||||
0000001042 00000 n
|
||||
0000001187 00000 n
|
||||
0000001236 00000 n
|
||||
0000001608 00000 n
|
||||
0000001659 00000 n
|
||||
0000001716 00000 n
|
||||
0000001763 00000 n
|
||||
0000002259 00000 n
|
||||
0000002310 00000 n
|
||||
0000002543 00000 n
|
||||
0000002637 00000 n
|
||||
0000002683 00000 n
|
||||
0000002846 00000 n
|
||||
0000003010 00000 n
|
||||
trailer <<
|
||||
/Info 2 0 R
|
||||
/Root 1 0 R
|
||||
/Size 21
|
||||
/ID [<68de518de1319b4dc1c1bfbdee95b02c><68de518de1319b4dc1c1bfbdee95b02c>]
|
||||
>>
|
||||
startxref
|
||||
3146
|
||||
%%EOF
|
336
test/pdfs/issue14165.pdf
Normal file
336
test/pdfs/issue14165.pdf
Normal file
File diff suppressed because one or more lines are too long
@ -5407,6 +5407,12 @@
|
||||
"enableXfa": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue14165",
|
||||
"file": "pdfs/issue14165.pdf",
|
||||
"md5": "917850af2a387475b34b00010200897d",
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "scorecard_reduced",
|
||||
"file": "pdfs/scorecard_reduced.pdf",
|
||||
"md5": "aa8ed0827092c963eea64adb718a3806",
|
||||
@ -6282,6 +6288,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "id": "issue10572",
|
||||
"file": "pdfs/issue10572.pdf",
|
||||
"md5": "48ad69ed106338b3c6845fc7101488b2",
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue11931",
|
||||
"file": "pdfs/issue11931.pdf",
|
||||
"md5": "9ea233037992e1f10280420a49e72845",
|
||||
|
Loading…
Reference in New Issue
Block a user