Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
532d65a355 | ||
|
|
9de38afb13 | ||
|
|
913c939dc9 | ||
|
|
9db9a3d6ec | ||
|
|
8423bd549b | ||
|
|
336d274a54 | ||
|
|
906d77b389 | ||
|
|
9416e850ff | ||
|
|
fd3248869c | ||
|
|
2a09a668f6 | ||
|
|
e788dde607 | ||
|
|
173a80864d | ||
|
|
aa115a8be3 | ||
|
|
e0441c4aa1 | ||
|
|
a861c58da2 | ||
|
|
b1306bd7a8 | ||
|
|
3a6eb383dc | ||
|
|
6c942ecefd | ||
|
|
a25f8ecc62 | ||
|
|
e1f4813d94 | ||
|
|
af526f078d | ||
|
|
16438c1312 | ||
|
|
dd6cb7ce20 | ||
|
|
653e2e23df | ||
|
|
a2033698fa | ||
|
|
ec1d585d40 | ||
|
|
a4e1f8e1f3 | ||
|
|
2e155c31bf | ||
|
|
e09ae9c68a | ||
|
|
c5bf1dd90d | ||
|
|
e96770c5e4 | ||
|
|
f4f0f3c022 | ||
|
|
0a42934c08 | ||
|
|
d8f47768f9 | ||
|
|
c9594a4a5f | ||
|
|
873f915212 | ||
|
|
079c162a96 | ||
|
|
25c8c4656f | ||
|
|
ffcae9a1a0 | ||
|
|
6e71fe1186 | ||
|
|
0885799010 | ||
|
|
8ffc99f648 | ||
|
|
2261c51eff | ||
|
|
5c470778a3 | ||
|
|
4124889f36 | ||
|
|
a23c22b0e8 | ||
|
|
dd1f5f7215 | ||
|
|
5e2206bae7 | ||
|
|
079ee86d43 | ||
|
|
3692868004 | ||
|
|
064f935699 | ||
|
|
8770fff968 | ||
|
|
82de78b6b0 | ||
|
|
2a52c6dec2 | ||
|
|
2898879be7 | ||
|
|
18e613657c | ||
|
|
a48ca556c7 | ||
|
|
9cba738b48 | ||
|
|
bccf2f423f | ||
|
|
390fdf8c05 | ||
|
|
166de3086b | ||
|
|
206c675df6 | ||
|
|
6c8f9223e9 | ||
|
|
85c6a974ca | ||
|
|
dccdcfaa91 | ||
|
|
b1da09f141 | ||
|
|
42c84531e4 | ||
|
|
a9ad805347 | ||
|
|
16bda74974 | ||
|
|
d274d88929 | ||
|
|
327df5cbbc | ||
|
|
46d0632fe2 | ||
|
|
ef1e7a814e | ||
|
|
1084724937 | ||
|
|
ecb0109d79 | ||
|
|
386cabff00 | ||
|
|
3bd5054634 | ||
|
|
6a8dd65aa2 | ||
|
|
6083b4f0a7 | ||
|
|
1a3ce59476 | ||
|
|
c395436ba3 | ||
|
|
8d23d0b441 | ||
|
|
c6a2716cdb | ||
|
|
5545bae76f | ||
|
|
7bccb8c748 | ||
|
|
173c0d1274 | ||
|
|
6953f32465 | ||
|
|
26b4d9bb4b | ||
|
|
34e564cd7d | ||
|
|
504d5776d2 | ||
|
|
ee23976858 | ||
|
|
f559316881 | ||
|
|
084610c242 | ||
|
|
9ff627472b | ||
|
|
956310d1ec | ||
|
|
1a982da442 | ||
|
|
4879a1f0de | ||
|
|
ce66bcc9c8 | ||
|
|
1ebf3144af | ||
|
|
7a1cccbc4e | ||
|
|
ebacff1b39 | ||
|
|
c7c447be66 | ||
|
|
91aa175602 | ||
|
|
b267494e4a | ||
|
|
f687180ecc | ||
|
|
6f4b38b103 | ||
|
|
d32324859c | ||
|
|
48222b87b5 | ||
|
|
62e5edc72b | ||
|
|
2846d46bb8 | ||
|
|
47ef1914d4 | ||
|
|
df157552f3 | ||
|
|
0b3a526049 | ||
|
|
1e80d412fa | ||
|
|
df6e106203 | ||
|
|
bd0f005861 | ||
|
|
6ba4b7b3f3 | ||
|
|
2c11349ee8 | ||
|
|
b0afef09ef | ||
|
|
72fa347c38 | ||
|
|
96d68c2413 | ||
|
|
babc76fa74 | ||
|
|
dc06990e5d | ||
|
|
0ff0d2f8d1 | ||
|
|
81602cf420 | ||
|
|
607e2d7e81 | ||
|
|
b01d9e07e8 | ||
|
|
91db94cf2e | ||
|
|
416df803d4 | ||
|
|
037b96ca16 | ||
|
|
bb258fc99c | ||
|
|
4b8ccbe8cb | ||
|
|
ab1ff3331b | ||
|
|
3675ae918c | ||
|
|
0ba32b96b7 | ||
|
|
add64e4fa2 | ||
|
|
7fe2954ede | ||
|
|
ad202693b3 | ||
|
|
594ef83551 | ||
|
|
78b71618c1 | ||
|
|
b8aa89e1ec | ||
|
|
b4c1f66bc1 | ||
|
|
5172dbde8d | ||
|
|
d2908640c6 | ||
|
|
997bf7578d | ||
|
|
043258242c | ||
|
|
156d5d9a9c | ||
|
|
0b7e52fb5e | ||
|
|
a5feef07d0 | ||
|
|
f11bb53e61 | ||
|
|
68a57a7839 | ||
|
|
4194430dc1 | ||
|
|
a707c56fae | ||
|
|
3cba50bfbd | ||
|
|
ed5e17d0a4 | ||
|
|
ce0e0ecd4d | ||
|
|
7e1223c12c | ||
|
|
b83d7f6d1a | ||
|
|
80e957908a | ||
|
|
f0e7bea8ba | ||
|
|
0cdb9bd04a | ||
|
|
8224d89bc6 | ||
|
|
a2bbbe2a26 | ||
|
|
43f41863fa | ||
|
|
d71e50e83d | ||
|
|
1f598da3c1 | ||
|
|
d0cdbd5e1c | ||
|
|
5c56f61209 | ||
|
|
9bec85470a | ||
|
|
a03863a17d | ||
|
|
22cd9b2364 | ||
|
|
4fc7d6d93e | ||
|
|
71f0e7f545 | ||
|
|
895fddd85e | ||
|
|
5a59e4d543 | ||
|
|
b51abf2249 | ||
|
|
6d3f9ff15a | ||
|
|
5d1d1a712b | ||
|
|
6d5f8133e0 | ||
|
|
13018d3d5c | ||
|
|
14a85f9473 | ||
|
|
d22a1b3367 | ||
|
|
b913e5dfef | ||
|
|
dd8a5a4c72 | ||
|
|
36e9a54f02 | ||
|
|
3707af3b74 | ||
|
|
ced7ad9164 | ||
|
|
54bbbfdeb3 | ||
|
|
7f73a6ed1e | ||
|
|
dce206d3dc | ||
|
|
9304c856cf | ||
|
|
e5df98cbdf | ||
|
|
19bf3aeb00 | ||
|
|
e86be0031c | ||
|
|
6425977998 | ||
|
|
d57df2d980 | ||
|
|
664d0c7969 | ||
|
|
a354663ee1 | ||
|
|
b21b048ec4 | ||
|
|
709c65b41a | ||
|
|
67f99c5bb7 | ||
|
|
d55e673d9c | ||
|
|
21b90d2d14 | ||
|
|
2def7e3392 | ||
|
|
b0dcaa7512 | ||
|
|
e8285b1d10 | ||
|
|
5ba56adb53 | ||
|
|
ca735278e0 | ||
|
|
b5ccbfdf25 | ||
|
|
8c35d6e6e4 | ||
|
|
d1e0c81eda | ||
|
|
10c8e4f8b4 | ||
|
|
6be2242c21 | ||
|
|
204c9d6ae1 | ||
|
|
6eb393590b | ||
|
|
07c6654057 | ||
|
|
4e15eb8d14 | ||
|
|
8b01ab8ad2 | ||
|
|
e0a522ad50 | ||
|
|
a1a8788c5a | ||
|
|
cccdc178c3 | ||
|
|
4eacb3454f | ||
|
|
82b8b41e80 | ||
|
|
581c5020ab | ||
|
|
3ef8872a1e | ||
|
|
28eec73eed | ||
|
|
bfe4a5b329 | ||
|
|
29097837d6 | ||
|
|
a40361db3c | ||
|
|
8b29e3cbab | ||
|
|
b170be120b | ||
|
|
9a6cd95e5f | ||
|
|
d464d3122e | ||
|
|
1327ab37d4 | ||
|
|
67553fc5c6 | ||
|
|
306a903854 | ||
|
|
b93cf51c0f | ||
|
|
6b994221c6 | ||
|
|
8b5b02e0d8 | ||
|
|
624df9bb23 | ||
|
|
fa06ea3600 | ||
|
|
31994258fb | ||
|
|
1f15ecbca5 | ||
|
|
bcf5657e5c | ||
|
|
2ae028bf38 | ||
|
|
b51a5887e5 | ||
|
|
fc523e837c | ||
|
|
caeba76a61 | ||
|
|
cd35216f21 | ||
|
|
e6a7b58863 | ||
|
|
56184a762f | ||
|
|
07ab98f5af | ||
|
|
04fb1892b4 | ||
|
|
173ce2f215 | ||
|
|
9b641055e1 | ||
|
|
4fa28d7e74 | ||
|
|
bed74501fc | ||
|
|
8c90f7c972 | ||
|
|
aa0ec40102 | ||
|
|
12c567ee10 | ||
|
|
d39778ce3a | ||
|
|
e824cdbc4e | ||
|
|
1d91c09963 | ||
|
|
e821ca46d5 | ||
|
|
a29e4952fb | ||
|
|
4cc0dc6b4a | ||
|
|
7263702de9 | ||
|
|
0287d91874 | ||
|
|
436af55050 | ||
|
|
d6128e6937 | ||
|
|
642437e804 | ||
|
|
4ce802fdb2 | ||
|
|
a672422b0b | ||
|
|
addc2cbad0 | ||
|
|
5f45f77b4e | ||
|
|
93f9bffb37 | ||
|
|
44149ad319 | ||
|
|
d80d963cea | ||
|
|
4da33b8050 | ||
|
|
5cbbff8472 | ||
|
|
fa6e47c277 | ||
|
|
4ea9cffebd | ||
|
|
ae68edefc5 | ||
|
|
1558e068f1 | ||
|
|
d2a9c413f8 | ||
|
|
a510b21b20 | ||
|
|
e33ba07aa4 | ||
|
|
373f27832b | ||
|
|
b20a6e4c5d | ||
|
|
49734d5456 | ||
|
|
26a415c5dd | ||
|
|
60be64a5f1 | ||
|
|
190294634c | ||
|
|
1722cb579d | ||
|
|
dc42beb6a8 | ||
|
|
378f543619 | ||
|
|
62924ee280 | ||
|
|
86a73191b0 | ||
|
|
86875997b8 | ||
|
|
b939584c7a | ||
|
|
bbd174071d | ||
|
|
e5b6fe1317 | ||
|
|
f15d9049eb | ||
|
|
7630c93e5b | ||
|
|
638d68aa8a | ||
|
|
a92dde058a | ||
|
|
580f2ebb4b | ||
|
|
01cae7a584 | ||
|
|
66337813e6 | ||
|
|
eb5a211e72 | ||
|
|
5142933120 | ||
|
|
06ab114aa8 | ||
|
|
1257419465 | ||
|
|
30404f53f0 | ||
|
|
1ce8edbdfe | ||
|
|
d4b704a0ae | ||
|
|
2d64e1536d | ||
|
|
c8b581ac31 | ||
|
|
ad8dead7df | ||
|
|
c9bd87254e | ||
|
|
f4cb424451 | ||
|
|
fef14778d5 | ||
|
|
86ec63f215 | ||
|
|
5b10ec9d39 | ||
|
|
800c75c4e5 | ||
|
|
24d64b04c3 | ||
|
|
48e2750551 | ||
|
|
e182c5f63e | ||
|
|
06d52326db | ||
|
|
ebfe4f0d29 | ||
|
|
ad22977c84 | ||
|
|
6ac50646f0 | ||
|
|
24b6a4ad50 | ||
|
|
e802896d4d | ||
|
|
0b5a20e593 | ||
|
|
642998ead6 | ||
|
|
698aab4f75 | ||
|
|
34231ac667 | ||
|
|
ddedf7cd2e | ||
|
|
9d127d354c | ||
|
|
2d2a4894ab | ||
|
|
862861e3ca | ||
|
|
892db88f0e | ||
|
|
eeb44f78cc | ||
|
|
863835f660 | ||
|
|
393c5a9ea4 | ||
|
|
c6b9a49cbb | ||
|
|
17a4831745 | ||
|
|
7caf1e85ff | ||
|
|
f59a757e8b | ||
|
|
872bafad4b | ||
|
|
8599400445 | ||
|
|
b6eebadf05 | ||
|
|
a4e88eb8f0 | ||
|
|
f6257c2183 | ||
|
|
64891c2fc3 | ||
|
|
fe156db41d | ||
|
|
0f942fb714 | ||
|
|
be8ca589d4 | ||
|
|
3b6f6782f0 | ||
|
|
21c0e045cb | ||
|
|
ebbf68bd08 | ||
|
|
2059e916da | ||
|
|
c22f245606 | ||
|
|
7b9025f397 | ||
|
|
b109445215 | ||
|
|
fd1cd8e50a | ||
|
|
c6c70c2171 | ||
|
|
a9a473f2e5 | ||
|
|
6268e2faff | ||
|
|
ec3f506500 | ||
|
|
00daa51a73 | ||
|
|
e60f4d3f43 | ||
|
|
7460745f80 | ||
|
|
5e14d5b0dd | ||
|
|
d118132fa6 | ||
|
|
5f47aac36f | ||
|
|
c6b2fa8851 | ||
|
|
1b92f447c3 | ||
|
|
82e7eb91d2 | ||
|
|
4f4ad0fb76 | ||
|
|
1d0b8641a0 | ||
|
|
daca919775 | ||
|
|
1598f2f0e5 | ||
|
|
2b23f7ec73 | ||
|
|
6528234608 | ||
|
|
642ebc6098 | ||
|
|
74fdfeea3f | ||
|
|
3754185f56 | ||
|
|
df9f5157bd | ||
|
|
aa060db5bc | ||
|
|
d43212d30b | ||
|
|
a0f9ca3a30 | ||
|
|
0cefe886ec | ||
|
|
f656c00f41 | ||
|
|
03da34ee24 | ||
|
|
9bccff4f88 | ||
|
|
2bd586e093 | ||
|
|
9af94ac9b7 | ||
|
|
8174089c8b | ||
|
|
41eb54cc0a | ||
|
|
12a2f78c4d | ||
|
|
d372f1f7fa | ||
|
|
6f5b75bcd0 | ||
|
|
a2d3e0b53e | ||
|
|
7f67556995 | ||
|
|
db8c37e58c | ||
|
|
a87c81a64f | ||
|
|
4b986a5943 | ||
|
|
2fae9b655e | ||
|
|
2541f6cf89 | ||
|
|
33b68454f3 | ||
|
|
977665d2b6 | ||
|
|
fd7497f00d | ||
|
|
790ff58f67 | ||
|
|
4b98ce391b | ||
|
|
417dbd43f6 | ||
|
|
7a12908db9 | ||
|
|
9462f0a28f | ||
|
|
e760622a5c | ||
|
|
1b086f60a9 | ||
|
|
85cbf94a6e | ||
|
|
6f4286e1b1 | ||
|
|
39888ae8c9 | ||
|
|
dd361ecd05 | ||
|
|
32759c9025 | ||
|
|
59440448ee | ||
|
|
51b54893ce | ||
|
|
1f3665f614 | ||
|
|
75c34b873a | ||
|
|
fe4296c53b | ||
|
|
c85278b31d | ||
|
|
5dbc080fa0 | ||
|
|
e02f6c1e97 | ||
|
|
8c9a8fc85c | ||
|
|
23d558ad8c | ||
|
|
be107b4fed | ||
|
|
8d2535e327 | ||
|
|
5eb4fe0052 | ||
|
|
d8ff4485f8 | ||
|
|
82bce463ae | ||
|
|
016dfd420c | ||
|
|
b59e761a14 | ||
|
|
17cd655752 | ||
|
|
b840b16c82 | ||
|
|
8f5c95f0f4 | ||
|
|
168fc60774 | ||
|
|
c84d0f606d | ||
|
|
8b54ce338f | ||
|
|
18c4aa10bf | ||
|
|
991db17fde | ||
|
|
2c07515907 | ||
|
|
27a3b80376 | ||
|
|
8c381a0227 | ||
|
|
86145a8c76 | ||
|
|
7513f5425c | ||
|
|
af3c3c6466 | ||
|
|
db3e75e33e | ||
|
|
ce49fc26dd | ||
|
|
d0d0a98dca | ||
|
|
3834d1a0bf | ||
|
|
33e982b3fd | ||
|
|
43d650e78c | ||
|
|
b4c65c5781 | ||
|
|
d96867e6ab | ||
|
|
0a5108e704 | ||
|
|
94c52a6fa3 | ||
|
|
57771f06a3 | ||
|
|
58abb5785c | ||
|
|
509e75eaff | ||
|
|
0c50eedb2a | ||
|
|
4581027246 | ||
|
|
31b5f63f85 | ||
|
|
957fb1494e | ||
|
|
9e3e4f2687 | ||
|
|
2155bcacb4 | ||
|
|
346da95899 | ||
|
|
f4f7946a0c | ||
|
|
c2919f2e1c | ||
|
|
a63d624052 | ||
|
|
af91489376 | ||
|
|
d146d2b65c | ||
|
|
4ff4ed24a8 | ||
|
|
c38ff90081 | ||
|
|
4c029e973f | ||
|
|
21cf9029e8 | ||
|
|
4a640b8dcd | ||
|
|
9471bc8921 | ||
|
|
7fe06c64fc | ||
|
|
d13d70fd56 | ||
|
|
58ec56180a | ||
|
|
32a88f1bad | ||
|
|
99ef42940c | ||
|
|
c152710617 | ||
|
|
8de0f9b86f | ||
|
|
23bc3d3a29 | ||
|
|
8307832ce9 | ||
|
|
dd1cf567db | ||
|
|
2490be8490 | ||
|
|
85e6c6669a | ||
|
|
00498282f5 | ||
|
|
e4cc9fcba7 | ||
|
|
a4555b1dae | ||
|
|
f35a2303bb | ||
|
|
82142fe5ef | ||
|
|
9be533b5f4 | ||
|
|
99653fcd32 | ||
|
|
5442c97ed8 | ||
|
|
0165255bd9 | ||
|
|
378e4dae3b | ||
|
|
cdf5afa753 | ||
|
|
a2deee4920 | ||
|
|
1efa79cce2 | ||
|
|
b3b61c152c | ||
|
|
e429c3d729 | ||
|
|
8308b20096 | ||
|
|
8b41f60b6e | ||
|
|
d56f749017 | ||
|
|
9f31774aa9 | ||
|
|
7d55f6e01f | ||
|
|
c3bd2f296d | ||
|
|
e40c60d4d8 | ||
|
|
3960232ae0 | ||
|
|
5fbb3fc6ac | ||
|
|
0b1db8fccd | ||
|
|
0417610f9b | ||
|
|
43a23e3695 | ||
|
|
c4ca572afd | ||
|
|
e04e4565a9 | ||
|
|
2391fb0be0 | ||
|
|
c16f79d51b | ||
|
|
e3e888efde | ||
|
|
84f7e34ace | ||
|
|
32e2175891 | ||
|
|
975abfde9a | ||
|
|
d929ed76c2 | ||
|
|
4a27124eab | ||
|
|
683ffb84e8 | ||
|
|
2f2602357b | ||
|
|
a5f429f499 | ||
|
|
bdb7f92131 | ||
|
|
09f15ac4c0 | ||
|
|
4fdbf55c11 | ||
|
|
fe2b07652b | ||
|
|
f6d7aa6e33 | ||
|
|
a005d14f91 | ||
|
|
6f66232d44 | ||
|
|
b8a780d684 | ||
|
|
82f393dd09 | ||
|
|
4952af1604 | ||
|
|
bcf77375c0 | ||
|
|
3eab161771 | ||
|
|
b7f38e976b | ||
|
|
a6567f2ae4 | ||
|
|
e860c56b75 | ||
|
|
2e15d52895 | ||
|
|
ce97af5a79 | ||
|
|
3831c4cd4d | ||
|
|
61a2674317 | ||
|
|
9ad8cbf1f6 | ||
|
|
123fde174d | ||
|
|
fd991a2380 | ||
|
|
6f5d77d930 | ||
|
|
5169ac633b | ||
|
|
5b6ab1e003 | ||
|
|
8f984bf958 | ||
|
|
9c5f0d0ec6 | ||
|
|
32041c43e1 | ||
|
|
599028bebb | ||
|
|
6faa8f7221 | ||
|
|
a4dc5e365f | ||
|
|
e2a563cc76 | ||
|
|
1037d73efb | ||
|
|
aeb7b142a9 | ||
|
|
422ea9777e | ||
|
|
2f1c743227 | ||
|
|
96ee21aee9 | ||
|
|
4b759af6ff | ||
|
|
25d2b0cda4 | ||
|
|
16dd8b54a8 | ||
|
|
c4dc5269d2 | ||
|
|
c36e9950ae | ||
|
|
0c0d53b10f | ||
|
|
63de7e1677 | ||
|
|
b0e92760a2 | ||
|
|
054c0773a3 | ||
|
|
89aa78b724 | ||
|
|
708113a514 | ||
|
|
95ef5410c2 | ||
|
|
868b3b4abd | ||
|
|
045bdff95a | ||
|
|
d12b27ac1d | ||
|
|
e4e00de79f | ||
|
|
a53a3937c2 | ||
|
|
343424b4d2 | ||
|
|
c5edff2c2f | ||
|
|
8c5f8b8ddd | ||
|
|
39da931a56 | ||
|
|
9fe354359b | ||
|
|
facc4750bc | ||
|
|
437c235738 | ||
|
|
9559b0b186 | ||
|
|
91456e19a4 | ||
|
|
a2d89f67c4 | ||
|
|
f34130d193 | ||
|
|
c5571388e2 | ||
|
|
9af59c0d6d | ||
|
|
55ae838cb7 | ||
|
|
c434b97f55 | ||
|
|
607eee198d | ||
|
|
5e2a7f8a56 | ||
|
|
fd9550acda | ||
|
|
b354511ac9 | ||
|
|
7be293f628 | ||
|
|
65855dc14c | ||
|
|
cac4a8b9b6 | ||
|
|
17d97b354a | ||
|
|
1c1b60fa9f | ||
|
|
6b745d892f | ||
|
|
fbf271a3ec | ||
|
|
8077718804 | ||
|
|
66bda3420a | ||
|
|
f6510e2b15 | ||
|
|
51abd79136 | ||
|
|
5607429d9a | ||
|
|
b8b7ecfe7f | ||
|
|
d4abe88452 | ||
|
|
cb3cfaa055 | ||
|
|
9db01c7ff5 | ||
|
|
d0301813cc | ||
|
|
cff37bf681 | ||
|
|
66d04dd6e3 | ||
|
|
06a1f987d4 | ||
|
|
e51e21c6b6 | ||
|
|
c5fa72bd4e | ||
|
|
bf99587aa1 | ||
|
|
d249aef57d | ||
|
|
43ab7c88d7 | ||
|
|
ca9669742d | ||
|
|
8a1dddc3ee | ||
|
|
0cd424ffcb | ||
|
|
fde550f9a7 | ||
|
|
a3726e4ce3 | ||
|
|
4ab0a8ff35 | ||
|
|
37f6f72df3 | ||
|
|
3f92867ae6 | ||
|
|
e63503d64b | ||
|
|
17d20309c7 | ||
|
|
fe7c69ce95 | ||
|
|
9baccee8c5 | ||
|
|
d5bb9929f3 | ||
|
|
72d3ee3a87 | ||
|
|
17c419dfcb | ||
|
|
84cc49b14b | ||
|
|
b7f63bc93d | ||
|
|
ad9a3b5302 | ||
|
|
4e4bcaf243 | ||
|
|
11afe3507f | ||
|
|
7691ba8535 | ||
|
|
b787a369ee | ||
|
|
9fb8b267af | ||
|
|
0a08d6ce1f | ||
|
|
f517efe819 | ||
|
|
5f5421f23d | ||
|
|
703b6db95c | ||
|
|
000040d497 | ||
|
|
5bd6665b49 | ||
|
|
1c303afe21 | ||
|
|
11a5c80917 | ||
|
|
9b2ab92913 | ||
|
|
0c4b69ec5a | ||
|
|
45bea1c0e0 | ||
|
|
db914d4cd1 | ||
|
|
df4a8faecd | ||
|
|
1273e7aeda | ||
|
|
e13a673b1a | ||
|
|
979b0bcaed | ||
|
|
3438afaffe | ||
|
|
681fa039cc | ||
|
|
69e80f1545 | ||
|
|
983835cce4 | ||
|
|
6c23b137e2 | ||
|
|
d656b2b3f2 | ||
|
|
031b800aac | ||
|
|
05eb85ee77 | ||
|
|
4da5214ca9 | ||
|
|
1ee829dd59 | ||
|
|
99db5d91ae | ||
|
|
3a4490ee36 | ||
|
|
a492e3b472 | ||
|
|
c3719d3b72 | ||
|
|
ad48fc6415 | ||
|
|
7f8018ffde | ||
|
|
80651fe12c | ||
|
|
a58209e895 | ||
|
|
775b958c55 | ||
|
|
cdcdd16865 | ||
|
|
b332d76782 | ||
|
|
3660007fc8 | ||
|
|
b55d7e57af | ||
|
|
6e99e7b346 | ||
|
|
4d26867dee | ||
|
|
78e8bf9cbf | ||
|
|
de61530d4d | ||
|
|
c149f860b5 | ||
|
|
68c852acec | ||
|
|
a8565bac6e | ||
|
|
6e8b0c3194 | ||
|
|
ff860e8362 | ||
|
|
cf4b04c5d1 | ||
|
|
078bc2abe9 | ||
|
|
d7b7ca0574 | ||
|
|
17ac9d7a9a | ||
|
|
a2a197ce4c | ||
|
|
944d59e5ad | ||
|
|
1c3e90a892 | ||
|
|
c728836956 | ||
|
|
0d80fab339 | ||
|
|
a650caa599 | ||
|
|
c6caff90a1 | ||
|
|
671c88d3b5 | ||
|
|
b2cfaedf91 | ||
|
|
19ba3ae011 | ||
|
|
feff1e38bb | ||
|
|
c8d6ea6b10 | ||
|
|
b0d9775343 | ||
|
|
462bfb84fb | ||
|
|
11ef78a891 | ||
|
|
638eb556ef | ||
|
|
fdefcd8af2 | ||
|
|
09457edad3 | ||
|
|
6460a7eb3e | ||
|
|
707ebeb151 | ||
|
|
e9bc093842 | ||
|
|
2eeaca1168 | ||
|
|
7755c5c5a7 | ||
|
|
793348a47c | ||
|
|
b241f66919 | ||
|
|
8ad034a678 | ||
|
|
a1a7b973e9 | ||
|
|
7bfcd0a9d5 | ||
|
|
f276c4ef1e | ||
|
|
77bbc22c50 | ||
|
|
a6805ed343 | ||
|
|
c4afc5c242 | ||
|
|
df32008667 | ||
|
|
db4598f76a | ||
|
|
ce13431ecf | ||
|
|
eb104b405d | ||
|
|
5f00e4f9d8 | ||
|
|
1a91cd4652 | ||
|
|
b0f1a55537 | ||
|
|
0c066d1d53 | ||
|
|
e4cfcec5f3 | ||
|
|
85c90404d7 | ||
|
|
4d011c28ea | ||
|
|
5304c631ec | ||
|
|
6fbeb6347d | ||
|
|
f83de20c37 | ||
|
|
423324af01 | ||
|
|
016a2a01d9 | ||
|
|
6189910c74 | ||
|
|
7117dc10de | ||
|
|
b601cb0cba | ||
|
|
0c781faf89 | ||
|
|
12769b96e5 | ||
|
|
a7b4ed9688 | ||
|
|
ee92ce8717 | ||
|
|
cbeddab35f | ||
|
|
98050534d6 | ||
|
|
9850231e91 | ||
|
|
fd810239b5 | ||
|
|
2cff6ad2d1 | ||
|
|
3ee306184b | ||
|
|
1cc4c45b7e | ||
|
|
a86cb8148a | ||
|
|
eeae6f8292 | ||
|
|
4dab299619 | ||
|
|
340e2bbac6 | ||
|
|
187283192b | ||
|
|
f855bdd36b | ||
|
|
9873d51f58 | ||
|
|
11a57c7a17 | ||
|
|
8aa678859d | ||
|
|
1beb7dfd37 | ||
|
|
9b60d3e285 | ||
|
|
3331a686fa | ||
|
|
c32ea3b374 | ||
|
|
c357d4146e | ||
|
|
f47cb2fade | ||
|
|
9c4b1aeb8d | ||
|
|
51ed381bfc | ||
|
|
5ee45411c9 | ||
|
|
16990890d8 | ||
|
|
cfb11559d5 | ||
|
|
8b8de7cc1d | ||
|
|
aba293fd80 | ||
|
|
066a293462 | ||
|
|
0bbd6885e2 | ||
|
|
5dd10c961c | ||
|
|
81fc95556c | ||
|
|
20ad032977 | ||
|
|
93f1b73579 | ||
|
|
fd427a8ec1 | ||
|
|
9444cf357b | ||
|
|
5ab69153ee | ||
|
|
eb5200d26a | ||
|
|
98a3fda1f5 | ||
|
|
e73740ae9d | ||
|
|
fb933edc0f | ||
|
|
ba41ccae1b | ||
|
|
df9e286e9c | ||
|
|
b9d6e46572 | ||
|
|
8347c0d662 | ||
|
|
45a361d112 | ||
|
|
522e1e948b | ||
|
|
8ed4e229f3 | ||
|
|
db29cae177 | ||
|
|
d5b6cbb95e | ||
|
|
396c39978a | ||
|
|
9d5f23e961 | ||
|
|
26a6232e1c | ||
|
|
7566d4b768 | ||
|
|
5c4c32ab3c | ||
|
|
692f7b3151 | ||
|
|
8d0958d7ea | ||
|
|
e9731b6bac | ||
|
|
0628a89041 | ||
|
|
c14f62752b | ||
|
|
24855045e1 | ||
|
|
ed236e0c27 | ||
|
|
db6aa22eae | ||
|
|
805aa776ad | ||
|
|
d0efdf643c | ||
|
|
22298b31be | ||
|
|
5cecb3ecb4 | ||
|
|
a139e64c67 | ||
|
|
db69b4d11a | ||
|
|
8bcb85720c | ||
|
|
09ca1bee97 | ||
|
|
23dd77ce0f | ||
|
|
32a076c039 | ||
|
|
e4baa8c0dd | ||
|
|
2fdaa76a0d | ||
|
|
7ee0c52a57 | ||
|
|
ac2fc9c2a0 | ||
|
|
188e08e98b | ||
|
|
ef1ef1cdf0 | ||
|
|
24da92d39e | ||
|
|
61afef549e | ||
|
|
cfd67ab6aa | ||
|
|
56067b590b | ||
|
|
4340ad9f12 | ||
|
|
70def4a0d0 | ||
|
|
8df1ea2754 | ||
|
|
e528adc603 | ||
|
|
c1af0fb18d | ||
|
|
0cb4e854e5 | ||
|
|
13ab23ba54 | ||
|
|
19263f00c6 | ||
|
|
50bd129d7a | ||
|
|
471cdea232 | ||
|
|
9d750828c7 | ||
|
|
5e025c3382 | ||
|
|
4410503349 | ||
|
|
486f73d5d6 | ||
|
|
b10285d11b | ||
|
|
c904b430b6 | ||
|
|
07d4fff3d4 | ||
|
|
7e388f59af | ||
|
|
84ec83151d | ||
|
|
0a72c12ff0 | ||
|
|
5adbddd1f9 | ||
|
|
c2fecffdb4 | ||
|
|
7dea0a8362 | ||
|
|
482cb788ed | ||
|
|
15a988b999 | ||
|
|
83398e54ea | ||
|
|
bcdd196699 | ||
|
|
0cd576e701 | ||
|
|
4d5e0eb749 | ||
|
|
7ed0f8f50e | ||
|
|
79c84eefa3 | ||
|
|
5398003160 | ||
|
|
58b2bed99d | ||
|
|
58c29ffb5c | ||
|
|
f615b6f0e8 | ||
|
|
e0c8dadcce | ||
|
|
9a86f53109 | ||
|
|
91cb092aa0 | ||
|
|
f4b87915df | ||
|
|
922a107b7f | ||
|
|
1c44fd4f3b | ||
|
|
c92ccc6134 | ||
|
|
1137534e97 | ||
|
|
39617dd739 | ||
|
|
6590875756 | ||
|
|
01bbf064e0 | ||
|
|
fc1c4f12f5 | ||
|
|
2647382cf6 | ||
|
|
783a128bd1 | ||
|
|
b214aa5b38 | ||
|
|
6e49bb3588 | ||
|
|
aa512b6181 | ||
|
|
a4667b5656 | ||
|
|
f65a3d3762 | ||
|
|
2fa43ecf09 | ||
|
|
427afc0616 | ||
|
|
9c7ee2bf23 | ||
|
|
c5cfaa950b | ||
|
|
4e2a98ead4 | ||
|
|
210f134b5b | ||
|
|
696c0721a0 | ||
|
|
aabab95418 | ||
|
|
7d614dd68b | ||
|
|
f57dda7939 | ||
|
|
1b4542aa77 | ||
|
|
6c7fca57ec | ||
|
|
486dc7e22c | ||
|
|
dc616bb507 | ||
|
|
902bda43e3 | ||
|
|
f7da63f68b | ||
|
|
5da26e4c9c | ||
|
|
c19c852705 | ||
|
|
a27ee3ee8c | ||
|
|
c2f316c2c5 | ||
|
|
974979b0a0 | ||
|
|
66586bdaab | ||
|
|
01d2ea309f | ||
|
|
e918480351 | ||
|
|
52fd84fa95 | ||
|
|
2c56b0935c | ||
|
|
4f69ace868 | ||
|
|
497c531112 | ||
|
|
b27b92fbf3 | ||
|
|
2e6ba2df8c | ||
|
|
67a405c6b7 | ||
|
|
58e6663806 | ||
|
|
602570fcf9 | ||
|
|
691f8ce254 | ||
|
|
22812e74b9 | ||
|
|
9d824e723d | ||
|
|
5dad800d85 | ||
|
|
56a56a4dcb | ||
|
|
3f1d9ef99c | ||
|
|
92c8a5885e | ||
|
|
7749d14252 | ||
|
|
9b92af5aed | ||
|
|
0bf26b03ae | ||
|
|
e2847ea4c3 | ||
|
|
19e35db2b7 | ||
|
|
df688742d5 | ||
|
|
42c2925f9d | ||
|
|
933f0b8f9b | ||
|
|
03ab5a8ee2 | ||
|
|
4f06920224 | ||
|
|
a733b09623 | ||
|
|
5483dacf52 | ||
|
|
ae7844ad88 | ||
|
|
a6e7485da6 | ||
|
|
3bcc6d6121 | ||
|
|
9fe067bbd9 | ||
|
|
f095e91cb4 | ||
|
|
66c8d4b47a | ||
|
|
721489a06c | ||
|
|
9a4493f211 | ||
|
|
edb4d6c586 | ||
|
|
b8cd3acd9e | ||
|
|
03779e33da | ||
|
|
c466483e82 | ||
|
|
e3a58219d1 | ||
|
|
72337094ca | ||
|
|
f472587d22 | ||
|
|
f34b3015b2 | ||
|
|
089ece2715 | ||
|
|
6438465e3f | ||
|
|
7d330afd81 | ||
|
|
68fbd9fcc9 | ||
|
|
c771938907 | ||
|
|
c2a947acf4 | ||
|
|
8c0009c5c8 | ||
|
|
cfc5cdf47d | ||
|
|
05152a8af9 | ||
|
|
0880b16491 | ||
|
|
06308a22ce | ||
|
|
80bd7de580 | ||
|
|
8b90c45437 | ||
|
|
72b920eb16 | ||
|
|
b4a51907d6 | ||
|
|
1ca1221432 | ||
|
|
40b72b0fa8 | ||
|
|
0e55b4ad52 | ||
|
|
7b4f5a8fc4 | ||
|
|
9261a38493 | ||
|
|
cc8ff318ed | ||
|
|
ad15e845f9 | ||
|
|
ab632f57cd | ||
|
|
13d20bd993 | ||
|
|
b973208137 | ||
|
|
942abf8074 | ||
|
|
ed9bb985e2 | ||
|
|
5a7a8e573b | ||
|
|
ce878db913 | ||
|
|
a3d58683b2 | ||
|
|
039e8ca7e7 | ||
|
|
0ebbd4e21b | ||
|
|
2cb75f6076 | ||
|
|
857d871364 | ||
|
|
632dab2cc0 | ||
|
|
7647918f2d | ||
|
|
75c5d8055c | ||
|
|
a938bbea55 | ||
|
|
414407fbd6 | ||
|
|
076fc717df | ||
|
|
2a04b2d82b | ||
|
|
065db414c0 | ||
|
|
19a054a78b | ||
|
|
9df24a81b7 | ||
|
|
40c0acd3f2 | ||
|
|
20db7f0a8f | ||
|
|
e54f6ee37f | ||
|
|
2da556bf79 | ||
|
|
b183ad8167 | ||
|
|
9e6b54c7ed | ||
|
|
d3b334c10f | ||
|
|
622f2c4bab | ||
|
|
07b638a394 | ||
|
|
9bee2405d8 | ||
|
|
8f040491bf | ||
|
|
8a18988706 | ||
|
|
47a954514b | ||
|
|
e3b65d4288 | ||
|
|
4704f7ed1d | ||
|
|
3a2745445a | ||
|
|
12e15bab15 | ||
|
|
9593aa4fb9 | ||
|
|
817d520e63 | ||
|
|
700abbb8a5 | ||
|
|
701ef1df3f | ||
|
|
0f5c484b62 | ||
|
|
cc7f2a3f02 | ||
|
|
755b5d87e3 | ||
|
|
e55a4115e1 | ||
|
|
16a6fd2ea9 | ||
|
|
e3fce112ed | ||
|
|
eacd26a68b | ||
|
|
0e88b3c38a | ||
|
|
a2170ef8d6 | ||
|
|
eed0424390 | ||
|
|
5ed05e08b1 | ||
|
|
58b26f6715 | ||
|
|
806daf4284 | ||
|
|
c64bc9329e | ||
|
|
dd01745519 | ||
|
|
501ce726e7 | ||
|
|
03076e89ce | ||
|
|
02f37293ee | ||
|
|
590942ad14 | ||
|
|
2ac028c759 | ||
|
|
2125b5bfab | ||
|
|
b96532caa4 | ||
|
|
995fc58466 | ||
|
|
c023cae299 | ||
|
|
237eaf9130 | ||
|
|
8b9ab25125 | ||
|
|
77e87abe8f | ||
|
|
3be02e1e8d | ||
|
|
64c9ede979 | ||
|
|
5b8d197812 | ||
|
|
2cba62dc4f | ||
|
|
288e28328f | ||
|
|
b8214b3c49 | ||
|
|
8681693994 | ||
|
|
1364c63b7c | ||
|
|
4ba9e8fe25 | ||
|
|
a195713bb4 | ||
|
|
600d31a907 | ||
|
|
be31cec332 | ||
|
|
22a7cd3421 | ||
|
|
8b61d2d521 | ||
|
|
559e5269d2 | ||
|
|
ebf6acb318 | ||
|
|
7acd75f013 | ||
|
|
93623b2226 | ||
|
|
d71fd089cb | ||
|
|
05aa43c856 | ||
|
|
de80fb6bc8 | ||
|
|
8e396f4be2 | ||
|
|
efec6da377 | ||
|
|
00ef53195e | ||
|
|
f564aaf485 | ||
|
|
5ac2d31d0d | ||
|
|
fda890ab47 | ||
|
|
a873278c2a | ||
|
|
e6d64be890 | ||
|
|
0e4d978d20 | ||
|
|
b12c2cfedf | ||
|
|
58cc70725e | ||
|
|
339afb02aa | ||
|
|
7ba0ff5c36 | ||
|
|
ff41fbf673 | ||
|
|
2435cd23ce | ||
|
|
a063cff720 | ||
|
|
0d396e1ac0 | ||
|
|
f5807a2053 | ||
|
|
eb4938a36f | ||
|
|
c5ad530bbf | ||
|
|
d11c428407 | ||
|
|
6182b1f53e | ||
|
|
00fc1a12e2 | ||
|
|
16af753206 | ||
|
|
fa48205bb8 | ||
|
|
f7dbf94071 | ||
|
|
b18e66e2ca | ||
|
|
7a5504dfa5 | ||
|
|
d1cad7bc68 | ||
|
|
c58d5c097c | ||
|
|
46157ca94e | ||
|
|
dd99511bcc | ||
|
|
5bc2efd3c7 | ||
|
|
1b18dbecf5 | ||
|
|
9f82c0eb6e | ||
|
|
68bac1b177 | ||
|
|
1495b78330 | ||
|
|
6f777d2848 | ||
|
|
5650eba848 | ||
|
|
5bc5dc93f3 | ||
|
|
c1e18bb825 | ||
|
|
58282ea0fb | ||
|
|
891da7834c | ||
|
|
5c229d48d5 | ||
|
|
53f660cf35 | ||
|
|
7b66ca68f2 | ||
|
|
ba71c3ffbd | ||
|
|
6707ad427a | ||
|
|
5b84549716 | ||
|
|
c74f2ee6e8 | ||
|
|
b32dd9f9d3 | ||
|
|
fb8b161f6c | ||
|
|
baddd6d233 | ||
|
|
6f554c6ae8 | ||
|
|
a71e4488b3 | ||
|
|
72156b5653 | ||
|
|
9fa471e053 | ||
|
|
31ef2fe907 | ||
|
|
9a8ec4b210 | ||
|
|
75aad4cc79 | ||
|
|
4b27feca98 | ||
|
|
45522cd15f | ||
|
|
677d9a4e76 | ||
|
|
efa7ea4fde | ||
|
|
137a6e45f5 | ||
|
|
29116e1dec | ||
|
|
87193335b9 | ||
|
|
cfd4f8a850 | ||
|
|
eaa324939f | ||
|
|
ef70e538f7 | ||
|
|
b7b912e56a | ||
|
|
4615cf2f1e | ||
|
|
eaf772f80a | ||
|
|
96ba75eabd | ||
|
|
fdfe52c1ad | ||
|
|
932b2e2a29 | ||
|
|
57e489c957 | ||
|
|
17a3fa671c | ||
|
|
2659afb4f6 | ||
|
|
7392115507 | ||
|
|
c54d0c7eaa | ||
|
|
b95eefc65f | ||
|
|
686207ab7f | ||
|
|
517b385fe5 | ||
|
|
795019b0c1 | ||
|
|
3127a73822 | ||
|
|
069ee6c91f | ||
|
|
3aac3a98ca | ||
|
|
268859a304 | ||
|
|
a96710aa7b | ||
|
|
edcc58826a | ||
|
|
7077c8220a | ||
|
|
f7cbf68edd | ||
|
|
68a58ee8a5 | ||
|
|
3109ec5091 | ||
|
|
e0599fe8d7 | ||
|
|
a749240589 | ||
|
|
6decdaa062 | ||
|
|
4d5c9b8cdf | ||
|
|
1e23ea5364 | ||
|
|
cf9a8a91b5 | ||
|
|
05d3a65e94 | ||
|
|
c043552f8b | ||
|
|
487ee2b6c9 | ||
|
|
8013fd50da | ||
|
|
4ec9ec12e3 | ||
|
|
ed96594727 | ||
|
|
91b7193249 | ||
|
|
008f65c6a9 | ||
|
|
7aa4e60af2 | ||
|
|
6ef26516d1 | ||
|
|
bb50501369 | ||
|
|
55eb481f30 | ||
|
|
4509ca6e75 | ||
|
|
c61fe9af61 | ||
|
|
4181a712d1 | ||
|
|
c171cb7286 | ||
|
|
1d09061130 | ||
|
|
a2203b2447 | ||
|
|
755f6e0979 | ||
|
|
95b2830d17 | ||
|
|
2669d8332e | ||
|
|
11fbd32e6e | ||
|
|
6a302fdb88 | ||
|
|
1d9cc239ee | ||
|
|
d240fc1ea6 | ||
|
|
e7d21dd826 | ||
|
|
e774b4650b | ||
|
|
8f8e6dcdd4 | ||
|
|
5252b88f0f | ||
|
|
ea69883386 | ||
|
|
eb343b1e37 | ||
|
|
9f02de55be | ||
|
|
7394a4cf49 | ||
|
|
ed9fb110b1 | ||
|
|
4650074428 | ||
|
|
70aa644c10 | ||
|
|
2ccb3edc58 | ||
|
|
a12a5f11ff | ||
|
|
f46e4067f4 | ||
|
|
47bf5585e8 | ||
|
|
72fb4d39be | ||
|
|
9681c0e05a | ||
|
|
2628575dab | ||
|
|
f7d59068e5 | ||
|
|
4cf10d62ca | ||
|
|
2f65e3aac8 | ||
|
|
e494cd7aa6 | ||
|
|
809880f46d | ||
|
|
5925ebe31c | ||
|
|
316709c291 | ||
|
|
0d6a2ba554 | ||
|
|
1fcb06b1aa | ||
|
|
36138c7c06 | ||
|
|
338593d9e7 | ||
|
|
d6eb1f9578 | ||
|
|
1cc9d2d3d1 | ||
|
|
58642aa98b | ||
|
|
7baaf00a38 | ||
|
|
5cc23dbf24 | ||
|
|
216d60ea2c | ||
|
|
8b0496d35e | ||
|
|
e44001641c | ||
|
|
47885f4230 | ||
|
|
921767e82e | ||
|
|
85f96b7fb0 | ||
|
|
890c7fd0f6 | ||
|
|
39c44bdd2f | ||
|
|
5f99f7f6ca | ||
|
|
4f864bce98 | ||
|
|
2974929b26 | ||
|
|
db837aa55c | ||
|
|
7200623007 | ||
|
|
73e02ae4ea | ||
|
|
d4cbef9457 | ||
|
|
ed8ff79e10 | ||
|
|
e725f64b6a | ||
|
|
0029cc4fe7 | ||
|
|
9637696a54 | ||
|
|
02b3ca6862 | ||
|
|
bc90f40a8f | ||
|
|
3d727ff4c0 | ||
|
|
b0eacd6586 | ||
|
|
7795701595 | ||
|
|
bf214eecb3 | ||
|
|
434b96d734 | ||
|
|
b9dc109892 | ||
|
|
1f40a70554 | ||
|
|
e14ffbf03f | ||
|
|
25a1dde57c | ||
|
|
bf96171b65 | ||
|
|
b7ff821fa3 | ||
|
|
b81daf71d1 | ||
|
|
faad1fc58a | ||
|
|
6f48181a56 | ||
|
|
f1305e5a37 | ||
|
|
f0e0f92776 | ||
|
|
807c8b0726 | ||
|
|
6333ec928c | ||
|
|
cd220d9ed9 | ||
|
|
76532649b8 | ||
|
|
b0dbaeafc5 | ||
|
|
2530d1791b | ||
|
|
94150f414a | ||
|
|
54e74f84cc | ||
|
|
76e7e8dbbb | ||
|
|
324598e992 | ||
|
|
9e765ddf46 | ||
|
|
6ac9e92f17 | ||
|
|
faaa4a1def | ||
|
|
0aa51f0f3a | ||
|
|
73431d9761 | ||
|
|
45cb4525cf | ||
|
|
8c84c515b6 | ||
|
|
1dfbbdebf4 | ||
|
|
740918daee | ||
|
|
1d10eac764 | ||
|
|
3f868118cd | ||
|
|
04d79b15b4 | ||
|
|
a13c398c06 | ||
|
|
e3b3f716ee | ||
|
|
cf43c06f46 | ||
|
|
74a5a18607 | ||
|
|
44241c6dd5 | ||
|
|
8fff496ffd | ||
|
|
edf75c519c | ||
|
|
9608b22d34 | ||
|
|
8ba4968c48 | ||
|
|
ffdd78f1a5 | ||
|
|
ad9f8ca78e | ||
|
|
78a686ecb4 | ||
|
|
59e786eb3c | ||
|
|
6d0461435f | ||
|
|
0a04a60f69 | ||
|
|
68d8642988 | ||
|
|
16f70ff054 | ||
|
|
c00aeafff0 | ||
|
|
83f35e00f3 | ||
|
|
786a2ad65a | ||
|
|
9425506c2a | ||
|
|
93b858afd1 | ||
|
|
7b0a3ec365 | ||
|
|
083d442529 | ||
|
|
b52eb95cf8 | ||
|
|
f4571e2508 | ||
|
|
b06ef03aac | ||
|
|
1d1962a106 | ||
|
|
4b98e9ff08 | ||
|
|
f83ca5d8ac | ||
|
|
95cb4d22d7 | ||
|
|
0c279b01a4 | ||
|
|
3b820ffa7b | ||
|
|
35cb416563 | ||
|
|
cdb737259c | ||
|
|
0843b5939c | ||
|
|
2b5f23a2d1 | ||
|
|
5e20d1d554 | ||
|
|
18595ca86a | ||
|
|
3e269fa188 | ||
|
|
65405c2cb9 | ||
|
|
442cf8897a | ||
|
|
d5fb275e9e | ||
|
|
e60aec81ca | ||
|
|
398e9e535e | ||
|
|
08bf651ef2 | ||
|
|
6171de41bf | ||
|
|
f0a56592e2 | ||
|
|
87a7d4d1a8 | ||
|
|
05287902a2 | ||
|
|
96e453feb6 | ||
|
|
9c0fa9fc04 | ||
|
|
3bde0715b0 | ||
|
|
e2ec3d8b9b | ||
|
|
ad91eaf8a7 | ||
|
|
b6d30214fd | ||
|
|
c4ab01d63d | ||
|
|
4ba3b3f55a | ||
|
|
52d2706a9e | ||
|
|
964afc69f6 | ||
|
|
3ddf545ccd | ||
|
|
f9374733bb | ||
|
|
5930135f45 | ||
|
|
f03f6bc128 | ||
|
|
6c50c70235 | ||
|
|
8790fc2c1b | ||
|
|
f86c4fccf4 | ||
|
|
7d0785e9ed | ||
|
|
2cac88162c | ||
|
|
4809627d8a | ||
|
|
871979abd6 | ||
|
|
efb95722ca | ||
|
|
d9bbb80a6b | ||
|
|
3254315127 | ||
|
|
ca297fd26b | ||
|
|
ac36a43cef | ||
|
|
f00183115d | ||
|
|
161b29a899 | ||
|
|
72253d09fa | ||
|
|
40d09ddb23 | ||
|
|
3026d86a9e | ||
|
|
0661a7edc3 | ||
|
|
24b0adfacc | ||
|
|
acc6698ab3 | ||
|
|
606d3e6aa1 | ||
|
|
687a7954d6 | ||
|
|
36a53a7b37 | ||
|
|
0a5982a902 | ||
|
|
601863f9e9 | ||
|
|
c9ce731119 | ||
|
|
abed8e034e | ||
|
|
63032d304d | ||
|
|
a57ecede78 | ||
|
|
b0ce7c63dd | ||
|
|
d139a11c16 | ||
|
|
aef043db0b | ||
|
|
b8f3ead541 | ||
|
|
e0bb898f29 | ||
|
|
45336c7c28 | ||
|
|
20aabb2e83 | ||
|
|
1539e24d61 | ||
|
|
c7cf041e4a | ||
|
|
da80d3f354 | ||
|
|
001c8d7678 | ||
|
|
38ab03655b | ||
|
|
9226f8a5d1 | ||
|
|
5c8a007f3e | ||
|
|
b3ad3e297d | ||
|
|
d607553e48 | ||
|
|
7cf83c77ca | ||
|
|
8a9f174f63 | ||
|
|
98a0786c32 | ||
|
|
df1129724c | ||
|
|
423cef08bf | ||
|
|
04580accb4 | ||
|
|
6376f77b8c | ||
|
|
e27e614ed9 | ||
|
|
b0c04704a1 | ||
|
|
6bb6bf8323 | ||
|
|
e22fe8aefc | ||
|
|
76276f61e5 | ||
|
|
bfd26e6ec6 | ||
|
|
d787e1ea0f | ||
|
|
b5d7e9cbb0 | ||
|
|
f3b6d9dcdf | ||
|
|
a9abe13185 | ||
|
|
6b315e8315 | ||
|
|
37677de884 | ||
|
|
c7387de325 | ||
|
|
2495b1e038 | ||
|
|
073ee52ce7 | ||
|
|
54150a14e9 | ||
|
|
88ff091cce | ||
|
|
e87a5776f1 | ||
|
|
0806ce6406 | ||
|
|
6409894a71 | ||
|
|
e7286f6129 | ||
|
|
2ab94b3151 | ||
|
|
7ee90890ec | ||
|
|
383e726d65 | ||
|
|
e046f70642 | ||
|
|
2131ad4670 | ||
|
|
219fe2155b | ||
|
|
4209034d20 | ||
|
|
abcae0c2a4 | ||
|
|
0934905493 | ||
|
|
11cd6201d9 | ||
|
|
8d2a917676 | ||
|
|
44b4afa534 | ||
|
|
775be3933c | ||
|
|
df87e21c85 | ||
|
|
d761d80750 | ||
|
|
8052019dde | ||
|
|
a3d8950088 | ||
|
|
004f5d3bf1 | ||
|
|
f5d308a156 | ||
|
|
3869996758 | ||
|
|
cdb2107c4e | ||
|
|
4db2b3413b | ||
|
|
b2f31bec79 | ||
|
|
78f9f4a266 | ||
|
|
ad6087c342 | ||
|
|
0d6ef430de | ||
|
|
a5942209e8 | ||
|
|
9a60694cfc | ||
|
|
4bf13f4737 | ||
|
|
9e89b75186 | ||
|
|
0b10db91be | ||
|
|
1a516b2af9 | ||
|
|
076363d78e | ||
|
|
5fde214290 | ||
|
|
a620724d6a | ||
|
|
640b953ec7 | ||
|
|
a009ca7597 | ||
|
|
7368399f8b | ||
|
|
c974aec934 | ||
|
|
3033f03f64 | ||
|
|
72723e0bb5 | ||
|
|
2fb6ab3939 | ||
|
|
25c1c160b8 | ||
|
|
7e92895471 | ||
|
|
d291d48991 | ||
|
|
0e6b8042b0 | ||
|
|
34c78a892a | ||
|
|
9d28879505 | ||
|
|
2482296e2b | ||
|
|
f755fb76ee | ||
|
|
c61b5dcb62 | ||
|
|
fae893b9d9 | ||
|
|
10aadefd6a | ||
|
|
e75b6280fd | ||
|
|
8c4023165a | ||
|
|
b7d403f106 | ||
|
|
b069de0caa | ||
|
|
136da74bfa | ||
|
|
7fc897e6dc | ||
|
|
9b731d63b8 | ||
|
|
10aa59f674 | ||
|
|
1f7837e7b1 | ||
|
|
ba0535e3fb | ||
|
|
49fa7f6b5c | ||
|
|
c95db246d4 | ||
|
|
1ba93371ce | ||
|
|
fedbbdb575 | ||
|
|
85ebba72bc | ||
|
|
b6cd436d5d | ||
|
|
ec170c7e1e | ||
|
|
f6399eb90f | ||
|
|
77f2448e59 | ||
|
|
3d69b46fca | ||
|
|
4b6153ad18 | ||
|
|
75d37eb103 | ||
|
|
11b6f77df0 | ||
|
|
db8b0319dd | ||
|
|
c9dd330766 | ||
|
|
e40228102c | ||
|
|
7889c6fb4c | ||
|
|
6eb1773110 | ||
|
|
1d25823746 | ||
|
|
d1d4f1e198 | ||
|
|
709c01c7a1 | ||
|
|
4a341c9034 | ||
|
|
be41ff6d54 | ||
|
|
1dbb6f1746 | ||
|
|
753e6274ab | ||
|
|
7f462c618b | ||
|
|
d8ac6e28ab | ||
|
|
a95ffcdc46 | ||
|
|
1b01d45dd2 | ||
|
|
7a1cd39b21 | ||
|
|
1c1fd9616a | ||
|
|
11e19e4085 | ||
|
|
2a43f73228 | ||
|
|
b1d1310a75 | ||
|
|
0e7fa78e65 | ||
|
|
4032570d97 | ||
|
|
90644a3017 | ||
|
|
4f6bffb477 | ||
|
|
158f902c3b | ||
|
|
6dc25ddc6e | ||
|
|
7f6aaeaecf | ||
|
|
ace439910e | ||
|
|
7f038568de | ||
|
|
af777c0b6a | ||
|
|
fc299032a4 | ||
|
|
e0f3f07907 | ||
|
|
b36df9cf9e | ||
|
|
81c3f780d4 | ||
|
|
b51efdd3e3 | ||
|
|
610b769df9 | ||
|
|
527f4d0101 | ||
|
|
8d9be43c60 | ||
|
|
40ef4f0bbe | ||
|
|
d0271d5049 | ||
|
|
5becfcf8ea | ||
|
|
112e8d6c18 | ||
|
|
1d8d49a01d | ||
|
|
5050155685 | ||
|
|
a9bd494cc0 | ||
|
|
6a4df78bc0 | ||
|
|
530eae3898 | ||
|
|
3e444f6a90 | ||
|
|
45dbff6401 | ||
|
|
bc56b8e058 | ||
|
|
d86e315c48 | ||
|
|
746969207a | ||
|
|
1caebaefb5 | ||
|
|
2d10fdcf0f | ||
|
|
355ec70a80 | ||
|
|
a2f499de01 | ||
|
|
f4bca89722 | ||
|
|
9fbc69df3f | ||
|
|
230d301268 | ||
|
|
1ce7b02d94 | ||
|
|
a2d00f5f1d | ||
|
|
f68eaa3b46 | ||
|
|
0199ab220e | ||
|
|
656045610a | ||
|
|
8c1c61f207 | ||
|
|
af085b79dd | ||
|
|
77476965ae | ||
|
|
961c1365f9 | ||
|
|
ca51514046 | ||
|
|
8975b72a01 | ||
|
|
874ec6a87f | ||
|
|
909eaeeead | ||
|
|
c138161fae | ||
|
|
e48590d66c | ||
|
|
5b1c8541fc | ||
|
|
e5e011021b | ||
|
|
11d74dea09 | ||
|
|
cbdf9c88c5 | ||
|
|
46601b1350 | ||
|
|
6f1a40b2ca | ||
|
|
a2b1f54eb2 | ||
|
|
6756016572 | ||
|
|
f42123afc3 | ||
|
|
1425ffd274 | ||
|
|
d700154e0e | ||
|
|
efecf42566 | ||
|
|
74bdfc07fb | ||
|
|
376dfdba1c | ||
|
|
3795d6720f | ||
|
|
537aaf56d7 | ||
|
|
34d51b5d3d | ||
|
|
dea8fcfb5b | ||
|
|
4f1f3b9b51 | ||
|
|
dfeb8812ad | ||
|
|
63e2b4273a | ||
|
|
5790dbc085 | ||
|
|
9e2105e08d | ||
|
|
22582bbd1c | ||
|
|
e5f27b7a12 | ||
|
|
e88ec9822b | ||
|
|
5ffd2f5c96 | ||
|
|
11fdb4c5d8 | ||
|
|
319aff6d09 | ||
|
|
a614fa3400 | ||
|
|
8d691391ac | ||
|
|
0089a84c94 | ||
|
|
90676e1c6a | ||
|
|
062901be43 | ||
|
|
b195d79b50 | ||
|
|
6d7ee98721 | ||
|
|
fc0800ed5d | ||
|
|
f4e3a0e5b2 | ||
|
|
d631c80024 | ||
|
|
f1f0033875 | ||
|
|
84d120e850 | ||
|
|
8159cc6b88 | ||
|
|
995f8c106b | ||
|
|
7cc104b138 | ||
|
|
b3a7299a62 | ||
|
|
0e7a4deaec | ||
|
|
b4d66650bd | ||
|
|
4986afca28 | ||
|
|
2b6004a82b | ||
|
|
04c54a7c31 | ||
|
|
7ae6c5ae87 | ||
|
|
4046766ca5 | ||
|
|
810390df0b | ||
|
|
de749bc7ae | ||
|
|
9965b8800c | ||
|
|
ab870fddd6 | ||
|
|
a79d6807cf | ||
|
|
8185fb7e43 | ||
|
|
4b10929b25 | ||
|
|
f6c70312c9 | ||
|
|
9fd9c7a51f | ||
|
|
422e619978 | ||
|
|
e6e34251c6 | ||
|
|
2d8aad1086 | ||
|
|
74ca736333 | ||
|
|
5e4fd8b0b9 | ||
|
|
8ab8132411 | ||
|
|
6899dd46e4 | ||
|
|
8ad0697a20 | ||
|
|
b47e5672e6 | ||
|
|
45c7bd9a60 | ||
|
|
e7bcb95635 | ||
|
|
3de83627a9 | ||
|
|
f248576994 | ||
|
|
aac5b6de3b | ||
|
|
24435f11e0 | ||
|
|
a9da839c39 | ||
|
|
fa2c0296d6 | ||
|
|
1dfc32d7e6 | ||
|
|
4a61beae41 | ||
|
|
bd30587bf1 | ||
|
|
e0070e3e18 | ||
|
|
019513696b | ||
|
|
ad7a4476db | ||
|
|
4812b20fb2 | ||
|
|
f5e07c9427 | ||
|
|
75dcb90621 | ||
|
|
dfc0434cc2 | ||
|
|
882fc2257c | ||
|
|
41e83b52fc | ||
|
|
47758b4d8f | ||
|
|
6bf1f970a0 | ||
|
|
7d451f101f | ||
|
|
7edbfe0e40 | ||
|
|
91b42cbfa8 | ||
|
|
6907df41b4 | ||
|
|
2cebd90cbd | ||
|
|
376a121aaa | ||
|
|
da11fd17ee | ||
|
|
a40689a0ff | ||
|
|
44a45fc3fb | ||
|
|
ec4bb5359a | ||
|
|
d2217632df | ||
|
|
2cc044feed | ||
|
|
64fd0cb54f | ||
|
|
c5a1d22e81 | ||
|
|
a7b307af04 | ||
|
|
3269eba16c | ||
|
|
d472860e3b | ||
|
|
731c9ea55e | ||
|
|
0b6af8d965 | ||
|
|
92ca9e954c | ||
|
|
67aa00e2c5 | ||
|
|
a1bf161eb7 | ||
|
|
56614fcaa4 | ||
|
|
4d9169e15f | ||
|
|
3a167af2c4 | ||
|
|
64b9005030 | ||
|
|
965de3a235 | ||
|
|
2040ae4856 | ||
|
|
31a1f9f5ea | ||
|
|
7eadd82048 | ||
|
|
31d0eaac8e | ||
|
|
f45d012635 | ||
|
|
5a777ee9bc | ||
|
|
7bbf6bc7f4 | ||
|
|
9bfc45702d | ||
|
|
40aa82ab41 | ||
|
|
5d2c67c62b | ||
|
|
a00ef4836d | ||
|
|
3ef766bb93 | ||
|
|
44b5a18462 | ||
|
|
4df716f0e8 | ||
|
|
fcbf34a4d3 | ||
|
|
c7b8b6e18b | ||
|
|
9fd165bf4b | ||
|
|
2061092ec5 | ||
|
|
57466a31ba | ||
|
|
4213c69bef | ||
|
|
cc5578488a | ||
|
|
4b7135f0e5 | ||
|
|
984df023b1 | ||
|
|
6f8682f558 | ||
|
|
51defa6d66 | ||
|
|
7d73098d6e | ||
|
|
c580aa4683 | ||
|
|
47d1199360 | ||
|
|
61ab435b31 | ||
|
|
aa8f534b45 | ||
|
|
dc9589aca8 | ||
|
|
dd6eaacc6b | ||
|
|
37dc03eec6 | ||
|
|
6b478172f6 | ||
|
|
c6e73bcfd6 | ||
|
|
a2d62938ce | ||
|
|
d7ae1f3cca | ||
|
|
70219581c4 | ||
|
|
f70ac9fb89 | ||
|
|
235b9fbaf0 | ||
|
|
ebda7f42db | ||
|
|
0b04e4b977 | ||
|
|
9498601a37 | ||
|
|
ef5d320e06 | ||
|
|
b00c9a562d | ||
|
|
5372656893 | ||
|
|
571de0e368 | ||
|
|
82cea2fd85 | ||
|
|
aed9814345 | ||
|
|
34fc1f5fd7 | ||
|
|
87c2ed8b27 | ||
|
|
1467d118ab | ||
|
|
922dbe83c3 | ||
|
|
6af7d61ee5 | ||
|
|
bafd08391d | ||
|
|
82ebd8ef1a | ||
|
|
4ed1aa4d23 | ||
|
|
d04e43d46d | ||
|
|
952f0cca15 | ||
|
|
f6a4d8f1f8 | ||
|
|
b3097a2384 | ||
|
|
6d9ddbe98b | ||
|
|
9bb42c0229 | ||
|
|
bd7226b27a | ||
|
|
5b413e3873 | ||
|
|
be5831a629 | ||
|
|
084d2bf8e2 | ||
|
|
da79e6bac7 | ||
|
|
c4831ac00c | ||
|
|
93a954ef9f | ||
|
|
f7ce8f44e9 | ||
|
|
0b012697e5 | ||
|
|
58e357c992 | ||
|
|
71fbad83ad | ||
|
|
52483072dc | ||
|
|
7f0b8621f3 | ||
|
|
cd8db60b06 | ||
|
|
1aa34f5d2e | ||
|
|
dfa1d88ce9 | ||
|
|
dd38519f07 | ||
|
|
098f5d4f0b | ||
|
|
ffc685d536 | ||
|
|
cd1a99a0de | ||
|
|
48e3b267fc | ||
|
|
3a7c3417bb | ||
|
|
d792ef7222 | ||
|
|
2c24f67deb | ||
|
|
9e75e28d0c | ||
|
|
3232643809 | ||
|
|
f7ee9e90ce | ||
|
|
47298be132 | ||
|
|
a88fa83515 | ||
|
|
12bfe20385 | ||
|
|
3d2f6f0772 | ||
|
|
1cb607f64b | ||
|
|
d3c54fbbde | ||
|
|
28341b755f | ||
|
|
4b5cd420e1 | ||
|
|
1d57bcc99e | ||
|
|
facdd13879 | ||
|
|
6e891f91d3 | ||
|
|
9b50ede977 | ||
|
|
82cf010333 | ||
|
|
6ff6c8614f | ||
|
|
eb1cd38f6c | ||
|
|
148b632b4f | ||
|
|
591e213713 | ||
|
|
75f2262659 | ||
|
|
d9005a1074 | ||
|
|
3e73fa81bf | ||
|
|
ba6e290231 | ||
|
|
08e47117a3 | ||
|
|
532ef38157 | ||
|
|
4c09875890 | ||
|
|
0e98139712 | ||
|
|
4c04d802d7 | ||
|
|
b3dc404571 | ||
|
|
8694f8d2eb | ||
|
|
263f9b79f4 | ||
|
|
56d2aae963 | ||
|
|
127706153d | ||
|
|
caee5b1428 | ||
|
|
6c12e7e944 | ||
|
|
cd04ae6949 | ||
|
|
6a0b68298f | ||
|
|
0a2f732267 | ||
|
|
4bade99f27 | ||
|
|
0b048cd24e | ||
|
|
c69ee63d82 | ||
|
|
744fa104d7 | ||
|
|
e24ff0fd64 | ||
|
|
5de107d44c | ||
|
|
131a5b741d | ||
|
|
65b89687a9 | ||
|
|
048ae40e75 | ||
|
|
234183ecd2 | ||
|
|
fb067dc97b | ||
|
|
a1fea0ce16 | ||
|
|
e1e9135e93 | ||
|
|
aff982036b | ||
|
|
d087649eab | ||
|
|
7f3fa46a40 | ||
|
|
b1f79e4d97 | ||
|
|
115d6df94f | ||
|
|
559af9635f | ||
|
|
cb06359c0b | ||
|
|
5e26bb29d9 | ||
|
|
b0e95842b8 | ||
|
|
08e678f21f | ||
|
|
c17817810f | ||
|
|
ff5c38b1f7 | ||
|
|
64314c1b82 | ||
|
|
83230097ae | ||
|
|
8f91acf956 | ||
|
|
d211722a2f | ||
|
|
56e6ed1249 | ||
|
|
21982cf1cb | ||
|
|
edc01408da | ||
|
|
aee33c87ed | ||
|
|
0dae1602c7 | ||
|
|
d926f07ac1 | ||
|
|
96045e98f4 | ||
|
|
01b7205e2c | ||
|
|
c8a4cbcf17 | ||
|
|
16b6442b23 | ||
|
|
183eafa587 | ||
|
|
47a2997538 | ||
|
|
37ebcadfa1 | ||
|
|
74d98216f1 | ||
|
|
4bdebf573e | ||
|
|
1606b6a383 | ||
|
|
2a61902df5 | ||
|
|
01a1c2b576 | ||
|
|
c4f01de231 | ||
|
|
63a4a761dd | ||
|
|
d077c03686 | ||
|
|
c97ea1f2a9 | ||
|
|
fd27df2abb | ||
|
|
bf04f03c4c | ||
|
|
93e802f473 | ||
|
|
1464b9087a | ||
|
|
e8cc8fc879 | ||
|
|
fae2119b1e | ||
|
|
aa859a4139 | ||
|
|
b9b12e2879 | ||
|
|
cf643c9f43 | ||
|
|
5b1a7880a9 | ||
|
|
474b6b0500 | ||
|
|
6c8c1d8173 | ||
|
|
6a91fa637f | ||
|
|
2846fb4e31 | ||
|
|
a1033cdc64 | ||
|
|
204336e1a5 | ||
|
|
8954e6c3b9 | ||
|
|
fee22b6b0b | ||
|
|
2b82c31b85 | ||
|
|
9a4813089c | ||
|
|
554fcc8b9d | ||
|
|
345256ee99 | ||
|
|
58d1042147 | ||
|
|
7b7e3a3e03 | ||
|
|
1e7fbd4202 | ||
|
|
6e907856f2 | ||
|
|
8bc6019172 | ||
|
|
059f79242e | ||
|
|
89599b4812 | ||
|
|
a9f4047a97 | ||
|
|
23227ae763 | ||
|
|
4a9e9e9db2 | ||
|
|
88ef2718f1 | ||
|
|
e71e8ca3ad | ||
|
|
45e9257d6e | ||
|
|
2954e72652 | ||
|
|
199de96cff | ||
|
|
8ddbe81513 | ||
|
|
a3e26e0498 | ||
|
|
4ad129d8d8 | ||
|
|
dfb9fa0736 | ||
|
|
eb036898e9 | ||
|
|
7c6aa76a2a | ||
|
|
f035cb1088 | ||
|
|
35162166c5 | ||
|
|
107f6abcb1 | ||
|
|
760a939e7d | ||
|
|
72660d0dec | ||
|
|
8444a8f211 | ||
|
|
4a1fec8328 | ||
|
|
42547f6017 | ||
|
|
0ccf564f03 | ||
|
|
65c9a07dde | ||
|
|
4700a19322 | ||
|
|
3d3b3abc1b | ||
|
|
7cd2770a13 | ||
|
|
7b94129d9e | ||
|
|
d1a0065ef8 | ||
|
|
5a817370fd | ||
|
|
ab0a210763 | ||
|
|
9f800736bc | ||
|
|
c9a83afad6 | ||
|
|
5e14274f10 | ||
|
|
167470b4bd | ||
|
|
f06d3c2ec2 | ||
|
|
74c99a8a77 | ||
|
|
0e4d312ee2 | ||
|
|
589f19559d | ||
|
|
f28bc25dc0 | ||
|
|
a0657ad937 | ||
|
|
5b8d88af4c | ||
|
|
fa82b50340 | ||
|
|
005216bc57 | ||
|
|
e748fdcf6f | ||
|
|
8c17c9918e | ||
|
|
ea0dd99d0b | ||
|
|
e0cc67afae | ||
|
|
04f9cbe364 | ||
|
|
99afebd033 | ||
|
|
a6feacc810 | ||
|
|
65e4b1672f | ||
|
|
46cc0dd190 | ||
|
|
678b9fb603 | ||
|
|
49ab0c1f0b | ||
|
|
ab490a7736 | ||
|
|
e4ce1dae35 | ||
|
|
179b812acb | ||
|
|
7f170517ec | ||
|
|
5480da4f04 | ||
|
|
9a15a4db10 | ||
|
|
55aeaec293 | ||
|
|
f6df1fb40c | ||
|
|
b889a89c36 | ||
|
|
1976dc6f30 | ||
|
|
e864c65d26 | ||
|
|
02fba02d31 | ||
|
|
fb9e7c82f6 | ||
|
|
77d31bf646 | ||
|
|
29ca799bcf | ||
|
|
467b7f0163 | ||
|
|
bad67c6dc5 | ||
|
|
ac40426971 | ||
|
|
7acfaf6d34 | ||
|
|
99e47c9c04 | ||
|
|
d7904e2251 | ||
|
|
68aef489de | ||
|
|
3f9adcd5e0 | ||
|
|
6cc5135d2d | ||
|
|
d4c72b371f | ||
|
|
18b6f05657 | ||
|
|
c42d9baa26 | ||
|
|
6e27ecd2b9 | ||
|
|
482692396e | ||
|
|
c48acf165a | ||
|
|
9e004c3ec0 | ||
|
|
7be4e9c919 | ||
|
|
5ec38a4bed | ||
|
|
f246779b8e | ||
|
|
a7d8cdf061 | ||
|
|
620745c812 | ||
|
|
b8767e5ba9 | ||
|
|
d33a50660d | ||
|
|
4ee9658e97 | ||
|
|
dd1b84e7ba | ||
|
|
4c677e6c47 | ||
|
|
f0f889440b | ||
|
|
cc9ceaeb74 | ||
|
|
ad2fa8d1d7 | ||
|
|
adc1580742 | ||
|
|
4d3b44d6df | ||
|
|
e57aa0eee2 | ||
|
|
1ae1d116c7 | ||
|
|
097a69d07f | ||
|
|
a81ce87a50 | ||
|
|
88be0d43a0 | ||
|
|
ff16a00a3d | ||
|
|
8982b3e1e2 | ||
|
|
be0fa35d14 | ||
|
|
9f51ed9d01 | ||
|
|
731e6792c7 | ||
|
|
c35ec0b4aa | ||
|
|
03aaf575dc | ||
|
|
9a060579ba | ||
|
|
d40a5c4f7a | ||
|
|
21f7dc3377 | ||
|
|
43c13a1ed9 | ||
|
|
6bc3f189e1 | ||
|
|
2c5437135c | ||
|
|
444da02523 | ||
|
|
00e8af2381 | ||
|
|
401b21864f | ||
|
|
de939951d4 | ||
|
|
7725d16a26 | ||
|
|
8a74408d83 | ||
|
|
3d0dc95a06 | ||
|
|
04a57a3cc2 | ||
|
|
d0c22ce01d | ||
|
|
23c95e9660 | ||
|
|
eecab9b95d | ||
|
|
8abc2f113c | ||
|
|
949d2ff1c2 | ||
|
|
1c8b763d53 | ||
|
|
bb91393b85 | ||
|
|
cc9c0d819e | ||
|
|
a72b8caf47 | ||
|
|
fdd9b8b8ce | ||
|
|
c096b4ca8c | ||
|
|
427add3008 | ||
|
|
c45871700d | ||
|
|
6821e8eeb2 | ||
|
|
a4f07756a5 | ||
|
|
f24fb0e0c5 | ||
|
|
73b88a0a6f | ||
|
|
c42f39e2d4 | ||
|
|
5e5fe3175f | ||
|
|
cab65d1f11 | ||
|
|
245f05d5f4 | ||
|
|
dda751f9e3 | ||
|
|
3d37ae988a | ||
|
|
717acd9855 | ||
|
|
2e4431cc63 | ||
|
|
f7387b0859 | ||
|
|
a09f6b8977 | ||
|
|
d63449c214 | ||
|
|
a86805f0d9 | ||
|
|
7d2009ccef | ||
|
|
18ae5db06d | ||
|
|
9a1838f102 | ||
|
|
e20346032d | ||
|
|
693a27d76c | ||
|
|
203966d86b | ||
|
|
7eca8508fd | ||
|
|
b85270df1c | ||
|
|
aff597cef4 | ||
|
|
61b05b3dee | ||
|
|
453c4ef602 | ||
|
|
cf4b04f92d | ||
|
|
06c6999987 | ||
|
|
013c5a369f | ||
|
|
07891d994a | ||
|
|
6baf8668a6 | ||
|
|
4ba2962c56 | ||
|
|
7ad92f5db4 | ||
|
|
4dad09cc91 | ||
|
|
7b2e0c7a7a | ||
|
|
7f08f15fc9 | ||
|
|
825c0f8b2a | ||
|
|
dbe880bc41 | ||
|
|
2ec516b6ff | ||
|
|
7942a01e50 | ||
|
|
df684f9344 | ||
|
|
ae16e95e42 | ||
|
|
2ac8e8a0cc | ||
|
|
0a0ceda71f | ||
|
|
220f1ce161 | ||
|
|
c62a8a97c9 | ||
|
|
f8a1136979 | ||
|
|
9ca29c787b | ||
|
|
6af748a251 | ||
|
|
9041867f86 | ||
|
|
04099b087c | ||
|
|
6d6234714c | ||
|
|
520be23481 | ||
|
|
346c3c8dd3 | ||
|
|
bd534c3313 | ||
|
|
2625368aed | ||
|
|
8ac94879f1 | ||
|
|
dd8c0f3756 | ||
|
|
010f353a5e | ||
|
|
e0a18edb92 | ||
|
|
c6f2eea058 | ||
|
|
bf89e38c69 | ||
|
|
e1f0640d42 | ||
|
|
71b54035ba | ||
|
|
325cc0beca | ||
|
|
1a9f09c4d5 | ||
|
|
4fed4e2af3 | ||
|
|
74cc2346a5 | ||
|
|
cc7e328358 | ||
|
|
d25397e2b0 | ||
|
|
bc11454e1c | ||
|
|
2025a096c3 | ||
|
|
38fe14b108 | ||
|
|
1b7b2f3695 | ||
|
|
5d67cc76cc | ||
|
|
27a3813207 | ||
|
|
b06e0bfdcd | ||
|
|
d616f25324 | ||
|
|
b03028e31f | ||
|
|
e08c42fd3d | ||
|
|
16901f7134 | ||
|
|
dffceedd85 | ||
|
|
e5541e435c | ||
|
|
b969aad67b | ||
|
|
e70387b1af | ||
|
|
44f47fba21 | ||
|
|
02584094a1 | ||
|
|
91d715ac93 | ||
|
|
35addb8a33 | ||
|
|
d32ea8d0dd | ||
|
|
12575d594a | ||
|
|
0746083301 | ||
|
|
5c99acf6d1 | ||
|
|
2b10df7b74 | ||
|
|
ebe68de4ff | ||
|
|
b17c6a146d | ||
|
|
46d837c866 | ||
|
|
24856b61e4 | ||
|
|
8d0c6ff616 | ||
|
|
0b24f971cd | ||
|
|
bc5d3824bd | ||
|
|
4356983707 | ||
|
|
2414b79ee6 | ||
|
|
968e1546f0 | ||
|
|
48213c9c3f | ||
|
|
f385772d21 | ||
|
|
d257c83520 | ||
|
|
7b72ffec4f | ||
|
|
757f6826dc | ||
|
|
5df83a0d30 | ||
|
|
d70e3d3753 | ||
|
|
0dfceedcfb | ||
|
|
2c30f4bfc5 | ||
|
|
9e7fb52b47 | ||
|
|
bb5fd38e38 | ||
|
|
7c8cf5cfa2 | ||
|
|
fef35e4eb2 | ||
|
|
8f77576dc4 | ||
|
|
b3fcf24a26 | ||
|
|
16e4d342d2 | ||
|
|
8458a51860 | ||
|
|
636d1903b3 | ||
|
|
514efa36fc | ||
|
|
bd48f40d3d | ||
|
|
c02dbc809a | ||
|
|
410111d6fb | ||
|
|
68cf9cbd87 | ||
|
|
c9b2540d9d | ||
|
|
1bacf35a2c | ||
|
|
8aef0d9277 | ||
|
|
b2fa8645ba | ||
|
|
c96823a648 | ||
|
|
3807b7d655 | ||
|
|
a45505cf1d | ||
|
|
b4a734fc0d | ||
|
|
bbd02926e1 | ||
|
|
5022ded276 | ||
|
|
c7612152ef | ||
|
|
af91642cd1 | ||
|
|
9c66334c38 | ||
|
|
8d79b94b84 | ||
|
|
d7f60b96c1 | ||
|
|
b964999427 | ||
|
|
3473345ea6 | ||
|
|
349ec5c81f | ||
|
|
ff78d7c56c | ||
|
|
ff092c8629 | ||
|
|
fe14cb57c0 | ||
|
|
507fbc01d5 | ||
|
|
325479e5be | ||
|
|
e926ecb8b2 | ||
|
|
d0cb6c0e92 | ||
|
|
5b7c8cf5d3 | ||
|
|
40baab32ac | ||
|
|
e877d37ac8 | ||
|
|
5a9f77e438 | ||
|
|
8ddd67d1e2 | ||
|
|
1605408c23 | ||
|
|
2d3b1ebf6e | ||
|
|
c74eaab7f5 | ||
|
|
c21d231388 | ||
|
|
a73afc4e76 | ||
|
|
76c364150d | ||
|
|
94a3e447cc | ||
|
|
12868b461a | ||
|
|
322085933b | ||
|
|
3fed94bb79 | ||
|
|
8c877482bd | ||
|
|
b17d589e84 | ||
|
|
368252a243 | ||
|
|
ccefda1bee | ||
|
|
3d0e8c9629 | ||
|
|
313bbbb94c | ||
|
|
0360f078de | ||
|
|
c8901666c4 | ||
|
|
7430006596 | ||
|
|
f3e06b2dbd | ||
|
|
e97df307ff | ||
|
|
1443354aa2 | ||
|
|
250e68c1cd | ||
|
|
6a380ee99c | ||
|
|
3c90bd96a9 | ||
|
|
06a7ceb25a | ||
|
|
733a8e7d58 | ||
|
|
570bbe9a05 | ||
|
|
5cc3adb39a | ||
|
|
3957a0606c | ||
|
|
11a561dbce | ||
|
|
dad2198394 | ||
|
|
e40fdc502d | ||
|
|
d446fe5922 | ||
|
|
4ca90c106d | ||
|
|
7c5e58a497 | ||
|
|
323b9a5f8e | ||
|
|
cab381a339 | ||
|
|
fe4d4c39cd | ||
|
|
ad188d7ae1 | ||
|
|
8246cc0538 | ||
|
|
6f3ac46b1c | ||
|
|
ac71c3be63 | ||
|
|
ecc0ac9b19 | ||
|
|
ea4e6bf67d | ||
|
|
46c204f533 | ||
|
|
71fbda8bf6 | ||
|
|
9b79b4a7c8 | ||
|
|
c04cc853d7 | ||
|
|
dd41e70ccc | ||
|
|
4206e74f42 | ||
|
|
68c3ce56a9 | ||
|
|
ab0e5fa425 | ||
|
|
f3b0434a87 | ||
|
|
aa394440db | ||
|
|
3b98a1a04b | ||
|
|
fcb89b0c58 | ||
|
|
ac65d6a03a | ||
|
|
2103f60906 | ||
|
|
e3c3d848c1 | ||
|
|
d4ef3411e0 | ||
|
|
71d616e413 | ||
|
|
fe651d1bf5 | ||
|
|
582ba8cfad | ||
|
|
d23291650a | ||
|
|
812fd745b6 | ||
|
|
a87aa71d85 | ||
|
|
60b2eb1455 | ||
|
|
ab3c1988c1 | ||
|
|
ee5223eea8 | ||
|
|
edd2185268 | ||
|
|
35b1ca2be2 | ||
|
|
71e493a810 | ||
|
|
6178e22e7f | ||
|
|
ef0aab060a | ||
|
|
d70ce61cfd | ||
|
|
8cd84afac8 | ||
|
|
ec2c6c312b | ||
|
|
3946bba318 | ||
|
|
2ed0b78a7b | ||
|
|
ed346d032c | ||
|
|
acd645f192 | ||
|
|
88433e4c34 | ||
|
|
1224af1780 | ||
|
|
ab13342931 | ||
|
|
d7913da484 | ||
|
|
c50e3f1329 | ||
|
|
a62f86dbd7 | ||
|
|
33b88b18db | ||
|
|
7c691c21ab | ||
|
|
4ec51729d8 | ||
|
|
07b41e479a | ||
|
|
6510bcad19 | ||
|
|
265d2ce39b | ||
|
|
1928a64cae | ||
|
|
11e575a5a3 | ||
|
|
7fbc0d6460 | ||
|
|
1ba8b1aa4b | ||
|
|
3569c76c0f | ||
|
|
16c7ac2582 | ||
|
|
4ceb59215f | ||
|
|
2e6879ee51 | ||
|
|
66fc2e9d7d | ||
|
|
2c7a6e574f | ||
|
|
78c3bf5dba | ||
|
|
98c115e3bb | ||
|
|
2752bda80b | ||
|
|
7c0940609a | ||
|
|
d30a879e2d | ||
|
|
b907234d5c | ||
|
|
b0114c9174 | ||
|
|
d2ba8c501f | ||
|
|
6a7ed7d359 | ||
|
|
6289afa1a6 | ||
|
|
9bb6fa04cb | ||
|
|
afb6f6f5c9 | ||
|
|
8a69671dbd | ||
|
|
178aee4687 | ||
|
|
8484caddfb | ||
|
|
08313316de | ||
|
|
1d0eca5c63 | ||
|
|
fe89232a30 | ||
|
|
4b51b521e2 | ||
|
|
e9ec458304 | ||
|
|
54b0ddd787 | ||
|
|
93bec22f9c | ||
|
|
0dc96442d8 | ||
|
|
58f4582517 | ||
|
|
2d15c09cca | ||
|
|
04cb8865b0 | ||
|
|
6fe32bbaf7 | ||
|
|
4abb20390d | ||
|
|
daa3916430 | ||
|
|
e9b87cefcc | ||
|
|
60593b5ad3 | ||
|
|
f708b11ea4 | ||
|
|
7982f58b2e | ||
|
|
e805c1908a | ||
|
|
cb3ba8e973 | ||
|
|
344fc40cbc | ||
|
|
7e5c37137b | ||
|
|
1aae11714b | ||
|
|
d82f14a7aa | ||
|
|
4b65e0b093 | ||
|
|
43b0faa830 | ||
|
|
8674c9fb20 | ||
|
|
ccfbb54e8c | ||
|
|
9893ebf889 | ||
|
|
303eb3e93a | ||
|
|
ca546d70e5 | ||
|
|
6a5ea2d64a | ||
|
|
ec3d92ad8e | ||
|
|
66a095d7de | ||
|
|
411981efbc | ||
|
|
350ad5210e | ||
|
|
f3b588764e | ||
|
|
b49f5a7d77 | ||
|
|
bacbcba58a | ||
|
|
52e8aa434f | ||
|
|
37c508f3f8 | ||
|
|
26e36422cc | ||
|
|
f82cb002bc | ||
|
|
c1eb047a4b | ||
|
|
626ca18f5c | ||
|
|
9058dedfbe | ||
|
|
a0952bfca3 | ||
|
|
354e61946e | ||
|
|
fd6d1d748a | ||
|
|
360acd1e2c | ||
|
|
fc0479f110 | ||
|
|
62728205b6 | ||
|
|
dc0fb25e64 | ||
|
|
f3e04cce56 | ||
|
|
7067110308 | ||
|
|
599d889703 | ||
|
|
2fa8366632 | ||
|
|
c368c51bad | ||
|
|
7c558b3713 | ||
|
|
8d323ae510 | ||
|
|
3b53e9adac | ||
|
|
074c1d71b4 | ||
|
|
1fca9a004d | ||
|
|
b485a1ef78 | ||
|
|
326ef7a3ac | ||
|
|
12bc58b5b6 | ||
|
|
6af0815681 | ||
|
|
66c2b9b78e | ||
|
|
d03c056cb1 | ||
|
|
3f94d628fa | ||
|
|
a64c7dbe99 | ||
|
|
61b3ccb57c | ||
|
|
424b4b33b1 | ||
|
|
e510f89792 | ||
|
|
49cd6cc619 | ||
|
|
9aa3d340d4 | ||
|
|
09782242c8 | ||
|
|
9ec4aa039d | ||
|
|
ecebe2f24b | ||
|
|
7313a77c2a | ||
|
|
45113676a3 | ||
|
|
102bd07019 | ||
|
|
9622e31da9 | ||
|
|
1731ce2a44 | ||
|
|
276f421c44 | ||
|
|
133357779a | ||
|
|
5d8167b232 | ||
|
|
e76ae8c46c | ||
|
|
53a7c0e668 | ||
|
|
4ca243e490 | ||
|
|
9f37446155 | ||
|
|
d7c7559b05 | ||
|
|
b2b66d1344 | ||
|
|
5d111a3c04 | ||
|
|
10416f847f | ||
|
|
79b3472b26 | ||
|
|
f1b2f1ae08 | ||
|
|
ee7d97ae8c | ||
|
|
7d9f473bb1 | ||
|
|
e77a5e5e75 | ||
|
|
6ab19af122 | ||
|
|
276fe49867 | ||
|
|
acb31abe86 | ||
|
|
4f964a3c8a | ||
|
|
df1fda7438 | ||
|
|
d6124c1787 | ||
|
|
80d89b5420 | ||
|
|
74059eecf1 | ||
|
|
78697341a2 | ||
|
|
cfb56dd8ff | ||
|
|
b1769cbe18 | ||
|
|
955b801e7f | ||
|
|
3cea3f1afe | ||
|
|
fd4a227ccb | ||
|
|
19c3097483 | ||
|
|
cdd1a6d03c | ||
|
|
5fb8411571 | ||
|
|
334a15b8c7 | ||
|
|
6390736577 | ||
|
|
d55a214516 | ||
|
|
0994164b9a | ||
|
|
54ee0dd147 | ||
|
|
47c7990fb3 | ||
|
|
997e95de4d | ||
|
|
44204be256 | ||
|
|
9b1d9aa88a | ||
|
|
b775762f6a | ||
|
|
df1a28e319 | ||
|
|
c300b2802a | ||
|
|
01040ace4c | ||
|
|
8367172e0b | ||
|
|
09afd8d25d | ||
|
|
7ed60429b3 | ||
|
|
281eafada0 | ||
|
|
c14e10128a | ||
|
|
3270635192 | ||
|
|
3d26257710 | ||
|
|
c4f134d694 | ||
|
|
83f9dfbac4 | ||
|
|
3a445ad5f7 | ||
|
|
c6d106ec33 | ||
|
|
2ce6834be4 | ||
|
|
b376672dbc | ||
|
|
d07db8547f | ||
|
|
aab08bfcc7 | ||
|
|
e0a25494ee | ||
|
|
fd876d5e4e | ||
|
|
ee7f008ff5 | ||
|
|
d9161a6ddb | ||
|
|
f8d66768e3 | ||
|
|
4f3673d14d | ||
|
|
1712fdb74a | ||
|
|
3a5ffc79e0 | ||
|
|
859b063444 | ||
|
|
bd61e7c644 | ||
|
|
c9abf282b5 | ||
|
|
9dad40b5a3 | ||
|
|
8e2d690cb0 | ||
|
|
c132e091e1 | ||
|
|
630e6cbf1e | ||
|
|
83ff5760a8 | ||
|
|
fed0ee638e | ||
|
|
cc161780df | ||
|
|
898b2b000a | ||
|
|
b3ee743ed7 | ||
|
|
ef17b669fe | ||
|
|
2dff3e07ce | ||
|
|
53c88093ad | ||
|
|
0ec13d3a17 | ||
|
|
0d5104049a | ||
|
|
ce8fa69785 | ||
|
|
30072e0c70 | ||
|
|
eb04a890b2 | ||
|
|
0c53adb04f | ||
|
|
ee5a43fd47 | ||
|
|
c43d6c2cbe | ||
|
|
87aeeacb04 | ||
|
|
6b26e9cad6 | ||
|
|
85af0f0d03 | ||
|
|
f6f4705ea3 | ||
|
|
a4702bff22 | ||
|
|
73c5c48f79 | ||
|
|
adf495e8cc | ||
|
|
9247ea00bf | ||
|
|
a1238d7bf9 | ||
|
|
2d63268f0f | ||
|
|
1cb5f6a90d | ||
|
|
8d848284df | ||
|
|
8fe54d1a5c | ||
|
|
11dd9f14c3 | ||
|
|
16d24f1166 | ||
|
|
97015ef775 | ||
|
|
2744dafb74 | ||
|
|
7b268dbe1a | ||
|
|
8fcbbcef94 | ||
|
|
8f93f0a06e | ||
|
|
387142488c | ||
|
|
6887e232fc | ||
|
|
6ac7ffd77b | ||
|
|
b28faa582a | ||
|
|
454ee029c8 | ||
|
|
a036de318e | ||
|
|
9918c4020e | ||
|
|
3d6264e1b8 | ||
|
|
1c25270503 | ||
|
|
47e50f82c4 | ||
|
|
27ecdfbba8 | ||
|
|
6901550065 | ||
|
|
6e6f918630 | ||
|
|
4633812246 | ||
|
|
14bd1555aa | ||
|
|
b9d7687fa0 | ||
|
|
93b36965e2 | ||
|
|
9e0c443c2f | ||
|
|
60832152b1 | ||
|
|
6a160d22fe | ||
|
|
e35526192c | ||
|
|
bea57bdded | ||
|
|
2a9da225e4 | ||
|
|
a3f37de9b5 | ||
|
|
6064160953 | ||
|
|
8508141314 | ||
|
|
1c95597882 | ||
|
|
587fa63c8e | ||
|
|
b40eec4cb0 | ||
|
|
7bcd48c269 | ||
|
|
2e7cd52c0f | ||
|
|
77d4cb367e | ||
|
|
2c45c5abc6 | ||
|
|
a89afabd79 | ||
|
|
03f7c9bf07 | ||
|
|
d5f4862749 | ||
|
|
8aced0b6d3 | ||
|
|
6b9adef684 | ||
|
|
5440d988fc | ||
|
|
30da4fc569 | ||
|
|
2c1b5e100b | ||
|
|
3684f278ed | ||
|
|
6c3cb6acba | ||
|
|
b98ba8d174 | ||
|
|
d3088829af | ||
|
|
9aaaba1714 | ||
|
|
9adb0d696f | ||
|
|
c270f1ba5f | ||
|
|
7b255b575a | ||
|
|
d7a9f3a2ab | ||
|
|
abf2e7e9bb | ||
|
|
72e5fa9ba0 | ||
|
|
32c1078d2c | ||
|
|
133f901a69 | ||
|
|
42cd683ec0 | ||
|
|
151eb05377 | ||
|
|
16177d0a52 | ||
|
|
5ce544289f | ||
|
|
77bd35c3c7 | ||
|
|
0c5c208db0 | ||
|
|
60eb745331 | ||
|
|
9f90b5cb0a | ||
|
|
5adff94545 | ||
|
|
aa2baabfa9 | ||
|
|
75c2b23efc | ||
|
|
6451017962 | ||
|
|
0f857a6a34 | ||
|
|
7638a88a6a | ||
|
|
bed12d2021 | ||
|
|
587569fcb6 | ||
|
|
8c0dc9a06d | ||
|
|
289e4025ad | ||
|
|
5476eafe4c | ||
|
|
df32f283cd | ||
|
|
68ecaac9cc | ||
|
|
cffd4623ca | ||
|
|
6dc2782e80 | ||
|
|
5df187c086 | ||
|
|
7fd172e41e | ||
|
|
619528a1b5 | ||
|
|
596d468c14 | ||
|
|
eddbf1060a | ||
|
|
33731a6864 | ||
|
|
0c36cd2e24 | ||
|
|
5cef1be26d | ||
|
|
e89f482c3d | ||
|
|
fe3e40305d | ||
|
|
a92b5ceb6b | ||
|
|
0e7e7d8437 | ||
|
|
f47fa98f33 | ||
|
|
d3d5879911 | ||
|
|
b2168e11db | ||
|
|
6d5d8be708 | ||
|
|
ce2dbdf372 | ||
|
|
ec8a35a7a6 | ||
|
|
f6577c22c3 | ||
|
|
43d6c03093 | ||
|
|
1870f116bb | ||
|
|
8b87def013 | ||
|
|
de599d97b5 | ||
|
|
5d7e6b45c4 | ||
|
|
c6091bcfe1 | ||
|
|
466a8a1318 | ||
|
|
a99ba3b696 | ||
|
|
9229f7c6cc | ||
|
|
bf114bb188 | ||
|
|
b8eed2f861 | ||
|
|
ccb1e347be | ||
|
|
8698974f11 | ||
|
|
f2c79c4341 | ||
|
|
4966d1346b | ||
|
|
4a9337f757 | ||
|
|
db311fb6a2 | ||
|
|
02c1dcec8e | ||
|
|
52dc74d3ce | ||
|
|
cc2af2bc15 | ||
|
|
638c6db05d | ||
|
|
f7db8d9aff | ||
|
|
564fb7a87e | ||
|
|
4d88e64774 | ||
|
|
26f1163b46 | ||
|
|
40058e99e0 | ||
|
|
bece4c3e02 | ||
|
|
f0f6b57c87 | ||
|
|
dc2a4ab044 | ||
|
|
b16d6f5b81 | ||
|
|
69ce6ff7b5 | ||
|
|
32ba50b8dc | ||
|
|
36aca45f35 | ||
|
|
925290342d | ||
|
|
4dc0370c57 | ||
|
|
b92f8e43f2 | ||
|
|
22b0733a1d | ||
|
|
6021684ab6 | ||
|
|
f4b1d0cdfe | ||
|
|
d0d8048621 | ||
|
|
cfd119325d | ||
|
|
ad30833ffc | ||
|
|
e5c79a6666 | ||
|
|
63dc753c1b | ||
|
|
017bc1f252 | ||
|
|
bcd67c009d | ||
|
|
635358884e | ||
|
|
2f6cfafdfc | ||
|
|
25234fa30b | ||
|
|
5b17341804 | ||
|
|
9bedfa9a72 | ||
|
|
e1f1220970 | ||
|
|
5855bcd1fe | ||
|
|
a14af5b9ee | ||
|
|
f11c03750e | ||
|
|
ea5cfa40c1 | ||
|
|
c562754d81 | ||
|
|
90d892512a | ||
|
|
9c6fedb15b | ||
|
|
3a7175115f | ||
|
|
98c41f3223 | ||
|
|
d101e96e16 | ||
|
|
a446b6c440 | ||
|
|
b1fec0f1b1 | ||
|
|
1dfdc93745 | ||
|
|
6c5ee4095c | ||
|
|
986fbf63a4 | ||
|
|
2612105d32 | ||
|
|
954fe13f54 | ||
|
|
bb5a00685e | ||
|
|
dabbddb04e | ||
|
|
5f173e5acb | ||
|
|
b28ff40aea | ||
|
|
fccfb4589e | ||
|
|
5384c98013 | ||
|
|
2ed2307573 | ||
|
|
3f8a2d8d3e | ||
|
|
1a13b7c85f | ||
|
|
d7130a1e56 | ||
|
|
f69054cb17 | ||
|
|
80dc6eca2c | ||
|
|
d250fbb3d6 | ||
|
|
09bbe92611 | ||
|
|
69d922e096 | ||
|
|
d510e7e4ae | ||
|
|
5893290dd9 | ||
|
|
5c3bbc4031 | ||
|
|
27cd8cf0db | ||
|
|
b403016d5b | ||
|
|
5a81823969 | ||
|
|
17801401cd | ||
|
|
5c7b2a2a36 | ||
|
|
1db06de287 | ||
|
|
3904178d44 | ||
|
|
8bb9c3610c | ||
|
|
7dcc382ccc | ||
|
|
b71fc807d2 | ||
|
|
15d28d970a | ||
|
|
e083a860e9 | ||
|
|
6463b9dd84 | ||
|
|
c873de6ca4 | ||
|
|
b70863b47e | ||
|
|
3546f84c6d | ||
|
|
1d98917db9 | ||
|
|
1c34fd69cf | ||
|
|
4cf38404cc | ||
|
|
112fb5098b | ||
|
|
5ace6906c7 | ||
|
|
8cfbdaf0d0 | ||
|
|
6703434976 | ||
|
|
62edc15cd7 | ||
|
|
be830ddc31 | ||
|
|
18322b424f | ||
|
|
6901c60db4 | ||
|
|
e369ce6766 | ||
|
|
64e4e5d91e | ||
|
|
efce7de9ae | ||
|
|
38c64ac689 | ||
|
|
6d203e3eee | ||
|
|
81f461e557 | ||
|
|
988bde1387 | ||
|
|
aedbabdbe8 | ||
|
|
6ed53e53c7 | ||
|
|
a78630ce99 | ||
|
|
6653066784 | ||
|
|
e40f1fa081 | ||
|
|
a872ce751d | ||
|
|
317846fbdc | ||
|
|
f581a55544 | ||
|
|
447b291e70 | ||
|
|
01d07253e8 | ||
|
|
034a466094 | ||
|
|
c6211e2335 | ||
|
|
1d03a6417d | ||
|
|
1d62ef27a2 | ||
|
|
996048dc08 | ||
|
|
bf02ee3bdc | ||
|
|
a3c7fba02d | ||
|
|
a8cd7febf6 | ||
|
|
20c008b84f | ||
|
|
7cd73566be | ||
|
|
e56fd53d06 | ||
|
|
810b1b3b3e | ||
|
|
cb0b033fe7 | ||
|
|
46f673a3b7 | ||
|
|
455303b3d4 | ||
|
|
24a84d6380 | ||
|
|
9aa2171052 | ||
|
|
3a46ea1f36 | ||
|
|
d33779f301 | ||
|
|
d6ea0793b8 | ||
|
|
4e5e5bb925 | ||
|
|
3232ed8e38 | ||
|
|
29d6748af8 | ||
|
|
828f195071 | ||
|
|
b0b7e32783 | ||
|
|
c1103c0248 | ||
|
|
940a016e95 | ||
|
|
c6cc098e47 | ||
|
|
54f47ab89b | ||
|
|
fc3de64dce | ||
|
|
414c4e3f3c | ||
|
|
6a9f38d31e | ||
|
|
aa4256d35c | ||
|
|
8a1241ba44 | ||
|
|
7eab052e0f | ||
|
|
552d19e36b | ||
|
|
463b04e795 | ||
|
|
c0d8508264 | ||
|
|
6ef4ba31e2 | ||
|
|
10a3d26291 | ||
|
|
ab994b32ee | ||
|
|
9352b71d78 | ||
|
|
71593421ed | ||
|
|
2754970f37 | ||
|
|
5945454597 | ||
|
|
884dbce712 | ||
|
|
8ee1bc6598 | ||
|
|
7d76c46731 | ||
|
|
f8ccf42c06 | ||
|
|
0abe0f1f10 | ||
|
|
ee8a5d80ff | ||
|
|
f08893b5c8 | ||
|
|
41cd88506e | ||
|
|
081223b138 | ||
|
|
4e60c9ba09 | ||
|
|
95fe7cd3bc | ||
|
|
79ec1d994e | ||
|
|
045362425f | ||
|
|
2b2637fbc3 | ||
|
|
bfc4f7a28d | ||
|
|
407670e1f3 | ||
|
|
d0671d81b5 | ||
|
|
7a74ebbcc3 | ||
|
|
9e69800332 | ||
|
|
7542188592 | ||
|
|
b4a23c005d | ||
|
|
5e0f8be4b1 | ||
|
|
50dee55606 | ||
|
|
da5cd01fe4 | ||
|
|
d3fb317d41 | ||
|
|
88ddeb1fb6 | ||
|
|
f9e2e74bf3 | ||
|
|
87e01aff60 | ||
|
|
7e8481186a | ||
|
|
2b0103a4e6 | ||
|
|
064d4be83c | ||
|
|
ab536d5678 | ||
|
|
9db805c4ad | ||
|
|
f7923a9761 | ||
|
|
fd52650255 | ||
|
|
f0fe295175 | ||
|
|
2f89aa3935 | ||
|
|
5aa27343e0 | ||
|
|
5ce2841389 | ||
|
|
e4ffb58269 | ||
|
|
2ce3d9e19d | ||
|
|
9271fe73a8 | ||
|
|
edaa70b97f | ||
|
|
ab07f4deea |
@@ -0,0 +1,84 @@
|
||||
# OCRmyPDF
|
||||
#
|
||||
FROM ubuntu:20.04 as base
|
||||
|
||||
FROM base as builder
|
||||
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential autoconf automake libtool \
|
||||
libleptonica-dev \
|
||||
zlib1g-dev \
|
||||
python3-dev \
|
||||
python3-distutils \
|
||||
libffi-dev \
|
||||
libqpdf-dev \
|
||||
ca-certificates \
|
||||
curl \
|
||||
git
|
||||
|
||||
# Get the latest pip (Ubuntu version doesn't support manylinux2010)
|
||||
RUN \
|
||||
curl https://bootstrap.pypa.io/get-pip.py | python3
|
||||
|
||||
# Compile and install jbig2
|
||||
# Needs libleptonica-dev, zlib1g-dev
|
||||
RUN \
|
||||
mkdir jbig2 \
|
||||
&& curl -L https://github.com/agl/jbig2enc/archive/ea6a40a.tar.gz | \
|
||||
tar xz -C jbig2 --strip-components=1 \
|
||||
&& cd jbig2 \
|
||||
&& ./autogen.sh && ./configure && make && make install \
|
||||
&& cd .. \
|
||||
&& rm -rf jbig2
|
||||
|
||||
COPY . /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN pip3 install --no-cache-dir \
|
||||
-r requirements/main.txt \
|
||||
-r requirements/webservice.txt \
|
||||
-r requirements/test.txt \
|
||||
-r requirements/watcher.txt \
|
||||
.
|
||||
|
||||
FROM base
|
||||
|
||||
ENV LANG=C.UTF-8
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ghostscript \
|
||||
img2pdf \
|
||||
liblept5 \
|
||||
libsm6 libxext6 libxrender-dev \
|
||||
zlib1g \
|
||||
pngquant \
|
||||
python3 \
|
||||
qpdf \
|
||||
tesseract-ocr \
|
||||
tesseract-ocr-chi-sim \
|
||||
tesseract-ocr-deu \
|
||||
tesseract-ocr-eng \
|
||||
tesseract-ocr-fra \
|
||||
tesseract-ocr-por \
|
||||
tesseract-ocr-spa \
|
||||
unpaper \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /usr/local/lib/ /usr/local/lib/
|
||||
COPY --from=builder /usr/local/bin/ /usr/local/bin/
|
||||
|
||||
COPY --from=builder /app/misc/webservice.py /app/
|
||||
COPY --from=builder /app/misc/watcher.py /app/
|
||||
|
||||
# Copy minimal project files to get the test suite.
|
||||
COPY --from=builder /app/setup.cfg /app/setup.py /app/README.md /app/
|
||||
COPY --from=builder /app/requirements /app/requirements
|
||||
COPY --from=builder /app/tests /app/tests
|
||||
COPY --from=builder /app/src /app/src
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/ocrmypdf"]
|
||||
@@ -0,0 +1,44 @@
|
||||
# dotfiles
|
||||
.*
|
||||
!.coveragerc
|
||||
!.dockerignore
|
||||
!.git_archival.txt
|
||||
!.gitattributes
|
||||
!.gitignore
|
||||
!.pre-commit-config.yaml
|
||||
!.readthedocs.yml
|
||||
|
||||
# Dev scratch
|
||||
*.ipynb
|
||||
**/*.pyc
|
||||
/*.pdf
|
||||
/*.qdf
|
||||
/*.png
|
||||
/scratch.py
|
||||
IDEAS
|
||||
log/
|
||||
tests/resources/private/
|
||||
tmp/
|
||||
venv*/
|
||||
/debug_tests.py
|
||||
*.traineddata
|
||||
/private
|
||||
|
||||
# Package building
|
||||
*.egg-info/
|
||||
build/
|
||||
dist/
|
||||
wheelhouse/
|
||||
pip-wheel-metadata/
|
||||
|
||||
# Code coverage
|
||||
htmlcov/
|
||||
|
||||
# Docker specific
|
||||
bin/
|
||||
docs/
|
||||
include/
|
||||
lib/
|
||||
|
||||
# Docker include .git/
|
||||
!.git/
|
||||
@@ -0,0 +1 @@
|
||||
ref-names: $Format:%D$
|
||||
+10
-18
@@ -1,22 +1,14 @@
|
||||
# Always use Unix convention for new lines
|
||||
* text eol=lf
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
*.sln merge=union
|
||||
*.csproj merge=union
|
||||
*.vbproj merge=union
|
||||
*.fsproj merge=union
|
||||
*.dbproj merge=union
|
||||
# These files are binary and should be left untouched
|
||||
# (binary is a macro for -text -diff)
|
||||
*.jar binary
|
||||
*.pdf binary
|
||||
*.PDF binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.bin binary
|
||||
*.afdesign binary
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
.git_archival.txt export-subst
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: james-barlow
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: General issues
|
||||
about: Installation, packages, dependencies, "nothing works", test suite failures...
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
What's the problem?
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior.
|
||||
|
||||
**Expected behavior**
|
||||
What did you expected to happen?
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**System (please complete the following information):**
|
||||
- OS:
|
||||
- Python version:
|
||||
- OCRmyPDF version:
|
||||
|
||||
**Installation**
|
||||
How did you install OCRmyPDF? Did you install it from your operating system's
|
||||
package manager, or using pip?
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: Problem with a specific input file
|
||||
about: Something went wrong while trying to OCR a specific file
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
What command line or API call were you trying to run?
|
||||
|
||||
```bash
|
||||
ocrmypdf ...arguments... input.pdf output.pdf
|
||||
```
|
||||
|
||||
Run with verbosity or higher `-v1` to see more detailed logging. This information may be helpful.
|
||||
|
||||
**Example file**
|
||||
If your issue is a problem that affects only certain files, and we will require an input file (PDF or image) that demonstrates your issue.
|
||||
|
||||
Please provide an input file with no personal or confidential information. At your option you may [GPG-encrypt the file](https://github.com/jbarlow83/OCRmyPDF/wiki) for OCRmyPDF's author only.
|
||||
|
||||
Links to files hosted elsewhere are perfectly acceptable. You could also look in ``tests/resources`` and see if any of those files reproduce your issue.
|
||||
|
||||
*(Issues without example files usually cannot be resolved. It's like reporting an issue against a web browser without providing a URL.)*
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**System**
|
||||
- OS: [e.g. Linux, Windows, macOS]
|
||||
- OCRmyPDF Version: ``ocrmypdf --version``
|
||||
- How did you install ocrmypdf? Did you use a system package manager, `pip`, or a Docker image?
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,275 @@
|
||||
name: Test and deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- ci
|
||||
- release/*
|
||||
tags:
|
||||
- v*
|
||||
paths-ignore:
|
||||
- README*
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test_linux:
|
||||
name: Test ${{ matrix.os }} with Python ${{ matrix.python }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-18.04] #, ubuntu-20.04]
|
||||
python: ["3.6"] #, "3.7", "3.8", "3.9"]
|
||||
|
||||
env:
|
||||
OS: ${{ matrix.os }}
|
||||
PYTHON: ${{ matrix.python }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: "0" # 0=all, needed for setuptools-scm to resolve version tags
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
name: Install Python
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Install common packages
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ghostscript \
|
||||
img2pdf \
|
||||
libffi-dev \
|
||||
liblept5 \
|
||||
libsm6 libxext6 libxrender-dev \
|
||||
pngquant \
|
||||
poppler-utils \
|
||||
tesseract-ocr \
|
||||
tesseract-ocr-deu \
|
||||
tesseract-ocr-eng \
|
||||
unpaper \
|
||||
zlib1g
|
||||
|
||||
- name: Install Ubuntu 18.04 packages
|
||||
if: matrix.os == 'ubuntu-18.04'
|
||||
run: |
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libexempi3
|
||||
|
||||
- name: Install Ubuntu 20.04 packages
|
||||
if: matrix.os == 'ubuntu-20.04'
|
||||
run: |
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libexempi8
|
||||
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
python -m pip install -r requirements/main.txt -r requirements/test.txt .
|
||||
|
||||
- name: Report versions
|
||||
run: |
|
||||
tesseract --version
|
||||
gs --version
|
||||
pngquant --version
|
||||
unpaper --version
|
||||
img2pdf --version
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
python -m pytest --cov-report xml --cov=ocrmypdf --cov=tests/ -n0 tests/
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
files: ./coverage.xml
|
||||
env_vars: OS,PYTHON
|
||||
|
||||
test_macos:
|
||||
name: Test macOS
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest]
|
||||
python: ["3.9"]
|
||||
|
||||
env:
|
||||
OS: ${{ matrix.os }}
|
||||
PYTHON: ${{ matrix.python }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: "0" # 0=all, needed for setuptools-scm to resolve version tags
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
name: Install Python
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Install Homebrew deps
|
||||
run: |
|
||||
brew update
|
||||
brew install \
|
||||
exempi \
|
||||
ghostscript \
|
||||
jbig2enc \
|
||||
leptonica \
|
||||
openjpeg \
|
||||
pngquant \
|
||||
tesseract
|
||||
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements/main.txt -r requirements/test.txt .
|
||||
|
||||
- name: Report versions
|
||||
run: |
|
||||
tesseract --version
|
||||
gs --version
|
||||
pngquant --version
|
||||
img2pdf --version
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
python -m pytest --cov-report xml --cov=ocrmypdf --cov=tests/ -n0 tests/
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
files: ./coverage.xml
|
||||
env_vars: OS,PYTHON
|
||||
|
||||
test_windows:
|
||||
name: Test Windows
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest]
|
||||
python: ["3.9"]
|
||||
|
||||
env:
|
||||
OS: ${{ matrix.os }}
|
||||
PYTHON: ${{ matrix.python }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: "0" # 0=all, needed for setuptools-scm to resolve version tags
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
name: Install Python
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
|
||||
- name: Install system packages
|
||||
run: |
|
||||
choco install --yes --no-progress --pre tesseract
|
||||
choco install --yes --no-progress ghostscript
|
||||
choco install --yes --no-progress pngquant
|
||||
|
||||
- name: Install Python packages
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements/main.txt -r requirements/test.txt .
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
python -m pytest --cov-report xml --cov=ocrmypdf --cov=tests/ -n0 tests/
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
files: ./coverage.xml
|
||||
env_vars: OS,PYTHON
|
||||
|
||||
wheel_sdist_linux:
|
||||
name: Build sdist and wheels
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: "0" # 0=all, needed for setuptools-scm to resolve version tags
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
name: Install Python
|
||||
with:
|
||||
python-version: "3.6"
|
||||
|
||||
- name: Make wheels and sdist
|
||||
run: |
|
||||
python -m pip install --upgrade pip wheel
|
||||
python setup.py sdist
|
||||
python setup.py bdist_wheel
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: |
|
||||
./dist/*.whl
|
||||
./dist/*.tar.gz
|
||||
|
||||
upload_pypi:
|
||||
name: Deploy artifacts to PyPI
|
||||
needs: [wheel_sdist_linux, test_linux, test_macos, test_windows]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: artifact
|
||||
path: dist
|
||||
|
||||
- uses: pypa/gh-action-pypi-publish@master
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.TOKEN_PYPI }}
|
||||
# repository_url: https://test.pypi.org/legacy/
|
||||
|
||||
docker:
|
||||
name: Build Docker images
|
||||
needs: [wheel_sdist_linux, test_linux, test_macos, test_windows]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set image tag to release or branch
|
||||
run: echo "DOCKER_IMAGE_TAG=${GITHUB_REF##*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: If master, set to latest
|
||||
run: echo 'DOCKER_IMAGE_TAG=latest' >> $GITHUB_ENV
|
||||
if: env.DOCKER_IMAGE_TAG == 'master'
|
||||
|
||||
- name: Set Docker Hub repository to username
|
||||
run: echo "DOCKER_REPOSITORY=jbarlow83" >> $GITHUB_ENV
|
||||
|
||||
- name: Set image name
|
||||
run: echo "DOCKER_IMAGE_NAME=ocrmypdf" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: "0" # 0=all, needed for setuptools-scm to resolve version tags
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: jbarlow83
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Print image tag
|
||||
run: echo "Building image ${DOCKER_REPOSITORY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}"
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
docker buildx build \
|
||||
--push \
|
||||
--platform linux/arm64/v8,linux/amd64 \
|
||||
--tag "${DOCKER_REPOSITORY}/${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" \
|
||||
--file .docker/Dockerfile .
|
||||
+39
-162
@@ -1,167 +1,44 @@
|
||||
releasePackage.sh
|
||||
tmp/
|
||||
# dotfiles
|
||||
.*
|
||||
!.coveragerc
|
||||
!.dockerignore
|
||||
!.git_archival.txt
|
||||
!.gitattributes
|
||||
!.gitignore
|
||||
!.pre-commit-config.yaml
|
||||
!.readthedocs.yml
|
||||
!.github/
|
||||
|
||||
# Dev scratch
|
||||
*.ipynb
|
||||
**/*.pyc
|
||||
/*.pdf
|
||||
/*.qdf
|
||||
/*.png
|
||||
/scratch.py
|
||||
IDEAS
|
||||
log/
|
||||
|
||||
#################
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
bin/
|
||||
tests/resources/private/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
venv*/
|
||||
/debug_tests.py
|
||||
*.traineddata
|
||||
/private
|
||||
/coverage.xml
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
# Package building
|
||||
*.egg-info/
|
||||
build/
|
||||
dist/
|
||||
wheelhouse/
|
||||
pip-wheel-metadata/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
# Code coverage
|
||||
htmlcov/
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
#################
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.vspscc
|
||||
.builds
|
||||
*.dotCover
|
||||
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment this
|
||||
#packages/
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish
|
||||
|
||||
# Others
|
||||
[Bb]in
|
||||
[Oo]bj
|
||||
sql
|
||||
TestResults
|
||||
*.Cache
|
||||
ClientBin
|
||||
stylecop.*
|
||||
~$*
|
||||
*.dbmdl
|
||||
Generated_Code #added for RIA/Silverlight projects
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
|
||||
|
||||
|
||||
############
|
||||
## Windows
|
||||
############
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
|
||||
#############
|
||||
## Python
|
||||
#############
|
||||
|
||||
*.py[co]
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
bin
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
# Automatically generated files
|
||||
docs/_build/
|
||||
docs/_static/
|
||||
docs/_templates/
|
||||
docs/Makefile
|
||||
ocrmypdf/lib/_*.py
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.4.0
|
||||
hooks:
|
||||
- id: check-case-conflict
|
||||
- id: check-merge-conflict
|
||||
- id: check-toml
|
||||
- id: check-yaml
|
||||
- id: debug-statements
|
||||
- repo: https://github.com/asottile/seed-isort-config
|
||||
rev: v2.2.0
|
||||
hooks:
|
||||
- id: seed-isort-config
|
||||
- repo: https://github.com/pre-commit/mirrors-isort
|
||||
rev: v5.7.0 # pick the isort version you'd like to use from https://github.com/pre-commit/mirrors-isort/releases
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 20.8b1
|
||||
hooks:
|
||||
- id: black
|
||||
language_version: python
|
||||
exclude: ^src/ocrmypdf/lib/_leptonica.py
|
||||
@@ -0,0 +1,10 @@
|
||||
build:
|
||||
image: latest
|
||||
|
||||
python:
|
||||
version: 3.6
|
||||
|
||||
formats:
|
||||
- pdf
|
||||
|
||||
requirements_file: requirements/main.txt
|
||||
@@ -1,17 +0,0 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
-370
@@ -1,370 +0,0 @@
|
||||
#!/bin/sh
|
||||
##############################################################################
|
||||
# Copyright (c) 2013: fritz-hh from Github (https://github.com/fritz-hh)
|
||||
##############################################################################
|
||||
|
||||
TOOLNAME="OCRmyPDF"
|
||||
VERSION="v1.0-rc2"
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
--------------------------------------------------------------------------------------
|
||||
Script aimed at generating a searchable PDF file from a PDF file containing only images.
|
||||
(The script performs optical character recognition of each respective page using the
|
||||
tesseract engine)
|
||||
|
||||
Copyright: fritz from NAS4Free forum
|
||||
Version: $VERSION
|
||||
|
||||
Usage: OCRmyPDF.sh [-h] [-v] [-g] [-k] [-d] [-c] [-i] [-l language] [-C filename] inputfile outputfile
|
||||
|
||||
-h : Display this help message
|
||||
-v : Increase the verbosity (this option can be used more than once)
|
||||
-k : Do not delete the temporary files
|
||||
-g : Activate debug mode:
|
||||
- Generates a PDF file containing each page twice (once with the image, once without the image
|
||||
but with the OCRed text as well as the detected bounding boxes)
|
||||
- Set the verbosity to the highest possible
|
||||
- Do not delete the temporary files
|
||||
-d : Deskew each page before performing OCR
|
||||
-c : Clean each page before performing OCR
|
||||
-i : Incorporate the cleaned image in the final PDF file (by default the original image
|
||||
image, or the deskewed image if the -d option is set, is incorporated)
|
||||
-l : Set the language of the PDF file in order to improve OCR results (default "eng")
|
||||
Any language supported by tesseract is supported.
|
||||
-C : Pass an additional configuration file to the tesseract OCR engine.
|
||||
(this option can be used more than once)
|
||||
Note: The configuration file must be available in the "tessdata/configs" folder
|
||||
of your tesseract installation
|
||||
inputfile : PDF file to be OCRed
|
||||
outputfile : The PDF/A file to be generated
|
||||
--------------------------------------------------------------------------------------
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
#################################################
|
||||
# Get an absolute path from a relative path to a file
|
||||
#
|
||||
# Param1 : Relative path
|
||||
# Returns: 1 if the folder in which the file is located does not exist
|
||||
# 0 otherwise
|
||||
#################################################
|
||||
absolutePath() {
|
||||
local wdsave absolutepath
|
||||
wdsave="`pwd`"
|
||||
! cd "`dirname "$1"`" 1> /dev/null 2> /dev/null && return 1
|
||||
absolutepath="`pwd`/`basename $1`"
|
||||
cd "$wdsave"
|
||||
echo "$absolutepath"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Initialization of constants
|
||||
EXIT_BAD_ARGS="1" # possible exit codes
|
||||
EXIT_BAD_INPUT_FILE="2"
|
||||
EXIT_MISSING_DEPENDENCY="3"
|
||||
EXIT_INVALID_OUPUT_PDFA="4"
|
||||
EXIT_OTHER_ERROR="5"
|
||||
LOG_ERR="0" # 0=only error messages
|
||||
LOG_INFO="1" # 1=error messages and some infos
|
||||
LOG_DEBUG="2" # 2=debug level logging
|
||||
SRC="./src" # location of the source folder (except source of external tools like jhove)
|
||||
JHOVE="./jhove/bin/JhoveApp.jar" # java SW for validating the final PDF/A
|
||||
JHOVE_CFG="./jhove/conf/jhove.conf" # location of the jhove config file
|
||||
|
||||
# Initialization the configuration parameters with default values
|
||||
VERBOSITY="$LOG_ERR" # default verbosity level
|
||||
LAN="eng" # default language of the PDF file (required to get good OCR results)
|
||||
KEEP_TMP="0" # do not delete the temporary files (default)
|
||||
PREPROCESS_DESKEW="0" # 0=no, 1=yes (deskew image)
|
||||
PREPROCESS_CLEAN="0" # 0=no, 1=yes (clean image to improve OCR)
|
||||
PREPROCESS_CLEANTOPDF="0" # 0=no, 1=yes (put cleaned image in final PDF)
|
||||
PDF_NOIMG="0" # 0=no, 1=yes (generates each PDF page twice, with and without image)
|
||||
TESS_CFG_FILES="" # list of additional configuration files to be used by tesseract
|
||||
|
||||
# Parse optional command line arguments
|
||||
while getopts ":hvgkdcil:C:" opt; do
|
||||
case $opt in
|
||||
h) usage ; exit 0 ;;
|
||||
v) VERBOSITY=$(($VERBOSITY+1)) ;;
|
||||
k) KEEP_TMP="1" ;;
|
||||
g) PDF_NOIMG="1"; VERBOSITY="10"; KEEP_TMP="1" ;;
|
||||
d) PREPROCESS_DESKEW="1" ;;
|
||||
c) PREPROCESS_CLEAN="1" ;;
|
||||
i) PREPROCESS_CLEANTOPDF="1" ;;
|
||||
l) LAN="$OPTARG" ;;
|
||||
C) TESS_CFG_FILES="$OPTARG $TESS_CFG_FILES" ;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
usage
|
||||
exit $EXIT_BAD_ARGS ;;
|
||||
:)
|
||||
echo "Option -$OPTARG requires an argument" >&2
|
||||
usage
|
||||
exit $EXIT_BAD_ARGS ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Remove the optional arguments parsed above.
|
||||
shift $((OPTIND-1))
|
||||
|
||||
# Check if the number of mandatory parameters
|
||||
# provided is as expected
|
||||
if [ "$#" -ne "2" ]; then
|
||||
echo "Exactly one mandatory argument shall be provided" >&2
|
||||
usage
|
||||
exit $EXIT_BAD_ARGS
|
||||
fi
|
||||
|
||||
! absolutePath "$1" > /dev/null && echo "The folder in which the input file should be located does not exist. Exiting..." >&2 && exit $EXIT_BAD_ARGS
|
||||
FILE_INPUT_PDF="`absolutePath "$1"`"
|
||||
! absolutePath "$2" > /dev/null && echo "The folder in which the output file should be generated does not exist. Exiting..." >&2 && exit $EXIT_BAD_ARGS
|
||||
FILE_OUTPUT_PDFA="`absolutePath "$2"`"
|
||||
|
||||
|
||||
|
||||
# set script path as working directory
|
||||
cd "`dirname $0`"
|
||||
|
||||
[ $VERBOSITY -ge $LOG_INFO ] && echo "$TOOLNAME version: $VERSION"
|
||||
|
||||
# check if the required utilities are installed
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Checking if all dependencies are installed"
|
||||
! command -v identify > /dev/null && echo "Please install ImageMagick. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
! command -v pdfimages > /dev/null && echo "Please install poppler-utils. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
! command -v pdftoppm > /dev/null && echo "Please install poppler-utils. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
! command -v pdftk > /dev/null && echo "Please install pdftk. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
[ $PREPROCESS_CLEAN -eq 1 ] && ! command -v unpaper > /dev/null && echo "Please install unpaper. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
! command -v tesseract > /dev/null && echo "Please install tesseract and tesseract-data. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
! command -v python > /dev/null && echo "Please install python, and the python libraries: reportlab, lxml. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
! command -v gs > /dev/null && echo "Please install ghostcript. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
! command -v java > /dev/null && echo "Please install java. Exiting..." >&2 && exit $EXIT_MISSING_DEPENDENCY
|
||||
|
||||
|
||||
|
||||
|
||||
# Initialize path to temporary files
|
||||
TMP_FLD="./tmp/`date +"%Y%m%d_%H%M"`.filename.`basename "$FILE_INPUT_PDF" | sed s/[.][^.]*//`"
|
||||
FILE_SIZE_PAGES="$TMP_FLD/page-sizes.txt" # size in pt of the respective page of the input PDF file
|
||||
FILE_INPUT_PDF_METADATA="$TMP_FLD/input-metadata.txt" # metadata of the input pdf file
|
||||
FILES_OCRed_PDFS="${TMP_FLD}/*-ocred.pdf" # string matching all 1 page PDF files that need to be merged
|
||||
FILE_OUTPUT_PDF_CAT="${TMP_FLD}/ocred.pdf" # concatenated OCRed PDF files
|
||||
FILE_OUTPUT_PDFA_WO_META="${TMP_FLD}/ocred-pdfa-wo-metadata.pdf" # PDFA file before appending metadata
|
||||
FILE_OUTPUT_PDFA_META="${TMP_FLD}/ocred-pdfa-metadata1.pdf" # PDFA file with metadata of the input pdf file
|
||||
FILE_VALIDATION_LOG="${TMP_FLD}/pdf_validation.log" # log file containing the results of the validation of the PDF/A file
|
||||
FILE_INPUT_PDF_ACL="${TMP_FLD}/input-pdf-acl.txt"
|
||||
|
||||
# Create tmp folder
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Creating temporary folder"
|
||||
rm -r -f "${TMP_FLD}"
|
||||
mkdir -p "${TMP_FLD}"
|
||||
|
||||
|
||||
|
||||
|
||||
# get the size of each pdf page (width / height) in pt (inch*72)
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Input file: Extracting size of each page (in pt)"
|
||||
! identify -format "%w %h\n" "$FILE_INPUT_PDF" > "$FILE_SIZE_PAGES" \
|
||||
&& echo "Could not get size of PDF pages. Exiting..." >&2 && exit $EXIT_BAD_INPUT_FILE
|
||||
sed -I "" '/^$/d' "$FILE_SIZE_PAGES" # removing empty lines (last one should be)
|
||||
numpages=`cat "$FILE_SIZE_PAGES" | wc -l | sed 's/^ *//g'`
|
||||
[ $VERBOSITY -ge $LOG_INFO ] && echo "Input file: The file has $numpages pages"
|
||||
|
||||
# Itterate the pages of the input pdf file
|
||||
cpt="1"
|
||||
while read pageSize ; do
|
||||
|
||||
# add leading zeros to the page number
|
||||
page=`printf "%04d" $cpt`
|
||||
[ $VERBOSITY -ge $LOG_INFO ] && echo "Processing page $page"
|
||||
|
||||
# create the name of the required file
|
||||
curOrigImg="$TMP_FLD/${page}_Image" # original image available in the current PDF page
|
||||
# (the image file may have a different orientation than in the pdf file)
|
||||
curHocr="$TMP_FLD/$page.hocr" # hocr file to be generated by the OCR SW for the current page
|
||||
curOCRedPDF="$TMP_FLD/${page}-ocred.pdf" # PDF file containing the image + the OCRed text for the current page
|
||||
curOCRedPDFDebug="$TMP_FLD/${page}-debug-ocred.pdf" # PDF file containing data required to find out if OCR worked correctly
|
||||
|
||||
# get width / height of PDF page (in pt)
|
||||
widthPDF=`echo $pageSize | cut -f1 -d" "`
|
||||
heightPDF=`echo $pageSize | cut -f2 -d" "`
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: size ${heightPDF}x${widthPDF} (h*w in pt)"
|
||||
# extract raw image from pdf file to compute resolution
|
||||
# unfortunatelly this image can have another orientation than in the pdf...
|
||||
# so we will have to extract it again later
|
||||
pdfimages -f $page -l $page -j "$FILE_INPUT_PDF" "$curOrigImg" 1>&2
|
||||
# count number of extracted images
|
||||
nbImg=`ls -1 "$curOrigImg"* | wc -l`
|
||||
[ $nbImg -ne "1" ] && echo "Expecting exactly 1 image on page $page (found $nbImg). Exiting..." >&2 && exit $EXIT_BAD_INPUT_FILE
|
||||
# Get characteristics of the extracted image
|
||||
curImg=`ls -1 "$curOrigImg"*`
|
||||
propCurImg=`identify -format "%w %h %[colorspace]" "$curImg"`
|
||||
widthCurImg=`echo "$propCurImg" | cut -f1 -d" "`
|
||||
heightCurImg=`echo "$propCurImg" | cut -f2 -d" "`
|
||||
colorspaceCurImg=`echo "$propCurImg" | cut -f3 -d" "`
|
||||
# switch height/width values if the image has not the right orientation
|
||||
# we make here the assumption that vertical/horizontal dpi are equal
|
||||
# we will check that later
|
||||
if [ $((($heightPDF-$widthPDF)*($heightCurImg-$widthCurImg))) -lt 0 ]; then
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: Extracted image has wrong orientation. Inverting image height/width values"
|
||||
tmpval=$heightCurImg
|
||||
heightCurImg=$widthCurImg
|
||||
widthCurImg=$tmpval
|
||||
fi
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: size ${heightCurImg}x${widthCurImg} (h*w pixel)"
|
||||
# compute the resolution of the image
|
||||
dpi_x=$(($widthCurImg*72/$widthPDF))
|
||||
dpi_y=$(($heightCurImg*72/$heightPDF))
|
||||
[ "$dpi_x" -ne "$dpi_y" ] && echo "X/Y resolutions not equal ($dpi_x/$dpi_y). Exiting..." >&2 && exit $EXIT_BAD_INPUT_FILE
|
||||
dpi="$dpi_x"
|
||||
|
||||
# Identify if page image should be saved as ppm (color) or pgm (gray)
|
||||
ext="ppm"
|
||||
opt=""
|
||||
if [ $colorspaceCurImg == "Gray" ]; then
|
||||
ext="pgm"
|
||||
opt="-gray"
|
||||
fi
|
||||
curImgPixmap="$TMP_FLD/$page.$ext"
|
||||
curImgPixmapDeskewed="$TMP_FLD/$page.deskewed.$ext"
|
||||
curImgPixmapClean="$TMP_FLD/$page.cleaned.$ext"
|
||||
|
||||
# extract current page as image with right orientation and resoltution
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: Extracting image as $ext file (${dpi} dpi)"
|
||||
! pdftoppm -f $page -l $page -r $dpi $opt "$FILE_INPUT_PDF" > "$curImgPixmap" \
|
||||
&& echo "Could not extract page $page as $ext from $FILE_INPUT_PDF. Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
|
||||
# if requested deskew image (without changing its size in pixel)
|
||||
if [ "$PREPROCESS_DESKEW" -eq "1" ]; then
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: Deskewing image"
|
||||
! convert "$curImgPixmap" -deskew 40% -gravity center -extent ${widthCurImg}x${heightCurImg} "$curImgPixmapDeskewed" \
|
||||
&& echo "Could not deskew \"$curImgPixmap\". Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
else
|
||||
cp "$curImgPixmap" "$curImgPixmapDeskewed"
|
||||
fi
|
||||
|
||||
# if requested clean image with unpaper to get better OCR results
|
||||
if [ "$PREPROCESS_CLEAN" -eq "1" ]; then
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: Cleaning image with unpaper"
|
||||
! unpaper --dpi $dpi --mask-scan-size 100 \
|
||||
--no-deskew --no-grayfilter --no-blackfilter --no-mask-center --no-border-align \
|
||||
"$curImgPixmapDeskewed" "$curImgPixmapClean" 1> /dev/null \
|
||||
&& echo "Could not clean \"$curImgPixmapDeskewed\". Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
else
|
||||
cp "$curImgPixmapDeskewed" "$curImgPixmapClean"
|
||||
fi
|
||||
|
||||
# perform OCR
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: Performing OCR"
|
||||
! tesseract -l "$LAN" "$curImgPixmapClean" "$curHocr" hocr $TESS_CFG_FILES 1> /dev/null 2> /dev/null \
|
||||
&& echo "Could not OCR file \"$curImgPixmapClean\". Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
mv "$curHocr.html" "$curHocr"
|
||||
|
||||
# embed text and image to new pdf file
|
||||
if [ "$PREPROCESS_CLEANTOPDF" -eq "1" ]; then
|
||||
image4finalPDF="$curImgPixmapClean"
|
||||
else
|
||||
image4finalPDF="$curImgPixmapDeskewed"
|
||||
fi
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: Embedding text in PDF"
|
||||
! python $SRC/hocrTransform.py -r $dpi -i "$image4finalPDF" "$curHocr" "$curOCRedPDF" \
|
||||
&& echo "Could not create PDF file from \"$curHocr\". Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
|
||||
# if requested generate special debug PDF page with visible OCR text
|
||||
if [ $PDF_NOIMG -eq "1" ] ; then
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Page $page: Embedding text in PDF (debug page)"
|
||||
! python $SRC/hocrTransform.py -b -r $dpi "$curHocr" "$curOCRedPDFDebug" \
|
||||
&& echo "Could not create PDF file from \"$curHocr\". Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
fi
|
||||
|
||||
# delete temporary files created for the current page
|
||||
# to avoid using to much disk space in case of PDF files having many pages
|
||||
if [ $KEEP_TMP -eq 0 ]; then
|
||||
rm "$curOrigImg"*.*
|
||||
rm "$curHocr"
|
||||
rm "$curImgPixmap"
|
||||
rm "$curImgPixmapDeskewed"
|
||||
rm "$curImgPixmapClean"
|
||||
fi
|
||||
|
||||
# go to next page of the pdf
|
||||
cpt=$(($cpt+1))
|
||||
|
||||
done < "$FILE_SIZE_PAGES"
|
||||
|
||||
|
||||
|
||||
|
||||
# concatenate all pages
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Output file: Concatenating all pages"
|
||||
! pdftk $FILES_OCRed_PDFS cat output "$FILE_OUTPUT_PDF_CAT" \
|
||||
&& echo "Could not concatenate individual PDF pages (\"$FILES_OCRed_PDFS\") to one file. Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
|
||||
# convert the pdf file to match PDF/A format
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Output file: Converting to PDF/A"
|
||||
! gs -dQUIET -dPDFA -dBATCH -dNOPAUSE -dUseCIEColor \
|
||||
-sProcessColorModel=DeviceCMYK -sDEVICE=pdfwrite -sPDFACompatibilityPolicy=2 \
|
||||
-sOutputFile="$FILE_OUTPUT_PDFA_WO_META" "$FILE_OUTPUT_PDF_CAT" 1> /dev/null 2> /dev/null \
|
||||
&& echo "Could not convert PDF file \"$FILE_OUTPUT_PDF_CAT\" to PDF/A. Exiting..." >&2 && exit $EXIT_OTHER_ERROR
|
||||
|
||||
# Write metadata
|
||||
# Needs to be done after converting to PDF/A, as gs does not preserve metadata
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Output file: Restoring metadata from input PDF"
|
||||
if ! pdftk "$FILE_INPUT_PDF" dump_data_utf8 > "$FILE_INPUT_PDF_METADATA" \
|
||||
|| ! pdftk "$FILE_OUTPUT_PDFA_WO_META" update_info_utf8 "$FILE_INPUT_PDF_METADATA" output "$FILE_OUTPUT_PDFA_META"; then
|
||||
echo "Output file: Could not restore metadata from input PDF"
|
||||
fi
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Output file: Update metadata (creator, producer, and title)"
|
||||
title=`basename $FILE_INPUT_PDF | sed 's/[.][^.]*//' | sed 's/_/ /g' | sed 's/-/ /g'`
|
||||
pdftk "$FILE_OUTPUT_PDFA_META" update_info_utf8 - output "$FILE_OUTPUT_PDFA" << EOF
|
||||
InfoBegin
|
||||
InfoKey: Title
|
||||
InfoValue: $title
|
||||
InfoBegin
|
||||
InfoKey: Creator
|
||||
InfoValue: $TOOLNAME $VERSION
|
||||
InfoBegin
|
||||
InfoKey: Producer
|
||||
InfoValue: ghostcript `gs --version`, pdftk
|
||||
EOF
|
||||
|
||||
# validate generated pdf file (compliance to PDF/A)
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Output file: Checking compliance to PDF/A standard"
|
||||
java -jar "$JHOVE" -c "$JHOVE_CFG" -m PDF-hul "$FILE_OUTPUT_PDFA" > "$FILE_VALIDATION_LOG"
|
||||
grep -i "Status|Message" "$FILE_VALIDATION_LOG" # summary of the validation
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && cat "$FILE_VALIDATION_LOG"
|
||||
# check the validation results
|
||||
pdf_valid=1
|
||||
grep -i 'ErrorMessage' "$FILE_VALIDATION_LOG" >&2 && pdf_valid=0
|
||||
grep -i 'Status.*not valid' "$FILE_VALIDATION_LOG" >&2 && pdf_valid=0
|
||||
grep -i 'Status.*Not well-formed' "$FILE_VALIDATION_LOG" >&2 && pdf_valid=0
|
||||
! grep -i 'Profile:.*PDF/A-1' "$FILE_VALIDATION_LOG" > /dev/null && echo "PDF file profile is not PDF/A-1" >&2 && pdf_valid=0
|
||||
[ $pdf_valid -ne 1 ] && echo "Output file: The generated PDF/A file is INVALID" >&2
|
||||
[ $pdf_valid -ne 0 ] && [ $VERBOSITY -ge $LOG_INFO ] && echo "Output file: The generated PDF/A file is VALID"
|
||||
|
||||
|
||||
|
||||
# set the owner / group / permissions of the output (equal to those of the intput file)
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Output file: restoring owner, group, permissions"
|
||||
owner=`stat -f "%Su" "$FILE_INPUT_PDF"`
|
||||
group=`stat -f "%Sg" "$FILE_INPUT_PDF"`
|
||||
! chown $owner:$group "$FILE_OUTPUT_PDFA" \
|
||||
&& echo "Could not restore owner/group" >&2
|
||||
getfacl "$FILE_INPUT_PDF" > "$FILE_INPUT_PDF_ACL"
|
||||
! setfacl -M "$FILE_INPUT_PDF_ACL" "$FILE_OUTPUT_PDFA" \
|
||||
&& echo "Could not restore permissions" >&2
|
||||
|
||||
|
||||
|
||||
# delete temporary files
|
||||
if [ $KEEP_TMP -eq 0 ]; then
|
||||
[ $VERBOSITY -ge $LOG_DEBUG ] && echo "Deleting temporary files"
|
||||
rm -r -f "${TMP_FLD}"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
[ $pdf_valid -ne 1 ] && exit $EXIT_INVALID_OUPUT_PDFA || exit 0
|
||||
@@ -1,42 +1,137 @@
|
||||
OCRmyPDF
|
||||
========
|
||||
<img src="docs/images/logo.svg" width="240" alt="OCRmyPDF">
|
||||
|
||||
OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to be searched
|
||||
[](https://github.com/jbarlow83/OCRmyPDF/actions/workflows/build.yml) [![PyPI version][pypi]](https://pypi.org/project/ocrmypdf/) ![Homebrew version][homebrew] ![ReadTheDocs][docs] ![Python versions][pyversions]
|
||||
|
||||
To get the script usage, call: ./OCmyPDF.sh -h
|
||||
[azure]: https://dev.azure.com/jim0585/ocrmypdf/_apis/build/status/jbarlow83.OCRmyPDF?branchName=master
|
||||
[travis]: https://travis-ci.org/jbarlow83/OCRmyPDF.svg?branch=master "Travis build status"
|
||||
[pypi]: https://img.shields.io/pypi/v/ocrmypdf.svg "PyPI version"
|
||||
[homebrew]: https://img.shields.io/homebrew/v/ocrmypdf.svg "Homebrew version"
|
||||
[docs]: https://readthedocs.org/projects/ocrmypdf/badge/?version=latest "RTD"
|
||||
[pyversions]: https://img.shields.io/pypi/pyversions/ocrmypdf "Supported Python versions"
|
||||
|
||||
Features
|
||||
--------
|
||||
OCRmyPDF adds an OCR text layer to scanned PDF files, allowing them to be searched or copy-pasted.
|
||||
|
||||
- Generate a searchable PDF/A file from a PDF file containing only images
|
||||
- Place OCRed text accurately below the image to easy copy / paste
|
||||
- Keep the exact resolution of the original embedded images
|
||||
- If requested deskew and / or clean the image before performing OCR
|
||||
- Validate the generated file against the PDF/A specification using jhove
|
||||
- Provides debug mode to enable easy verification of the OCR results
|
||||
```bash
|
||||
ocrmypdf # it's a scriptable command line program
|
||||
-l eng+fra # it supports multiple languages
|
||||
--rotate-pages # it can fix pages that are misrotated
|
||||
--deskew # it can deskew crooked PDFs!
|
||||
--title "My PDF" # it can change output metadata
|
||||
--jobs 4 # it uses multiple cores by default
|
||||
--output-type pdfa # it produces PDF/A by default
|
||||
input_scanned.pdf # takes PDF input (or images)
|
||||
output_searchable.pdf # produces validated PDF output
|
||||
```
|
||||
|
||||
Motivation
|
||||
----------
|
||||
[See the release notes for details on the latest changes](https://ocrmypdf.readthedocs.io/en/latest/release_notes.html).
|
||||
|
||||
## Main features
|
||||
|
||||
- Generates a searchable [PDF/A](https://en.wikipedia.org/?title=PDF/A) file from a regular PDF
|
||||
- Places OCR text accurately below the image to ease copy / paste
|
||||
- Keeps the exact resolution of the original embedded images
|
||||
- When possible, inserts OCR information as a "lossless" operation without disrupting any other content
|
||||
- Optimizes PDF images, often producing files smaller than the input file
|
||||
- If requested, deskews and/or cleans the image before performing OCR
|
||||
- Validates input and output files
|
||||
- Distributes work across all available CPU cores
|
||||
- Uses [Tesseract OCR](https://github.com/tesseract-ocr/tesseract) engine to recognize more than [100 languages](https://github.com/tesseract-ocr/tessdata)
|
||||
- Scales properly to handle files with thousands of pages
|
||||
- Battle-tested on millions of PDFs
|
||||
|
||||
For details: please consult the [documentation](https://ocrmypdf.readthedocs.io/en/latest/).
|
||||
|
||||
## Motivation
|
||||
|
||||
I searched the web for a free command line tool to OCR PDF files: I found many, but none of them were really satisfying:
|
||||
|
||||
I searched the web for a free command line tool to OCR PDF files on linux/unix:
|
||||
I found many, but none of them were really satisfying.
|
||||
- Either they produced PDF files with misplaced text under the image (making copy/paste impossible)
|
||||
- Or they did not display correctly some escaped html characters located in the hocr file produced by the OCR engine
|
||||
- Or they did not handle accents and multilingual characters
|
||||
- Or they changed the resolution of the embedded images
|
||||
- Or they generated PDF file having a ridiculous big size
|
||||
- Or they crashed when trying to OCR some of my PDF files
|
||||
- Or they did not produce valid PDF files (even though they were readable with my current PDF reader)
|
||||
- On top of that none of them produced PDF/A files (format dedicated for long time storage / archiving)
|
||||
- Or they generated ridiculously large PDF files
|
||||
- Or they crashed when trying to OCR
|
||||
- Or they did not produce valid PDF files
|
||||
- On top of that none of them produced PDF/A files (format dedicated for long time storage)
|
||||
|
||||
... so I decided to develop my own tool (using various existing scripts as an inspiration)
|
||||
...so I decided to develop my own tool.
|
||||
|
||||
Install
|
||||
--------
|
||||
## Installation
|
||||
|
||||
Download OCRmyPDF here: https://github.com/fritz-hh/OCRmyPDF/tags
|
||||
Linux, Windows, macOS and FreeBSD are supported. Docker images are also available.
|
||||
|
||||
Copy the file in onto your linux/unix machine and extract it.
|
||||
| Operating system | Install command |
|
||||
| ----------------------------- | ------------------------------|
|
||||
| Debian, Ubuntu | ``apt install ocrmypdf`` |
|
||||
| Windows Subsystem for Linux | ``apt install ocrmypdf`` |
|
||||
| Fedora | ``dnf install ocrmypdf`` |
|
||||
| macOS | ``brew install ocrmypdf`` |
|
||||
| LinuxBrew | ``brew install ocrmypdf`` |
|
||||
| FreeBSD | ``pkg install py37-ocrmypdf`` |
|
||||
| Conda | ``conda install ocrmypdf`` |
|
||||
|
||||
Run: "sh ./OCRmyPDF.sh -h" to get the script usage
|
||||
For everyone else, [see our documentation](https://ocrmypdf.readthedocs.io/en/latest/installation.html) for installation steps.
|
||||
|
||||
If not yet installed, the script will notify you about dependencies that need to be installed
|
||||
## Languages
|
||||
|
||||
OCRmyPDF uses Tesseract for OCR, and relies on its language packs. For Linux users, you can often find packages that provide language packs:
|
||||
|
||||
```bash
|
||||
# Display a list of all Tesseract language packs
|
||||
apt-cache search tesseract-ocr
|
||||
|
||||
# Debian/Ubuntu users
|
||||
apt-get install tesseract-ocr-chi-sim # Example: Install Chinese Simplified language pack
|
||||
|
||||
# Arch Linux users
|
||||
pacman -S tesseract-data-eng tesseract-data-deu # Example: Install the English and German language packs
|
||||
|
||||
# brew macOS users
|
||||
brew install tesseract-lang
|
||||
```
|
||||
|
||||
You can then pass the `-l LANG` argument to OCRmyPDF to give a hint as to what languages it should search for. Multiple languages can be requested.
|
||||
|
||||
## Documentation and support
|
||||
|
||||
Once OCRmyPDF is installed, the built-in help which explains the command syntax and options can be accessed via:
|
||||
|
||||
```bash
|
||||
ocrmypdf --help
|
||||
```
|
||||
|
||||
Our [documentation is served on Read the Docs](https://ocrmypdf.readthedocs.io/en/latest/index.html).
|
||||
|
||||
Please report issues on our [GitHub issues](https://github.com/jbarlow83/OCRmyPDF/issues) page, and follow the issue template for quick response.
|
||||
|
||||
## Requirements
|
||||
|
||||
In addition to the required Python version (3.6+), OCRmyPDF requires external program installations of Ghostscript, Tesseract OCR, QPDF, and Leptonica. OCRmyPDF is pure Python, but uses CFFI to portably generate library bindings. OCRmyPDF works on pretty much everything: Linux, macOS, Windows and FreeBSD.
|
||||
|
||||
## Press & Media
|
||||
|
||||
- [Going paperless with OCRmyPDF](https://medium.com/@ikirichenko/going-paperless-with-ocrmypdf-e2f36143f46a)
|
||||
- [Converting a scanned document into a compressed searchable PDF with redactions](https://medium.com/@treyharris/converting-a-scanned-document-into-a-compressed-searchable-pdf-with-redactions-63f61c34fe4c)
|
||||
- [c't 1-2014, page 59](https://heise.de/-2279695): Detailed presentation of OCRmyPDF v1.0 in the leading German IT magazine c't
|
||||
- [heise Open Source, 09/2014: Texterkennung mit OCRmyPDF](https://heise.de/-2356670)
|
||||
- [heise Durchsuchbare PDF-Dokumente mit OCRmyPDF erstellen](https://www.heise.de/ratgeber/Durchsuchbare-PDF-Dokumente-mit-OCRmyPDF-erstellen-4607592.html)
|
||||
- [Excellent Utilities: OCRmyPDF](https://www.linuxlinks.com/excellent-utilities-ocrmypdf-add-ocr-text-layer-scanned-pdfs/)
|
||||
|
||||
## Business enquiries
|
||||
|
||||
OCRmyPDF would not be the software that it is today without companies and users choosing to provide support for feature development and consulting enquiries. We are happy to discuss all enquiries, whether for extending the existing feature set, or integrating OCRmyPDF into a larger system.
|
||||
|
||||
## License
|
||||
|
||||
The OCRmyPDF software is licensed under the Mozilla Public License 2.0
|
||||
(MPL-2.0). This license permits integration of OCRmyPDF with other code,
|
||||
included commercial and closed source, but asks you to publish source-level
|
||||
modifications you make to OCRmyPDF.
|
||||
|
||||
Some components of OCRmyPDF have other licenses, as noted in those files and the
|
||||
``debian/copyright`` file. Most files in ``misc/`` use the MIT license, and the
|
||||
documentation and test files are generally licensed under Creative Commons
|
||||
ShareAlike 4.0 (CC-BY-SA 4.0).
|
||||
|
||||
## Disclaimer
|
||||
|
||||
The software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
RELEASE NOTES
|
||||
=============
|
||||
|
||||
Please always read this file before installing the package
|
||||
|
||||
Download software here: https://github.com/fritz-hh/OCRmyPDF/tags
|
||||
|
||||
v1.0-rc2 (2013-04-29):
|
||||
====
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- Keep temporary files if debug mode is set (fixes #22)
|
||||
- Set same owner & permissions if final PDF file than in input file (fixes #9)
|
||||
- Added metadata in final pdf file (fixes #4)
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- N/A
|
||||
|
||||
Fixes
|
||||
-----
|
||||
|
||||
- Fixed wrong image cropping when deskew option is activated
|
||||
- Exit with error message if page size is not found in hocr file (fixes #21)
|
||||
- Various minor fixes in log messages
|
||||
|
||||
Tested with
|
||||
-----------
|
||||
|
||||
- Operating system: FreeBSD 9.1
|
||||
- Dependencies:
|
||||
- poppler-utils 0.22.2
|
||||
- ImageMagick 6.8.0-7 2013-03-30
|
||||
- Unpaper 0.3
|
||||
- tesseract 3.02.02
|
||||
- Python 2.7.3
|
||||
- pdftk 1.45
|
||||
- ghoscript (gs): 9.06
|
||||
- java: openjdk version "1.7.0_17"
|
||||
|
||||
v1.0-rc1 (2013-04-26):
|
||||
====
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- First release candidate
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- N/A
|
||||
|
||||
Fixes
|
||||
-----
|
||||
|
||||
- N/A
|
||||
|
||||
Tested with
|
||||
-----------
|
||||
|
||||
- Operating system: FreeBSD 9.1
|
||||
- Dependencies:
|
||||
- poppler-utils 0.22.2
|
||||
- ImageMagick 6.8.0-7 2013-03-30
|
||||
- Unpaper 0.3
|
||||
- tesseract 3.02.02
|
||||
- Python 2.7.3
|
||||
- pdftk 1.45
|
||||
- ghoscript (gs): 9.06
|
||||
- java: openjdk version "1.7.0_17"
|
||||
Vendored
+2205
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,344 @@
|
||||
=================
|
||||
Advanced features
|
||||
=================
|
||||
|
||||
Control of unpaper
|
||||
==================
|
||||
|
||||
OCRmyPDF uses ``unpaper`` to provide the implementation of the
|
||||
``--clean`` and ``--clean-final`` arguments.
|
||||
`unpaper <https://github.com/Flameeyes/unpaper/blob/master/doc/basic-concepts.md>`__
|
||||
provides a variety of image processing filters to improve images.
|
||||
|
||||
By default, OCRmyPDF uses only ``unpaper`` arguments that were found to
|
||||
be safe to use on almost all files without having to inspect every page
|
||||
of the file afterwards. This is particularly true when only ``--clean``
|
||||
is used, since that instructs OCRmyPDF to only clean the image before
|
||||
OCR and not the final image.
|
||||
|
||||
However, if you wish to use the more aggressive options in ``unpaper``,
|
||||
you may use ``--unpaper-args '...'`` to override the OCRmyPDF's defaults
|
||||
and forward other arguments to unpaper. This option will forward
|
||||
arguments to ``unpaper`` without any knowledge of what that program
|
||||
considers to be valid arguments. The string of arguments must be quoted
|
||||
as shown in the examples below. No filename arguments may be included.
|
||||
OCRmyPDF will assume it can append input and output filename of
|
||||
intermediate images to the ``--unpaper-args`` string.
|
||||
|
||||
In this example, we tell ``unpaper`` to expect two pages of text on a
|
||||
sheet (image), such as occurs when two facing pages of a book are
|
||||
scanned. ``unpaper`` uses this information to deskew each independently
|
||||
and clean up the margins of both.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --clean --clean-final --unpaper-args '--layout double' input.pdf output.pdf
|
||||
ocrmypdf --clean --clean-final --unpaper-args '--layout double --no-noisefilter' input.pdf output.pdf
|
||||
|
||||
.. warning::
|
||||
|
||||
Some ``unpaper`` features will reposition text within the image.
|
||||
``--clean-final`` is recommended to avoid this issue.
|
||||
|
||||
.. warning::
|
||||
|
||||
Some ``unpaper`` features cause multiple input or output files to be
|
||||
consumed or produced. OCRmyPDF requires ``unpaper`` to consume one
|
||||
file and produce one file. An deviation from that condition will
|
||||
result in errors.
|
||||
|
||||
.. note::
|
||||
|
||||
``unpaper`` uses uncompressed PBM/PGM/PPM files for its intermediate
|
||||
files. For large images or documents, it can take a lot of temporary
|
||||
disk space.
|
||||
|
||||
Control of OCR options
|
||||
======================
|
||||
|
||||
OCRmyPDF provides many features to control the behavior of the OCR
|
||||
engine, Tesseract.
|
||||
|
||||
When OCR is skipped
|
||||
-------------------
|
||||
|
||||
If a page in a PDF seems to have text, by default OCRmyPDF will exit
|
||||
without modifying the PDF. This is to ensure that PDFs that were
|
||||
previously OCRed or were "born digital" rather than scanned are not
|
||||
processed.
|
||||
|
||||
If ``--skip-text`` is issued, then no OCR will be performed on pages
|
||||
that already have text. The page will be copied to the output. This may
|
||||
be useful for documents that contain both "born digital" and scanned
|
||||
content, or to use OCRmyPDF to normalize and convert to PDF/A regardless
|
||||
of their contents.
|
||||
|
||||
If ``--redo-ocr`` is issued, then a detailed text analysis is performed.
|
||||
Text is categorized as either visible or invisible. Invisible text (OCR)
|
||||
is stripped out. Then an image of each page is created with visible text
|
||||
masked out. The page image is sent for OCR, and any additional text is
|
||||
inserted as OCR. If a file contains a mix of text and bitmap images that
|
||||
contain text, OCRmyPDF will locate the additional text in images without
|
||||
disrupting the existing text.
|
||||
|
||||
If ``--force-ocr`` is issued, then all pages will be rasterized to
|
||||
images, discarding any hidden OCR text, and rasterizing any printable
|
||||
text. This is useful for redoing OCR, for fixing OCR text with a damaged
|
||||
character map (text is selectable but not searchable), and destroying
|
||||
redacted information. Any forms and vector graphics will be rasterized
|
||||
as well.
|
||||
|
||||
Time and image size limits
|
||||
--------------------------
|
||||
|
||||
By default, OCRmyPDF permits tesseract to run for three minutes (180
|
||||
seconds) per page. This is usually more than enough time to find all
|
||||
text on a reasonably sized page with modern hardware.
|
||||
|
||||
If a page is skipped, it will be inserted without OCR. If preprocessing
|
||||
was requested, the preprocessed image layer will be inserted.
|
||||
|
||||
If you want to adjust the amount of time spent on OCR, change
|
||||
``--tesseract-timeout``. You can also automatically skip images that
|
||||
exceed a certain number of megapixels with ``--skip-big``. (A 300 DPI,
|
||||
8.5×11" page is 8.4 megapixels.)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Allow 300 seconds for OCR; skip any page larger than 50 megapixels
|
||||
ocrmypdf --tesseract-timeout 300 --skip-big 50 bigfile.pdf output.pdf
|
||||
|
||||
Overriding default tesseract
|
||||
----------------------------
|
||||
|
||||
OCRmyPDF checks the system ``PATH`` for the ``tesseract`` binary.
|
||||
|
||||
Some relevant environment variables that influence Tesseract's behavior
|
||||
include:
|
||||
|
||||
.. envvar:: TESSDATA_PREFIX
|
||||
|
||||
Overrides the path to Tesseract's data files. This can allow
|
||||
simultaneous installation of the "best" and "fast" training data
|
||||
sets. OCRmyPDF does not manage this environment variable.
|
||||
|
||||
.. envvar:: OMP_THREAD_LIMIT
|
||||
|
||||
Controls the number of threads Tesseract will use. OCRmyPDF will
|
||||
manage this environment variable if it is not already set.
|
||||
|
||||
For example, if you have a development build of Tesseract don't wish to
|
||||
use the system installation, you can launch OCRmyPDF as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
env \
|
||||
PATH=/home/user/src/tesseract/api:$PATH \
|
||||
TESSDATA_PREFIX=/home/user/src/tesseract \
|
||||
ocrmypdf input.pdf output.pdf
|
||||
|
||||
In this example ``TESSDATA_PREFIX`` is required to redirect Tesseract to
|
||||
an alternate folder for its "tessdata" files.
|
||||
|
||||
Overriding other support programs
|
||||
---------------------------------
|
||||
|
||||
In addition to tesseract, OCRmyPDF uses the following external binaries:
|
||||
|
||||
- ``gs`` (Ghostscript)
|
||||
- ``unpaper``
|
||||
- ``pngquant``
|
||||
- ``jbig2``
|
||||
|
||||
In each case OCRmyPDF will search the ``PATH`` environment variable to
|
||||
locate the binaries.
|
||||
|
||||
Changing tesseract configuration variables
|
||||
------------------------------------------
|
||||
|
||||
You can override tesseract's default `control
|
||||
parameters <https://github.com/tesseract-ocr/tesseract/wiki/ControlParams>`__
|
||||
with a configuration file.
|
||||
|
||||
As an example, this configuration will disable Tesseract's dictionary
|
||||
for current language. Normally the dictionary is helpful for
|
||||
interpolating words that are unclear, but it may interfere with OCR if
|
||||
the document does not contain many words (for example, a list of part
|
||||
numbers).
|
||||
|
||||
Create a file named "no-dict.cfg" with these contents:
|
||||
|
||||
::
|
||||
|
||||
load_system_dawg 0
|
||||
language_model_penalty_non_dict_word 0
|
||||
language_model_penalty_non_freq_dict_word 0
|
||||
|
||||
then run ocrmypdf as follows (along with any other desired arguments):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --tesseract-config no-dict.cfg input.pdf output.pdf
|
||||
|
||||
.. warning::
|
||||
|
||||
Some combinations of control parameters will break Tesseract or break
|
||||
assumptions that OCRmyPDF makes about Tesseract's output.
|
||||
|
||||
Changing the PDF renderer
|
||||
=========================
|
||||
|
||||
rasterizing
|
||||
Converting a PDF to an image for display.
|
||||
|
||||
rendering
|
||||
Creating a new PDF from other data (such as an existing PDF).
|
||||
|
||||
OCRmyPDF has these PDF renderers: ``sandwich`` and ``hocr``. The
|
||||
renderer may be selected using ``--pdf-renderer``. The default is
|
||||
``auto`` which lets OCRmyPDF select the renderer to use. Currently,
|
||||
``auto`` always selects ``sandwich``.
|
||||
|
||||
The ``sandwich`` renderer
|
||||
-------------------------
|
||||
|
||||
The ``sandwich`` renderer uses Tesseract's new text-only PDF feature,
|
||||
which produces a PDF page that lays out the OCR in invisible text. This
|
||||
page is then "sandwiched" onto the original PDF page, allowing lossless
|
||||
application of OCR even to PDF pages that contain other vector objects.
|
||||
|
||||
Currently this is the best renderer for most uses, however it is
|
||||
implemented in Tesseract so OCRmyPDF cannot influence it. Currently some
|
||||
problematic PDF viewers like Mozilla PDF.js and macOS Preview have
|
||||
problems with segmenting its text output, and
|
||||
mightrunseveralwordstogether.
|
||||
|
||||
When image preprocessing features like ``--deskew`` are used, the
|
||||
original PDF will be rendered as a full page and the OCR layer will be
|
||||
placed on top.
|
||||
|
||||
The ``hocr`` renderer
|
||||
---------------------
|
||||
|
||||
The ``hocr`` renderer works with older versions of Tesseract. The image
|
||||
layer is copied from the original PDF page if possible, avoiding
|
||||
potentially lossy transcoding or loss of other PDF information. If
|
||||
preprocessing is specified, then the image layer is a new PDF.
|
||||
|
||||
Unlike ``sandwich`` this renderer is implemented within OCRmyPDF; anyone
|
||||
looking to customize how OCR is presented should look here. A major
|
||||
disadvantage of this renderer is it not capable of correctly handling
|
||||
text outside the Latin alphabet. Pull requests to improve the situation
|
||||
are welcome.
|
||||
|
||||
Currently, this renderer has the best compatibility with Mozilla's
|
||||
PDF.js viewer.
|
||||
|
||||
This works in all versions of Tesseract.
|
||||
|
||||
The ``tesseract`` renderer
|
||||
--------------------------
|
||||
|
||||
The ``tesseract`` renderer was removed. OCRmyPDF's new approach to text
|
||||
layer grafting makes it functionally equivalent to ``sandwich``.
|
||||
|
||||
Return code policy
|
||||
==================
|
||||
|
||||
OCRmyPDF writes all messages to ``stderr``. ``stdout`` is reserved for
|
||||
piping output files. ``stdin`` is reserved for piping input files.
|
||||
|
||||
The return codes generated by the OCRmyPDF are considered part of the
|
||||
stable user interface. They may be imported from
|
||||
``ocrmypdf.exceptions``.
|
||||
|
||||
.. list-table:: Return codes
|
||||
:widths: 5 35 60
|
||||
:header-rows: 1
|
||||
|
||||
* - Code
|
||||
- Name
|
||||
- Interpretation
|
||||
* - 0
|
||||
- ``ExitCode.ok``
|
||||
- Everything worked as expected.
|
||||
* - 1
|
||||
- ``ExitCode.bad_args``
|
||||
- Invalid arguments, exited with an error.
|
||||
* - 2
|
||||
- ``ExitCode.input_file``
|
||||
- The input file does not seem to be a valid PDF.
|
||||
* - 3
|
||||
- ``ExitCode.missing_dependency``
|
||||
- An external program required by OCRmyPDF is missing.
|
||||
* - 4
|
||||
- ``ExitCode.invalid_output_pdf``
|
||||
- An output file was created, but it does not seem to be a valid PDF. The file will be available.
|
||||
* - 5
|
||||
- ``ExitCode.file_access_error``
|
||||
- The user running OCRmyPDF does not have sufficient permissions to read the input file and write the output file.
|
||||
* - 6
|
||||
- ``ExitCode.already_done_ocr``
|
||||
- The file already appears to contain text so it may not need OCR. See output message.
|
||||
* - 7
|
||||
- ``ExitCode.child_process_error``
|
||||
- An error occurred in an external program (child process) and OCRmyPDF cannot continue.
|
||||
* - 8
|
||||
- ``ExitCode.encrypted_pdf``
|
||||
- The input PDF is encrypted. OCRmyPDF does not read encrypted PDFs. Use another program such as ``qpdf`` to remove encryption.
|
||||
* - 9
|
||||
- ``ExitCode.invalid_config``
|
||||
- A custom configuration file was forwarded to Tesseract using ``--tesseract-config``, and Tesseract rejected this file.
|
||||
* - 10
|
||||
- ``ExitCode.pdfa_conversion_failed``
|
||||
- A valid PDF was created, PDF/A conversion failed. The file will be available.
|
||||
* - 15
|
||||
- ``ExitCode.other_error``
|
||||
- Some other error occurred.
|
||||
* - 130
|
||||
- ``ExitCode.ctrl_c``
|
||||
- The program was interrupted by pressing Ctrl+C.
|
||||
|
||||
|
||||
Debugging the intermediate files
|
||||
================================
|
||||
|
||||
OCRmyPDF normally saves its intermediate results to a temporary folder
|
||||
and deletes this folder when it exits, whether it succeeded or failed.
|
||||
|
||||
If the ``-k`` argument is issued on the command line, OCRmyPDF will keep
|
||||
the temporary folder and print the location, whether it succeeded or
|
||||
failed (provided the Python interpreter did not crash). An example
|
||||
message is:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Temporary working files retained at:
|
||||
/tmp/ocrmypdf.io.u20wpz07
|
||||
|
||||
The organization of this folder is an implementation detail and subject
|
||||
to change between releases. However the general organization is that
|
||||
working files on a per page basis have the page number as a prefix
|
||||
(starting with page 1), an infix indicates the processing stage, and a
|
||||
suffix indicates the file type. Some important files include:
|
||||
|
||||
- ``_rasterize.png`` - what the input page looks like
|
||||
- ``_ocr.png`` - the file that is sent to Tesseract for OCR; depending
|
||||
on arguments this may differ from the presentation image
|
||||
- ``_pp_deskew.png`` - the image, after deskewing
|
||||
- ``_pp_clean.png`` - the image, after cleaning with unpaper
|
||||
- ``_ocr_tess.pdf`` - the OCR file; appears as a blank page with invisible
|
||||
text embedded
|
||||
- ``_ocr_tess.txt`` - the OCR text (not necessarily all text on the page,
|
||||
if the page is mixed format)
|
||||
- ``fix_docinfo.pdf`` - a temporary file created to fix the PDF DocumentInfo
|
||||
data structure
|
||||
- ``graft_layers.pdf`` - the rendered PDF with OCR layers grafted on
|
||||
- ``pdfa.pdf`` - ``graft_layers.pdf`` after conversion to PDF/A
|
||||
- ``pdfa.ps`` - a PostScript file used by Ghostscript for PDF/A conversion
|
||||
- ``optimize.pdf`` - the PDF generated before optimization
|
||||
- ``optimize.out.pdf`` - the PDF generated by optimization
|
||||
- ``origin`` - the input file
|
||||
- ``origin.pdf`` - the input file or the input image converted to PDF
|
||||
- ``images/*`` - images extracted during the optimization process; here
|
||||
the prefix indicates a PDF object ID not a page number
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
======================
|
||||
Using the OCRmyPDF API
|
||||
======================
|
||||
|
||||
OCRmyPDF originated as a command line program and continues to have this
|
||||
legacy, but parts of it can be imported and used in other Python
|
||||
applications.
|
||||
|
||||
Some applications may want to consider running ocrmypdf from a
|
||||
subprocess call anyway, as this provides isolation of its activities.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
OCRmyPDF one high-level function to run its main engine from an
|
||||
application. The parameters are symmetric to the command line arguments
|
||||
and largely have the same functions.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import ocrmypdf
|
||||
|
||||
if __name__ == '__main__': # To ensure correct behavior on Windows and macOS
|
||||
ocrmypdf.ocr('input.pdf', 'output.pdf', deskew=True)
|
||||
|
||||
With a few exceptions, all of the command line arguments are available
|
||||
and may be passed as equivalent keywords.
|
||||
|
||||
A few differences are that ``verbose`` and ``quiet`` are not available.
|
||||
Instead, output should be managed by configuring logging.
|
||||
|
||||
Parent process requirements
|
||||
---------------------------
|
||||
|
||||
The :func:`ocrmypdf.ocr` function runs OCRmyPDF similar to command line
|
||||
execution. To do this, it will:
|
||||
|
||||
- create a monitoring thread
|
||||
- create worker processes (on Linux, forking itself; on Windows and macOS, by
|
||||
spawning)
|
||||
- manage the signal flags of its worker processes
|
||||
- execute other subprocesses (forking and executing other programs)
|
||||
|
||||
The Python process that calls ``ocrmypdf.ocr()`` must be sufficiently
|
||||
privileged to perform these actions.
|
||||
|
||||
There is no currently no option to manage how jobs are scheduled other
|
||||
than the argument ``jobs=`` which will limit the number of worker
|
||||
processes.
|
||||
|
||||
Creating a child process to call ``ocrmypdf.ocr()`` is suggested. That
|
||||
way your application will survive and remain interactive even if
|
||||
OCRmyPDF fails for any reason.
|
||||
|
||||
Programs that call ``ocrmypdf.ocr()`` should also install a SIGBUS signal
|
||||
handler (except on Windows), to raise an exception if access to a memory
|
||||
mapped file fails. OCRmyPDF may use memory mapping.
|
||||
|
||||
``ocrmypdf.ocr()`` will take a threading lock to prevent multiple runs of itself
|
||||
in the same Python interpreter process. This is not thread-safe, because of how
|
||||
OCRmyPDF's plugins and Python's library import system work. If you need to parallelize
|
||||
OCRmyPDF, use processes.
|
||||
|
||||
.. warning::
|
||||
|
||||
On Windows and macOS, the script that calls ``ocrmypdf.ocr()`` must be
|
||||
protected by an "ifmain" guard (``if __name__ == '__main__'``). If you do
|
||||
not take at least one of these steps, process semantics will prevent
|
||||
OCRmyPDF from working correctly.
|
||||
|
||||
Logging
|
||||
-------
|
||||
|
||||
OCRmyPDF will log under loggers named ``ocrmypdf``. In addition, it
|
||||
imports ``pdfminer`` and ``PIL``, both of which post log messages under
|
||||
those logging namespaces.
|
||||
|
||||
You can configure the logging as desired for your application or call
|
||||
:func:`ocrmypdf.configure_logging` to configure logging the same way
|
||||
OCRmyPDF itself does. The command line parameters such as ``--quiet``
|
||||
and ``--verbose`` have no equivalents in the API; you must use the
|
||||
provided configuration function or do configuration in a way that suits
|
||||
your use case.
|
||||
|
||||
Progress monitoring
|
||||
-------------------
|
||||
|
||||
OCRmyPDF uses the ``tqdm`` package to implement its progress bars.
|
||||
:func:`ocrmypdf.configure_logging` will set up logging output to
|
||||
``sys.stderr`` in a way that is compatible with the display of the
|
||||
progress bar. Use ``ocrmypdf.ocr(...progress_bar=False)`` to disable
|
||||
the progress bar.
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
OCRmyPDF may throw standard Python exceptions, ``ocrmypdf.exceptions.*``
|
||||
exceptions, some exceptions related to multiprocessing, and
|
||||
``KeyboardInterrupt``. The parent process should provide an exception
|
||||
handler. OCRmyPDF will clean up its temporary files and worker processes
|
||||
automatically when an exception occurs.
|
||||
|
||||
Programs that call OCRmyPDF should consider trapping KeyboardInterrupt
|
||||
so that they allow OCR to terminate with the whole program terminating.
|
||||
|
||||
When OCRmyPDF succeeds conditionally, it returns an integer exit code.
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. autofunction:: ocrmypdf.ocr
|
||||
|
||||
.. autoclass:: ocrmypdf.Verbosity
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autofunction:: ocrmypdf.configure_logging
|
||||
@@ -0,0 +1,55 @@
|
||||
=============
|
||||
API Reference
|
||||
=============
|
||||
|
||||
This page summarizes the rest of the public API. Generally speaking this
|
||||
should mainly of interest to plugin developers.
|
||||
|
||||
ocrmypdf
|
||||
========
|
||||
|
||||
.. autoclass:: ocrmypdf.PageContext
|
||||
:members:
|
||||
|
||||
.. autoclass:: ocrmypdf.PdfContext
|
||||
:members:
|
||||
|
||||
ocrmypdf.exceptions
|
||||
===================
|
||||
|
||||
.. automodule:: ocrmypdf.exceptions
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
ocrmypdf.helpers
|
||||
================
|
||||
|
||||
.. automodule:: ocrmypdf.helpers
|
||||
:members:
|
||||
:noindex: deprecated
|
||||
|
||||
.. autodecorator:: deprecated
|
||||
|
||||
ocrmypdf.hocrtransform
|
||||
======================
|
||||
|
||||
.. automodule:: ocrmypdf.hocrtransform
|
||||
:members:
|
||||
|
||||
ocrmypdf.pdfa
|
||||
=============
|
||||
|
||||
.. automodule:: ocrmypdf.pdfa
|
||||
:members:
|
||||
|
||||
ocrmypdf.quality
|
||||
================
|
||||
|
||||
.. automodule:: ocrmypdf.quality
|
||||
:members:
|
||||
|
||||
ocrmypdf.subprocess
|
||||
===================
|
||||
|
||||
.. automodule:: ocrmypdf.subprocess
|
||||
:members:
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
================
|
||||
Batch processing
|
||||
================
|
||||
|
||||
This article provides information about running OCRmyPDF on multiple
|
||||
files or configuring it as a service triggered by file system events.
|
||||
|
||||
Batch jobs
|
||||
==========
|
||||
|
||||
Consider using the excellent `GNU
|
||||
Parallel <https://www.gnu.org/software/parallel/>`__ to apply OCRmyPDF
|
||||
to multiple files at once.
|
||||
|
||||
Both ``parallel`` and ``ocrmypdf`` will try to use all available
|
||||
processors. To maximize parallelism without overloading your system with
|
||||
processes, consider using ``parallel -j 2`` to limit parallel to running
|
||||
two jobs at once.
|
||||
|
||||
This command will run all ocrmypdf all files named ``*.pdf`` in the
|
||||
current directory and write them to the previous created ``output/``
|
||||
folder. It will not search subdirectories.
|
||||
|
||||
The ``--tag`` argument tells parallel to print the filename as a prefix
|
||||
whenever a message is printed, so that one can trace any errors to the
|
||||
file that produced them.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
parallel --tag -j 2 ocrmypdf '{}' 'output/{}' ::: *.pdf
|
||||
|
||||
OCRmyPDF automatically repairs PDFs before parsing and gathering
|
||||
information from them.
|
||||
|
||||
Directory trees
|
||||
===============
|
||||
|
||||
This will walk through a directory tree and run OCR on all files in
|
||||
place, printing the output in a way that makes
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
find . -printf '%p' -name '*.pdf' -exec ocrmypdf '{}' '{}' \;
|
||||
|
||||
Alternatively, with a docker container (mounts a volume to the container
|
||||
where the PDFs are stored):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
find . -printf '%p' -name '*.pdf' -exec docker run --rm -v <host dir>:<container dir> jbarlow83/ocrmypdf '<container dir>/{}' '<container dir>/{}' \;
|
||||
|
||||
This only runs one ``ocrmypdf`` process at a time. This variation uses
|
||||
``find`` to create a directory list and ``parallel`` to parallelize runs
|
||||
of ``ocrmypdf``, again updating files in place.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
find . -name '*.pdf' | parallel --tag -j 2 ocrmypdf '{}' '{}'
|
||||
|
||||
In a Windows batch file, use
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
for /r %%f in (*.pdf) do ocrmypdf %%f %%f
|
||||
|
||||
Sample script
|
||||
-------------
|
||||
|
||||
This user contributed script also provides an example of batch
|
||||
processing.
|
||||
|
||||
.. literalinclude:: ../misc/batch.py
|
||||
:caption: misc/batch.py
|
||||
|
||||
Synology DiskStations
|
||||
---------------------
|
||||
|
||||
Synology DiskStations (Network Attached Storage devices) can run the
|
||||
Docker image of OCRmyPDF if the Synology `Docker
|
||||
package <https://www.synology.com/en-global/dsm/packages/Docker>`__ is
|
||||
installed. Attached is a script to address particular quirks of using
|
||||
OCRmyPDF on one of these devices.
|
||||
|
||||
This is only possible for x86-based Synology products. Some Synology
|
||||
products use ARM or Power processors and do not support Docker. Further
|
||||
adjustments might be needed to deal with the Synology's relatively
|
||||
limited CPU and RAM.
|
||||
|
||||
.. literalinclude:: ../misc/synology.py
|
||||
:caption: misc/synology.py - Sample script for Synology DiskStations
|
||||
|
||||
Huge batch jobs
|
||||
---------------
|
||||
|
||||
If you have thousands of files to work with, contact the author.
|
||||
Consulting work related to OCRmyPDF helps fund this open source project
|
||||
and all inquiries are appreciated.
|
||||
|
||||
Hot (watched) folders
|
||||
=====================
|
||||
|
||||
Watched folders with watcher.py
|
||||
-------------------------------
|
||||
|
||||
OCRmyPDF has a folder watcher called watcher.py, which is currently included in source
|
||||
distributions but not part of the main program. It may be used natively or may run
|
||||
in a Docker container. Native instances tend to give better performance. watcher.py
|
||||
works on all platforms.
|
||||
|
||||
Users may need to customize the script to meet their requirements.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install -r requirements/watcher.txt
|
||||
|
||||
env OCR_INPUT_DIRECTORY=/mnt/input-pdfs \
|
||||
OCR_OUTPUT_DIRECTORY=/mnt/output-pdfs \
|
||||
OCR_OUTPUT_DIRECTORY_YEAR_MONTH=1 \
|
||||
python3 watcher.py
|
||||
|
||||
.. csv-table:: watcher.py environment variables
|
||||
:header: "Environment variable", "Description"
|
||||
:widths: 50, 50
|
||||
|
||||
"OCR_INPUT_DIRECTORY", "Set input directory to monitor (recursive)"
|
||||
"OCR_OUTPUT_DIRECTORY", "Set output directory (should not be under input)"
|
||||
"OCR_ON_SUCCESS_DELETE", "This will delete the input file if the exit code is 0 (OK)"
|
||||
"OCR_OUTPUT_DIRECTORY_YEAR_MONTH", "This will place files in the output in ``{output}/{year}/{month}/{filename}``"
|
||||
"OCR_DESKEW", "Apply deskew to crooked input PDFs"
|
||||
"OCR_JSON_SETTINGS", "A JSON string specifying any other arguments for ``ocrmypdf.ocr``, e.g. ``'OCR_JSON_SETTINGS={""rotate_pages"": true}'``."
|
||||
"OCR_POLL_NEW_FILE_SECONDS", "Polling interval"
|
||||
"OCR_LOGLEVEL", "Level of log messages to report"
|
||||
|
||||
One could configure a networked scanner or scanning computer to drop files in the
|
||||
watched folder.
|
||||
|
||||
Watched folders with Docker
|
||||
---------------------------
|
||||
|
||||
The watcher service is included in the OCRmyPDF Docker image. To run it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run \
|
||||
-v <path to files to convert>:/input \
|
||||
-v <path to store results>:/output \
|
||||
-e OCR_OUTPUT_DIRECTORY_YEAR_MONTH=1 \
|
||||
-e OCR_ON_SUCCESS_DELETE=1 \
|
||||
-e OCR_DESKEW=1 \
|
||||
-e PYTHONUNBUFFERED=1 \
|
||||
-it --entrypoint python3 \
|
||||
jbarlow83/ocrmypdf \
|
||||
watcher.py
|
||||
|
||||
This service will watch for a file that matches ``/input/\*.pdf`` and will
|
||||
convert it to a OCRed PDF in ``/output/``. The parameters to this image are:
|
||||
|
||||
.. csv-table:: watcher.py parameters for Docker
|
||||
:header: "Parameter", "Description"
|
||||
:widths: 50, 50
|
||||
|
||||
"``-v <path to files to convert>:/input``", "Files placed in this location will be OCRed"
|
||||
"``-v <path to store results>:/output``", "This is where OCRed files will be stored"
|
||||
"``-e OCR_OUTPUT_DIRECTORY_YEAR_MONTH=1``", "Define environment variable OCR_OUTPUT_DIRECTORY_YEAR_MONTH=1"
|
||||
"``-e OCR_ON_SUCCESS_DELETE=1``", "Define environment variable"
|
||||
"``-e OCR_DESKEW=1``", "Define environment variable"
|
||||
"``-e PYTHONBUFFERED=1``", "This will force STDOUT to be unbuffered and allow you to see messages in docker logs"
|
||||
|
||||
This service relies on polling to check for changes to the filesystem. It
|
||||
may not be suitable for some environments, such as filesystems shared on a
|
||||
slow network.
|
||||
|
||||
A configuration manager such as Docker Compose could be used to ensure that the
|
||||
service is always available.
|
||||
|
||||
.. literalinclude:: ../misc/docker-compose.example.yml
|
||||
:language: yaml
|
||||
:caption: misc/docker-compose.example.yml
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
- ``watchmedo`` may not work properly on a networked file system,
|
||||
depending on the capabilities of the file system client and server.
|
||||
- This simple recipe does not filter for the type of file system event,
|
||||
so file copies, deletes and moves, and directory operations, will all
|
||||
be sent to ocrmypdf, producing errors in several cases. Disable your
|
||||
watched folder if you are doing anything other than copying files to
|
||||
it.
|
||||
- If the source and destination directory are the same, watchmedo may
|
||||
create an infinite loop.
|
||||
- On BSD, FreeBSD and older versions of macOS, you may need to increase
|
||||
the number of file descriptors to monitor more files, using
|
||||
``ulimit -n 1024`` to watch a folder of up to 1024 files.
|
||||
|
||||
Alternatives
|
||||
------------
|
||||
|
||||
- On Linux, `systemd user services <https://wiki.archlinux.org/index.php/Systemd/User>`__
|
||||
can be configured to automatically perform OCR on a collection of files.
|
||||
|
||||
- `Watchman <https://facebook.github.io/watchman/>`__ is a more
|
||||
powerful alternative to ``watchmedo``.
|
||||
|
||||
macOS Automator
|
||||
===============
|
||||
|
||||
You can use the Automator app with macOS, to create a Workflow or Quick
|
||||
Action. Use a *Run Shell Script* action in your workflow. In the context
|
||||
of Automator, the ``PATH`` may be set differently your Terminal's
|
||||
``PATH``; you may need to explicitly set the PATH to include
|
||||
``ocrmypdf``. The following example may serve as a starting point:
|
||||
|
||||
.. figure:: images/macos-workflow.png
|
||||
:alt: Example macOS Automator workflow
|
||||
|
||||
You may customize the command sent to ocrmypdf.
|
||||
Executable
+373
@@ -0,0 +1,373 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# ocrmypdf documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Sep 4 14:29:43 2016.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
"""isort:skip_file"""
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.napoleon']
|
||||
|
||||
napoleon_use_rtype = False
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#
|
||||
# source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'ocrmypdf'
|
||||
copyright = (
|
||||
'2020, James R. Barlow. Licensed under Creative Commons Attribution-ShareAlike 4.0.'
|
||||
)
|
||||
author = 'James R. Barlow'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
|
||||
import os
|
||||
|
||||
on_rtd = os.environ.get('READTHEDOCS') == 'True'
|
||||
|
||||
if on_rtd:
|
||||
# Help ReadTheDocs avoid having to install any binary extension modules
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
class Mock(MagicMock):
|
||||
@classmethod
|
||||
def __getattr__(cls, name):
|
||||
return MagicMock()
|
||||
|
||||
MOCK_MODULES = [
|
||||
'pikepdf',
|
||||
'pikepdf.models',
|
||||
'pikepdf.models.metadata',
|
||||
'ocrmypdf.leptonica',
|
||||
]
|
||||
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)
|
||||
|
||||
|
||||
from pkg_resources import get_distribution, DistributionNotFound
|
||||
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = get_distribution('ocrmypdf').version
|
||||
version = '.'.join(release.split('.')[:2])
|
||||
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#
|
||||
# today = ''
|
||||
#
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#
|
||||
today_fmt = '%Y-%m-%d'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#
|
||||
# add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#
|
||||
# add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#
|
||||
# show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
# keep_warnings = False
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
import sphinx_rtd_theme
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
html_theme_options = {'display_version': False}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents.
|
||||
# "<project> v<release> documentation" by default.
|
||||
#
|
||||
# html_title = 'ocrmypdf v4.2'
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#
|
||||
# html_logo = "images/logo.svg" # looks bad
|
||||
|
||||
# The name of an image file (relative to this directory) to use as a favicon of
|
||||
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#
|
||||
# html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#
|
||||
# html_extra_path = []
|
||||
|
||||
# If not None, a 'Last updated on:' timestamp is inserted at every page
|
||||
# bottom, using the given strftime format.
|
||||
# The empty string is equivalent to '%b %d, %Y'.
|
||||
#
|
||||
# html_last_updated_fmt = None
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#
|
||||
# html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#
|
||||
# html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#
|
||||
# html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#
|
||||
# html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
# html_file_suffix = None
|
||||
|
||||
# Language to be used for generating the HTML full-text search index.
|
||||
# Sphinx supports the following languages:
|
||||
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
|
||||
# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh'
|
||||
#
|
||||
# html_search_language = 'en'
|
||||
|
||||
# A dictionary with options for the search language support, empty by default.
|
||||
# 'ja' uses this config value.
|
||||
# 'zh' user can custom change `jieba` dictionary path.
|
||||
#
|
||||
# html_search_options = {'type': 'default'}
|
||||
|
||||
# The name of a javascript file (relative to the configuration directory) that
|
||||
# implements a search results scorer. If empty, the default will be used.
|
||||
#
|
||||
# html_search_scorer = 'scorer.js'
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'ocrmypdfdoc'
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'ocrmypdf.tex', 'ocrmypdf Documentation', 'James R. Barlow', 'manual')
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#
|
||||
# latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#
|
||||
# latex_appendices = []
|
||||
|
||||
# It false, will not define \strong, \code, itleref, \crossref ... but only
|
||||
# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
|
||||
# packages.
|
||||
#
|
||||
# latex_keep_old_macro_names = True
|
||||
|
||||
# If false, no module index is generated.
|
||||
#
|
||||
# latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [(master_doc, 'ocrmypdf', 'ocrmypdf Documentation', [author], 1)]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(
|
||||
master_doc,
|
||||
'ocrmypdf',
|
||||
'ocrmypdf Documentation',
|
||||
author,
|
||||
'ocrmypdf',
|
||||
'One line description of project.',
|
||||
'Miscellaneous',
|
||||
)
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#
|
||||
# texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#
|
||||
# texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#
|
||||
# texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#
|
||||
# texinfo_no_detailmenu = False
|
||||
@@ -0,0 +1,67 @@
|
||||
=======================
|
||||
Contributing guidelines
|
||||
=======================
|
||||
|
||||
Contributions are welcome!
|
||||
|
||||
Big changes
|
||||
===========
|
||||
|
||||
Please open a new issue to discuss or propose a major change. Not only is it fun
|
||||
to discuss big ideas, but we might save each other's time too. Perhaps some of the
|
||||
work you're contemplating is already half-done in a development branch.
|
||||
|
||||
Code style
|
||||
==========
|
||||
|
||||
We use PEP8, ``black`` for code formatting and ``isort`` for import sorting. The
|
||||
settings for these programs are in ``pyproject.toml`` and ``setup.cfg``. Pull
|
||||
requests should follow the style guide. One difference we use from "black" style
|
||||
is that strings shown to the user are always in double quotes (``"``) and strings
|
||||
for internal uses are in single quotes (``'``).
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
New features should come with tests that confirm their correctness.
|
||||
|
||||
New Python dependencies
|
||||
=======================
|
||||
|
||||
If you are proposing a change that will require a new Python dependency, we
|
||||
prefer dependencies that are already packaged by Debian or Red Hat. This makes
|
||||
life much easier for our downstream package maintainers.
|
||||
|
||||
Python dependencies must also be license-compatible. GPLv3 or AGPLv3 are likely
|
||||
incompatible with the project's license, but LGPLv3 is compatible.
|
||||
|
||||
New non-Python dependencies
|
||||
===========================
|
||||
|
||||
OCRmyPDF uses several external programs (Tesseract, Ghostscript and others) for
|
||||
its functionality. In general we prefer to avoid adding new external programs.
|
||||
|
||||
Style guide: Is it OCRmyPDF or ocrmypdf?
|
||||
========================================
|
||||
|
||||
The program/project is OCRmyPDF and the name of the executable or library is ocrmypdf.
|
||||
|
||||
Known ports/packagers
|
||||
=====================
|
||||
|
||||
OCRmyPDF has been ported to many platforms already. If you are interesting in
|
||||
porting to a new platform, check with
|
||||
`Repology <https://repology.org/projects/?search=ocrmypdf>`__ to see the status
|
||||
of that platform.
|
||||
|
||||
Packager maintainers, please ensure that the command line completion scripts in
|
||||
``misc/`` are installed.
|
||||
|
||||
Copyright and license
|
||||
=====================
|
||||
|
||||
For contributions over 10 lines of code, please include your name to list of
|
||||
copyright holders for that file. The core program is licensed under MPL-2.0,
|
||||
test files and documentation under CC-BY-SA 4.0, and miscellaneous files under
|
||||
MIT. Please contribute code only that you wrote and you have the permission to
|
||||
contribute or license to us.
|
||||
@@ -0,0 +1,359 @@
|
||||
========
|
||||
Cookbook
|
||||
========
|
||||
|
||||
Basic examples
|
||||
==============
|
||||
|
||||
Help!
|
||||
-----
|
||||
|
||||
ocrmypdf has built-in help.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --help
|
||||
|
||||
Add an OCR layer and convert to PDF/A
|
||||
-------------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf input.pdf output.pdf
|
||||
|
||||
Add an OCR layer and output a standard PDF
|
||||
------------------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --output-type pdf input.pdf output.pdf
|
||||
|
||||
Create a PDF/A with all color and grayscale images converted to JPEG
|
||||
--------------------------------------------------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --output-type pdfa --pdfa-image-compression jpeg input.pdf output.pdf
|
||||
|
||||
Modify a file in place
|
||||
----------------------
|
||||
|
||||
The file will only be overwritten if OCRmyPDF is successful.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf myfile.pdf myfile.pdf
|
||||
|
||||
Correct page rotation
|
||||
---------------------
|
||||
|
||||
OCR will attempt to automatic correct the rotation of each page. This
|
||||
can help fix a scanning job that contains a mix of landscape and
|
||||
portrait pages.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --rotate-pages myfile.pdf myfile.pdf
|
||||
|
||||
You can increase (decrease) the parameter ``--rotate-pages-threshold``
|
||||
to make page rotation more (less) aggressive. The threshold number is the ratio
|
||||
of how confidence the OCR engine is that the document image should be changed,
|
||||
compared to kept the same. A value of ``15.0`` is the default, and is fairly
|
||||
conservative. A value of ``2.0`` will produce more rotations, and more false
|
||||
positives.
|
||||
|
||||
If the page is "just a little off horizontal", like a crooked picture,
|
||||
then you want ``--deskew``. ``--rotate-pages`` is for when the cardinal
|
||||
angle is wrong.
|
||||
|
||||
OCR languages other than English
|
||||
--------------------------------
|
||||
|
||||
OCRmyPDF assumes the document is in English unless told otherwise. OCR
|
||||
quality may be poor if the wrong language is used.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf -l fra LeParisien.pdf LeParisien.pdf
|
||||
ocrmypdf -l eng+fra Bilingual-English-French.pdf Bilingual-English-French.pdf
|
||||
|
||||
Language packs must be installed for all languages specified. See
|
||||
:ref:`Installing additional language packs <lang-packs>`.
|
||||
|
||||
Unfortunately, the Tesseract OCR engine has no ability to detect the
|
||||
language when it is unknown.
|
||||
|
||||
Produce PDF and text file containing OCR text
|
||||
---------------------------------------------
|
||||
|
||||
This produces a file named "output.pdf" and a companion text file named
|
||||
"output.txt".
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --sidecar output.txt input.pdf output.pdf
|
||||
|
||||
.. note::
|
||||
|
||||
The sidecar file contains the **OCR text** found by OCRmyPDF. If the document
|
||||
contains pages that already have text, that text will not appear in the
|
||||
sidecar. If the option ``--pages`` is used, only those pages on which OCR
|
||||
was performed will be included in the sidecar. If certain pages were skipped
|
||||
because of options like ``--skip-big`` or ``--tesseract-timeout``, those pages
|
||||
will not be in the sidecar.
|
||||
|
||||
To extract all text from a PDF, whether generated from OCR or otherwise,
|
||||
use a program like Poppler's ``pdftotext`` or ``pdfgrep``.
|
||||
|
||||
OCR images, not PDFs
|
||||
--------------------
|
||||
|
||||
Option: use Tesseract
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you are starting with images, you can just use Tesseract directly to
|
||||
convert images to PDFs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tesseract my-image.jpg output-prefix pdf
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# When there are multiple images
|
||||
tesseract text-file-containing-list-of-image-filenames.txt output-prefix pdf
|
||||
|
||||
Tesseract's PDF output is quite good – OCRmyPDF uses it internally, in
|
||||
some cases. However, OCRmyPDF has many features not available in
|
||||
Tesseract like image processing, metadata control, and PDF/A generation.
|
||||
|
||||
Option: use img2pdf
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can also use a program like
|
||||
`img2pdf <https://gitlab.mister-muffin.de/josch/img2pdf>`__ to convert
|
||||
your images to PDFs, and then pipe the results to run ocrmypdf. The
|
||||
``-`` tells ocrmypdf to read standard input.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
img2pdf my-images*.jpg | ocrmypdf - myfile.pdf
|
||||
|
||||
``img2pdf`` is recommended because it does an excellent job at
|
||||
generating PDFs without transcoding images.
|
||||
|
||||
Option: use OCRmyPDF (single images only)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For convenience, OCRmyPDF can also convert single images to PDFs on its
|
||||
own. If the resolution (dots per inch, DPI) of an image is not set or is
|
||||
incorrect, it can be overridden with ``--image-dpi``. (As 1 inch is 2.54
|
||||
cm, 1 dpi = 0.39 dpcm).
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --image-dpi 300 image.png myfile.pdf
|
||||
|
||||
If you have multiple images, you must use ``img2pdf`` to convert the
|
||||
images to PDF.
|
||||
|
||||
Not recommended
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
We caution against using ImageMagick or Ghostscript to convert images to
|
||||
PDF, since they may transcode images or produce downsampled images,
|
||||
sometimes without warning.
|
||||
|
||||
Image processing
|
||||
================
|
||||
|
||||
OCRmyPDF perform some image processing on each page of a PDF, if
|
||||
desired. The same processing is applied to each page. It is suggested
|
||||
that the user review files after image processing as these commands
|
||||
might remove desirable content, especially from poor quality scans.
|
||||
|
||||
- ``--rotate-pages`` attempts to determine the correct orientation for
|
||||
each page and rotates the page if necessary.
|
||||
- ``--remove-background`` attempts to detect and remove a noisy
|
||||
background from grayscale or color images. Monochrome images are
|
||||
ignored. This should not be used on documents that contain color
|
||||
photos as it may remove them.
|
||||
- ``--deskew`` will correct pages were scanned at a skewed angle by
|
||||
rotating them back into place. Skew determination and correction is
|
||||
performed using `Postl's variance of line
|
||||
sums <http://www.leptonica.org/skew-measurement.html>`__ algorithm as
|
||||
implemented in `Leptonica <http://www.leptonica.org/index.html>`__.
|
||||
- ``--clean`` uses
|
||||
`unpaper <https://www.flameeyes.eu/projects/unpaper>`__ to clean up
|
||||
pages before OCR, but does not alter the final output. This makes it
|
||||
less likely that OCR will try to find text in background noise.
|
||||
- ``--clean-final`` uses unpaper to clean up pages before OCR and
|
||||
inserts the page into the final output. You will want to review each
|
||||
page to ensure that unpaper did not remove something important.
|
||||
|
||||
.. note::
|
||||
|
||||
In many cases image processing will rasterize PDF pages as images,
|
||||
potentially losing quality.
|
||||
|
||||
.. warning::
|
||||
|
||||
``--clean-final`` and ``-remove-background`` may leave undesirable
|
||||
visual artifacts in some images where their algorithms have
|
||||
shortcomings. Files should be visually reviewed after using these
|
||||
options.
|
||||
|
||||
Example: OCR and correct document skew (crooked scan)
|
||||
-----------------------------------------------------
|
||||
|
||||
Deskew:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --deskew input.pdf output.pdf
|
||||
|
||||
Image processing commands can be combined. The order in which options
|
||||
are given does not matter. OCRmyPDF always applies the steps of the
|
||||
image processing pipeline in the same order (rotate, remove background,
|
||||
deskew, clean).
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --deskew --clean --rotate-pages input.pdf output.pdf
|
||||
|
||||
Don't actually OCR my PDF
|
||||
=========================
|
||||
|
||||
If you set ``--tesseract-timeout 0`` OCRmyPDF will apply its image
|
||||
processing without performing OCR, if all you want to is to apply image
|
||||
processing or PDF/A conversion.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --tesseract-timeout=0 --remove-background input.pdf output.pdf
|
||||
|
||||
Optimize images without performing OCR
|
||||
--------------------------------------
|
||||
|
||||
You can also optimize all images without performing any OCR:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --tesseract-timeout=0 --optimize 3 --skip-text input.pdf output.pdf
|
||||
|
||||
Perform OCR only certain pages
|
||||
------------------------------
|
||||
|
||||
You can ask OCRmyPDF to only apply OCR to certain pages.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --pages 2,3,13-17 input.pdf output.pdf
|
||||
|
||||
Hyphens denote a range of pages and commas separate page numbers. If you prefer
|
||||
to use spaces, quote all of the page numbers: ``--pages '2, 3, 5, 7'``.
|
||||
|
||||
OCRmyPDF will warn if your list of page numbers contains duplicates or
|
||||
overlap pages. OCRmyPDF does not currently account for document page numbers,
|
||||
such as an introduction section of a book that uses Roman numerals. It simply
|
||||
counts the number of virtual pieces of paper since the start.
|
||||
|
||||
Regardless of the argument to ``--pages``, OCRmyPDF will optimize all pages in
|
||||
the file and convert it to PDF/A, unless you disable those options. In this
|
||||
example, we want to OCR only the title and otherwise change the PDF as little
|
||||
as possible:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --pages 1 --output-type pdf --optimize 0 input.pdf output.pdf
|
||||
|
||||
Redo existing OCR
|
||||
=================
|
||||
|
||||
To redo OCR on a file OCRed with other OCR software or a previous
|
||||
version of OCRmyPDF and/or Tesseract, you may use the ``--redo-ocr``
|
||||
argument. (Normally, OCRmyPDF will exit with an error if asked to modify
|
||||
a file with OCR.)
|
||||
|
||||
This may be helpful for users who want to take advantage of accuracy
|
||||
improvements in Tesseract 4.0 for files they previously OCRed with an
|
||||
earlier version of Tesseract and OCRmyPDF.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --redo-ocr input.pdf output.pdf
|
||||
|
||||
This method will replace OCR without rasterizing, reducing quality or
|
||||
removing vector content. If a file contains a mix of pure digital text
|
||||
and OCR, digital text will be ignored and OCR will be replaced. As such
|
||||
this mode is incompatible with image processing options, since they
|
||||
alter the appearance of the file.
|
||||
|
||||
In some cases, existing OCR cannot be detected or replaced. Files
|
||||
produced by OCRmyPDF v2.2 or earlier, for example, are internally
|
||||
represented as having visible text with an opaque image drawn on top.
|
||||
This situation cannot be detected.
|
||||
|
||||
If ``--redo-ocr`` does not work, you can use ``--force-ocr``, which will
|
||||
force rasterization of all pages, potentially reducing quality or losing
|
||||
vector content.
|
||||
|
||||
Improving OCR quality
|
||||
=====================
|
||||
|
||||
The `Image processing <#image-processing>`__ features can improve OCR
|
||||
quality.
|
||||
|
||||
Rotating pages and deskewing helps to ensure that the page orientation
|
||||
is correct before OCR begins. Removing the background and/or cleaning
|
||||
the page can also improve results. The ``--oversample DPI`` argument can
|
||||
be specified to resample images to higher resolution before attempting
|
||||
OCR; this can improve results as well.
|
||||
|
||||
OCR quality will suffer if the resolution of input images is not correct
|
||||
(since the range of pixel sizes that will be checked for possible fonts
|
||||
will also be incorrect).
|
||||
|
||||
PDF optimization
|
||||
================
|
||||
|
||||
By default OCRmyPDF will attempt to perform lossless optimizations on
|
||||
the images inside PDFs after OCR is complete. Optimization is performed
|
||||
even if no OCR text is found.
|
||||
|
||||
The ``--optimize N`` (short form ``-O``) argument controls optimization,
|
||||
where ``N`` ranges from 0 to 3 inclusive, analogous to the optimization
|
||||
levels in the GCC compiler.
|
||||
|
||||
.. list-table::
|
||||
:widths: auto
|
||||
:header-rows: 1
|
||||
|
||||
* - Level
|
||||
- Comments
|
||||
* - ``--optimize 0``
|
||||
- Disables optimization.
|
||||
* - ``--optimize 1``
|
||||
- Enables lossless optimizations, such as transcoding images to more
|
||||
efficient formats. Also compress other uncompressed objects in the
|
||||
PDF and enables the more efficient "object streams" within the PDF.
|
||||
* - ``--optimize 2``
|
||||
- All of the above, and enables lossy optimizations and color quantization.
|
||||
* - ``--optimize 3``
|
||||
- All of the above, and enables more aggressive optimizations and targets lower image quality.
|
||||
|
||||
Optimization is improved when a JBIG2 encoder is available and when
|
||||
``pngquant`` is installed. If either of these components are missing,
|
||||
then some types of images cannot be optimized.
|
||||
|
||||
The types of optimization available may expand over time. By default,
|
||||
OCRmyPDF compresses data streams inside PDFs, and will change
|
||||
inefficient compression modes to more modern versions. A program like
|
||||
``qpdf`` can be used to change encodings, e.g. to inspect the internals
|
||||
fo a PDF.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --optimize 3 in.pdf out.pdf # Make it small
|
||||
|
||||
Some users may consider enabling lossy JBIG2. See: :ref:`jbig2-lossy`.
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
.. _docker:
|
||||
|
||||
=====================
|
||||
OCRmyPDF Docker image
|
||||
=====================
|
||||
|
||||
OCRmyPDF is also available in a Docker image that packages recent
|
||||
versions of all dependencies.
|
||||
|
||||
For users who already have Docker installed this may be an easy and
|
||||
convenient option. However, it is less performant than a system
|
||||
installation and may require Docker engine configuration.
|
||||
|
||||
OCRmyPDF needs a generous amount of RAM, CPU cores, temporary storage
|
||||
space, whether running in a Docker container or on its own. It may be
|
||||
necessary to ensure the container is provisioned with additional
|
||||
resources.
|
||||
|
||||
.. _docker-install:
|
||||
|
||||
Installing the Docker image
|
||||
===========================
|
||||
|
||||
If you have `Docker <https://docs.docker.com/>`__ installed on your
|
||||
system, you can install a Docker image of the latest release.
|
||||
|
||||
If you can run this command successfully, your system is ready to download and
|
||||
execute the image:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run hello-world
|
||||
|
||||
The recommended OCRmyPDF Docker image is currently named ``ocrmypdf``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker pull jbarlow83/ocrmypdf
|
||||
|
||||
|
||||
OCRmyPDF will use all available CPU cores. By default, the VirtualBox
|
||||
machine instance on Windows and macOS has only a single CPU core
|
||||
enabled. Use the VirtualBox Manager to determine the name of your Docker
|
||||
engine host, and then follow these optional steps to enable multiple
|
||||
CPUs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Optional step for Mac OS X users
|
||||
docker-machine stop "yourVM"
|
||||
VBoxManage modifyvm "yourVM" --cpus 2 # or whatever number of core is desired
|
||||
docker-machine start "yourVM"
|
||||
eval $(docker-machine env "yourVM")
|
||||
|
||||
See the Docker documentation for
|
||||
`adjusting memory and CPU on other platforms <https://docs.docker.com/config/containers/resource_constraints/>`__.
|
||||
|
||||
Using the Docker image on the command line
|
||||
==========================================
|
||||
|
||||
**Unlike typical Docker containers**, in this section the OCRmyPDF Docker
|
||||
container is emphemeral – it runs for one OCR job and terminates, just like a
|
||||
command line program. We are using Docker to deliver an application (as opposed
|
||||
to the more conventional case, where a Docker container runs as a server).
|
||||
|
||||
To start a Docker container (instance of the image):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker tag jbarlow83/ocrmypdf ocrmypdf
|
||||
docker run --rm -i ocrmypdf (... all other arguments here...) - -
|
||||
|
||||
For convenience, create a shell alias to hide the Docker command. It is
|
||||
easier to send the input file as stdin and read the output from
|
||||
stdout – **this avoids the messy permission issues with Docker entirely**.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
alias docker_ocrmypdf='docker run --rm -i ocrmypdf'
|
||||
docker_ocrmypdf --version # runs docker version
|
||||
docker_ocrmypdf - - <input.pdf >output.pdf
|
||||
|
||||
Or in the wonderful `fish shell <https://fishshell.com/>`__:
|
||||
|
||||
.. code-block:: fish
|
||||
|
||||
alias docker_ocrmypdf 'docker run --rm ocrmypdf'
|
||||
funcsave docker_ocrmypdf
|
||||
|
||||
Alternately, you could mount the local current working directory as a
|
||||
Docker volume:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
alias docker_ocrmypdf='docker run --rm -i --user "$(id -u):$(id -g)" --workdir /data -v "$PWD:/data" ocrmypdf'
|
||||
docker_ocrmypdf /data/input.pdf /data/output.pdf
|
||||
|
||||
.. _docker-lang-packs:
|
||||
|
||||
Adding languages to the Docker image
|
||||
====================================
|
||||
|
||||
By default the Docker image includes English, German, Simplified Chinese,
|
||||
French, Portuguese and Spanish, the most popular languages for OCRmyPDF
|
||||
users based on feedback. You may add other languages by creating a new
|
||||
Dockerfile based on the public one:
|
||||
|
||||
.. code-block:: dockerfile
|
||||
|
||||
FROM jbarlow83/ocrmypdf
|
||||
|
||||
# Add French
|
||||
RUN apt install tesseract-ocr-fra
|
||||
|
||||
You can also copy training data to ``/usr/share/tesseract-ocr/<tesseract version>/tessdata``.
|
||||
|
||||
Executing the test suite
|
||||
========================
|
||||
|
||||
The OCRmyPDF test suite is installed with image. To run it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run --entrypoint python3 jbarlow83/ocrmypdf -m pytest
|
||||
|
||||
Accessing the shell
|
||||
===================
|
||||
|
||||
To use the bash shell in the Docker image:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -it --entrypoint bash jbarlow83/ocrmypdf
|
||||
|
||||
Using the OCRmyPDF web service wrapper
|
||||
======================================
|
||||
|
||||
The OCRmyPDF Docker image includes an example, barebones HTTP web
|
||||
service. The webservice may be launched as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run --entrypoint python3 -p 5000:5000 jbarlow83/ocrmypdf webservice.py
|
||||
|
||||
This will configure the machine to listen on port 5000. On Linux machines
|
||||
this is port 5000 of localhost. On macOS or Windows machines running
|
||||
Docker, this is port 5000 of the virtual machine that runs your Docker
|
||||
images. You can find its IP address using the command ``docker-machine ip``.
|
||||
|
||||
Unlike command line usage this program will open a socket and wait for
|
||||
connections.
|
||||
|
||||
.. warning::
|
||||
|
||||
The OCRmyPDF web service wrapper is intended for demonstration or
|
||||
development. It provides no security, no authentication, no
|
||||
protection against denial of service attacks, and no load balancing.
|
||||
The default Flask WSGI server is used, which is intended for
|
||||
development only. The server is single-threaded and so can respond to
|
||||
only one client at a time. While running OCR, it cannot respond to
|
||||
any other clients.
|
||||
|
||||
Clients must keep their open connection while waiting for OCR to
|
||||
complete. This may entail setting a long timeout; this interface is more
|
||||
useful for internal HTTP API calls.
|
||||
|
||||
Unlike the rest of OCRmyPDF, this web service is licensed under the
|
||||
Affero GPLv3 (AGPLv3) since Ghostscript is also licensed in this way.
|
||||
|
||||
In addition to the above, please read our
|
||||
:ref:`general remarks on using OCRmyPDF as a service <ocr-service>`.
|
||||
@@ -0,0 +1,53 @@
|
||||
=====================
|
||||
Common error messages
|
||||
=====================
|
||||
|
||||
Page already has text
|
||||
=====================
|
||||
|
||||
.. code-block::
|
||||
|
||||
ERROR - 1: page already has text! – aborting (use --force-ocr to force OCR)
|
||||
|
||||
You ran ocrmypdf on a file that already contains printable text or a
|
||||
hidden OCR text layer (it can't quite tell the difference). You probably
|
||||
don't want to do this, because the file is already searchable.
|
||||
|
||||
As the error message suggests, your options are:
|
||||
|
||||
- ``ocrmypdf --force-ocr`` to :ref:`rasterize <raster-vector>` all
|
||||
vector content and run OCR on the images. This is useful if a
|
||||
previous OCR program failed, or if the document contains a text
|
||||
watermark.
|
||||
- ``ocrmypdf --skip-text`` to skip OCR and other processing on any
|
||||
pages that contain text. Text pages will be copied into the output
|
||||
PDF without modification.
|
||||
- ``ocrmypdf --redo-ocr`` to scan the file for any existing OCR
|
||||
(non-printing text), remove it, and do OCR again. This is one way
|
||||
to take advantage of improvements in OCR accuracy. Printable vector
|
||||
text is excluded from OCR, so this can be used on files that contain
|
||||
a mix of digital and scanned files.
|
||||
|
||||
|
||||
Input file 'filename' is not a valid PDF
|
||||
========================================
|
||||
|
||||
OCRmyPDF checks files with pikepdf, a library that in turn uses libqpdf to fixes
|
||||
errors in PDFs, before it tries to work on them. In most cases this happens
|
||||
because the PDF is corrupt and truncated (incomplete file copying) and not much
|
||||
can be done.
|
||||
|
||||
You can try rewriting the file with Ghostscript:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
gs -o output.pdf -dSAFER -sDEVICE=pdfwrite input.pdf
|
||||
|
||||
``pdftk`` can also rewrite PDFs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pdftk input.pdf cat output output.pdf
|
||||
|
||||
Sometimes Acrobat can repair PDFs with its `Preflight
|
||||
tool <https://helpx.adobe.com/acrobat/using/correcting-problem-areas-preflight-tool.html>`__.
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 915 585" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="b" y2="445" gradientUnits="userSpaceOnUse" y1="179" gradientTransform="translate(0 -2.06)" x2="-29.7" x1="322">
|
||||
<stop stop-color="#333" offset="0"/>
|
||||
<stop stop-color="#fff" stop-opacity="0" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="a" y2="414" gradientUnits="userSpaceOnUse" y1="159" x2="490" x1="815">
|
||||
<stop stop-color="#33f" offset="0"/>
|
||||
<stop stop-color="#3f3fff" stop-opacity="0" offset="1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#b)" d="m403 247c-12 115-135 122-368 123-4.3-1.07-7.32-7.33-6-41 76-37 151-124 167-236 93 123 201 40.9 207 154z"/>
|
||||
<g stroke-width="3.45" fill="none">
|
||||
<path stroke="#000" d="m11.8 11.8h411v411l-411 0.01v-411z"/>
|
||||
<path stroke="#448" d="m489 11.7h415v411h-415v-411z"/>
|
||||
</g>
|
||||
<path d="m876 244c-12 115-133 120-366 121-6-14-10-40-3-43 76-37.3 136-106 152-218 38 48 209 101 217 140z" fill="url(#a)"/>
|
||||
<g id="RasterLarge" transform="matrix(1.36 0 0 1.28 -161 -636)">
|
||||
<path fill="#999" d="m287 730h-30v-60h20v20h10v10h10v10h20v10h40v-10h20v-20h10v-20h-10v-10h-10v-10h-40v-10h-30v-10h-20v-10h-10v-10h-10v-60h10v-10h10v-10h10v-10h90v10h30v60h-20v-10h-10v-20h-10v-10h-20v-10h-30v10h-20v10h-10v20h10v20h30v10h30v10h30v10h10v10h10v10h10v60h-10v10h-10v10h-10v10h-100v-10z"/>
|
||||
<path fill="#555" d="m297 730h-30v-10h-10v-50h20v20h10v20h10 10v10h60v-10h10v-10h10v-40h-20v-10h-20v-10h-40v-10h-20v-10h-20v-20h-10v-50h10v-10h10v-10h20v-10h70v10h30v10h10v50h-20v-20h-10v-20h-20v-10h-50v10h-10v10h-10v30h10v10h20v10h30v10h30v10h20v10h10v10h10v50h-10v20h-10v10h-20v10h-80z"/>
|
||||
<path d="m307 730h-30v-10h-20v-50h20v30h10v10h10v10h70v-10h20v-50h-10v-10h-20v-10h-40v-10h-30v-10h-10v-10h-10v-20h-10v-30h10v-20h20v-10h20v-10h50v10h30v10h20v50h-20v-30h-10v-10h-10v-10h-70v10h-10v40h10v10h10v10h30v10h40v10h20v10h10v20h10v40h-10v20h-20v10h-30v10h-50v-10z"/>
|
||||
</g>
|
||||
<g font-size="40" font-family="sans-serif" text-anchor="middle">
|
||||
<g font-size="100">
|
||||
<text y="518" x="210">Raster</text>
|
||||
<text y="518" x="695" fill="#338">Vector</text>
|
||||
</g>
|
||||
<text y="563" x="210">.jpeg .gif .png</text>
|
||||
<text y="563" x="696" fill="#338">.svg</text>
|
||||
</g>
|
||||
<path id="VectorLarge" fill="#005" d="m661 294v-62.5l23.4 0.184c0.678 20.8 7.32 36.3 19.9 46.4 12.7 9.93 32.1 14.9 57.9 14.9 24.1 0 42.5-4.29 55.1-12.9 12.7-8.71 19.1-21.3 19.1-37.9 0-13.2-3.86-23.4-11.6-30.5-7.59-7.11-23.7-14-48.4-20.8l-40.1-10.9c-29-7.97-49.5-17.9-61.4-29.8-11.8-11.9-17.7-28.2-17.7-48.9 0-23.3 9.15-41.4 27.4-54.3 18.3-12.9 44-19.3 77.1-19.3 14.1 0 29.6 1.41 46.4 4.23 16.8 2.7 34.7 6.68 53.7 12v58.5h-23c-2.3-19.4-9.49-33.4-21.6-41.9-11.9-8.71-30.2-13.1-54.7-13.1-21.4 0-37.7 3.99-49 12-11.1 7.85-16.7 19.3-16.7 34.4 0 13.1 4.2 23.4 12.6 30.9 8.4 7.48 26.2 14.9 53.5 22.3l37.6 10.1c27.5 7.48 47.1 17 58.8 28.7 11.8 11.5 17.7 27 17.7 46.5 0 26.6-9.42 46.7-28.3 60.2s-46.9 20.2-84.2 20.2c-16.7 0-33.7-1.53-51-4.6-18-3-35-7-53-13z"/>
|
||||
<use xlink:href="#VectorLarge" transform="matrix(.17 0 0 .17 392 313)"/>
|
||||
<use xlink:href="#RasterLarge" transform="matrix(.173 0 0 .173 -8.25 314)" height="100%" width="100%" y="0" x="0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 503 227" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
|
||||
<g id="svg" transform="matrix(0.965977,0,0,0.807602,0,0)">
|
||||
<rect x="0" y="0" width="520" height="280" style="fill:white;"/>
|
||||
<g transform="matrix(1.03522,0,0,1.23823,-69.7528,-83.422)">
|
||||
<g transform="matrix(1,0,0,1,243.977,20.0703)">
|
||||
<g id="Page">
|
||||
<g transform="matrix(0.961773,0,0,1.05962,6.19811,-3.01071)">
|
||||
<path d="M328.5,97.682C328.5,96.465 327.983,95.296 327.056,94.418C320.026,87.758 289.442,58.78 282.228,51.944C281.251,51.019 279.901,50.496 278.49,50.496C264.493,50.496 188.083,50.496 167.339,50.496C164.468,50.496 162.141,52.609 162.141,55.214C162.141,83.051 162.141,225.565 162.141,253.4C162.141,256.005 164.468,258.117 167.338,258.117C192.242,258.117 299.159,258.117 323.538,258.117C326.278,258.117 328.5,256.101 328.5,253.613C328.5,229.268 328.5,113.896 328.5,97.682Z" style="fill:rgb(253,253,253);stroke:rgb(51,51,51);stroke-width:3.95px;"/>
|
||||
</g>
|
||||
<g id="Dog-ear" serif:id="Dog ear" transform="matrix(1,0,0,1,-4,2)">
|
||||
<path d="M277.072,48.496L277.072,93.848C277.072,95.172 277.598,96.441 278.534,97.377C279.47,98.313 280.739,98.839 282.063,98.839C294.548,98.839 326.141,98.839 326.141,98.839" style="fill:rgb(245,245,245);stroke:rgb(51,51,51);stroke-width:4px;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,-29.6816,-0.395178)">
|
||||
<g transform="matrix(1.00243,0,0,1.11818,-144.72,-8.80181)">
|
||||
<path d="M465.73,119.654C465.73,117.605 463.874,115.941 461.588,115.941L310.259,115.941C307.973,115.941 306.117,117.605 306.117,119.654L306.117,183.108C306.117,185.157 307.973,186.821 310.259,186.821L461.588,186.821C463.874,186.821 465.73,185.157 465.73,183.108L465.73,119.654Z" style="fill:rgb(248,0,0);stroke:white;stroke-width:3.77px;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.24571,0,0,1.35864,116.812,84.3924)">
|
||||
<g transform="matrix(64,0,0,64,42.1437,77.6203)">
|
||||
<path d="M0.084,0L0.084,-0.68L0.297,-0.68C0.371,-0.68 0.434,-0.663 0.487,-0.63C0.54,-0.596 0.566,-0.54 0.566,-0.462C0.566,-0.385 0.538,-0.328 0.481,-0.292C0.424,-0.255 0.36,-0.237 0.288,-0.237L0.213,-0.237L0.213,0L0.084,0ZM0.293,-0.572L0.213,-0.572L0.213,-0.344L0.295,-0.344C0.334,-0.344 0.365,-0.353 0.389,-0.371C0.413,-0.388 0.426,-0.416 0.429,-0.454C0.429,-0.498 0.417,-0.529 0.393,-0.546C0.369,-0.563 0.336,-0.572 0.293,-0.572Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(64,0,0,64,79.7117,77.6203)">
|
||||
<path d="M0.332,0L0.084,0L0.084,-0.68L0.336,-0.68C0.441,-0.68 0.518,-0.648 0.569,-0.585C0.62,-0.522 0.645,-0.441 0.645,-0.344C0.645,-0.239 0.618,-0.155 0.563,-0.093C0.508,-0.031 0.431,0 0.332,0ZM0.337,-0.57L0.213,-0.57L0.213,-0.109L0.33,-0.109C0.385,-0.109 0.429,-0.127 0.462,-0.163C0.495,-0.199 0.511,-0.259 0.511,-0.344C0.511,-0.415 0.497,-0.47 0.469,-0.51C0.441,-0.55 0.397,-0.57 0.337,-0.57Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(64,0,0,64,123.424,77.6203)">
|
||||
<path d="M0.405,-0.288L0.213,-0.288L0.213,0L0.084,0L0.084,-0.68L0.469,-0.68L0.489,-0.578L0.213,-0.578L0.213,-0.389L0.386,-0.389L0.405,-0.288Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1.52217,67.3796,10.7507)">
|
||||
<rect x="23.501" y="81.3" width="162.305" height="61.77" style="fill:rgb(180,213,255);"/>
|
||||
</g>
|
||||
<g transform="matrix(0.967536,0,0,0.961535,5.90498,47.9703)">
|
||||
<g transform="matrix(90.4804,0,0,90.4804,82.6698,167.705)">
|
||||
<path d="M0.057,-0.337C0.057,-0.442 0.084,-0.527 0.139,-0.594C0.194,-0.66 0.271,-0.694 0.37,-0.696C0.477,-0.696 0.556,-0.662 0.607,-0.593C0.658,-0.524 0.684,-0.441 0.684,-0.344C0.684,-0.239 0.657,-0.153 0.602,-0.086C0.547,-0.019 0.469,0.014 0.37,0.014C0.264,0.014 0.185,-0.02 0.134,-0.089C0.083,-0.157 0.057,-0.24 0.057,-0.337ZM0.192,-0.338C0.192,-0.267 0.206,-0.208 0.235,-0.163C0.264,-0.118 0.308,-0.095 0.369,-0.095C0.424,-0.095 0.467,-0.115 0.5,-0.156C0.533,-0.197 0.549,-0.259 0.549,-0.344C0.549,-0.415 0.535,-0.473 0.506,-0.518C0.477,-0.563 0.433,-0.586 0.372,-0.586C0.319,-0.586 0.275,-0.564 0.242,-0.519C0.209,-0.474 0.192,-0.414 0.192,-0.338Z" style="fill:rgb(51,51,51);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(90.4804,0,0,90.4804,147.906,167.705)">
|
||||
<path d="M0.505,-0.557C0.473,-0.567 0.448,-0.574 0.429,-0.579C0.41,-0.583 0.388,-0.585 0.361,-0.585C0.307,-0.585 0.265,-0.563 0.236,-0.519C0.207,-0.475 0.192,-0.415 0.192,-0.338C0.192,-0.272 0.204,-0.215 0.229,-0.167C0.254,-0.119 0.295,-0.095 0.353,-0.095C0.382,-0.095 0.409,-0.098 0.434,-0.104C0.459,-0.11 0.481,-0.117 0.502,-0.126L0.551,-0.03C0.525,-0.017 0.494,-0.006 0.457,0.002C0.42,0.01 0.388,0.014 0.36,0.014C0.254,0.014 0.177,-0.02 0.129,-0.088C0.081,-0.156 0.057,-0.239 0.057,-0.337C0.057,-0.442 0.084,-0.527 0.137,-0.594C0.19,-0.661 0.266,-0.694 0.365,-0.694C0.385,-0.694 0.413,-0.691 0.448,-0.684C0.483,-0.677 0.516,-0.666 0.545,-0.65L0.505,-0.557Z" style="fill:rgb(51,51,51);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(90.4804,0,0,90.4804,199.751,167.705)">
|
||||
<path d="M0.293,-0.572L0.213,-0.572L0.213,-0.364L0.295,-0.364C0.334,-0.364 0.366,-0.372 0.391,-0.388C0.416,-0.403 0.429,-0.429 0.429,-0.465C0.429,-0.503 0.417,-0.53 0.393,-0.547C0.369,-0.564 0.336,-0.572 0.293,-0.572ZM0.479,0L0.335,-0.26C0.328,-0.259 0.32,-0.259 0.312,-0.259C0.304,-0.258 0.296,-0.258 0.288,-0.258L0.213,-0.258L0.213,0L0.084,0L0.084,-0.68L0.297,-0.68C0.371,-0.68 0.434,-0.663 0.487,-0.629C0.54,-0.595 0.566,-0.542 0.566,-0.471C0.566,-0.429 0.555,-0.393 0.534,-0.363C0.512,-0.332 0.484,-0.309 0.45,-0.292L0.617,0L0.479,0Z" style="fill:rgb(51,51,51);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g transform="matrix(0.916882,0,0,1,121.475,-32.6535)">
|
||||
<g transform="matrix(86.953,0,0,86.953,152.996,241.878)">
|
||||
<path d="M0.479,-0.428C0.5,-0.451 0.527,-0.47 0.562,-0.484C0.596,-0.497 0.627,-0.504 0.654,-0.504C0.72,-0.504 0.767,-0.485 0.795,-0.446C0.822,-0.407 0.836,-0.36 0.836,-0.304L0.836,0L0.705,0L0.705,-0.298C0.705,-0.329 0.698,-0.352 0.683,-0.369C0.668,-0.385 0.647,-0.393 0.619,-0.393C0.6,-0.393 0.581,-0.388 0.56,-0.378C0.539,-0.368 0.521,-0.357 0.504,-0.344C0.505,-0.337 0.505,-0.331 0.506,-0.324C0.507,-0.317 0.507,-0.311 0.507,-0.304L0.507,0L0.376,0L0.376,-0.298C0.376,-0.329 0.369,-0.352 0.354,-0.369C0.339,-0.385 0.318,-0.393 0.291,-0.393C0.274,-0.393 0.258,-0.39 0.241,-0.383C0.224,-0.376 0.207,-0.367 0.192,-0.356L0.192,0L0.062,0L0.062,-0.485L0.13,-0.485L0.162,-0.441C0.184,-0.461 0.211,-0.476 0.242,-0.488C0.273,-0.499 0.3,-0.504 0.325,-0.504C0.363,-0.504 0.395,-0.497 0.42,-0.484C0.445,-0.47 0.465,-0.451 0.479,-0.428Z" style="fill:rgb(51,51,51);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(86.953,0,0,86.953,228.906,241.878)">
|
||||
<path d="M0.156,0.023L0.179,-0.034L0.006,-0.467L0.14,-0.485L0.252,-0.191L0.358,-0.485L0.495,-0.485L0.278,0.064C0.263,0.103 0.236,0.137 0.197,0.165C0.158,0.193 0.118,0.212 0.075,0.222L0.029,0.115C0.052,0.105 0.077,0.093 0.104,0.079C0.13,0.064 0.147,0.046 0.156,0.023Z" style="fill:rgb(51,51,51);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Selectors" transform="matrix(0.965977,0,0,0.807602,67.3796,67.3718)">
|
||||
<g id="Right-selector" serif:id="Right selector">
|
||||
<g transform="matrix(1.03522,0,0,1.23823,2.07044,0)">
|
||||
<path d="M185.806,161.156L185.806,67.132" style="fill:none;stroke:rgb(76,159,255);stroke-width:4px;stroke-linecap:butt;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.03522,0,0,1.23823,161.788,169.469)">
|
||||
<circle cx="31.523" cy="34.314" r="10.021" style="fill:rgb(76,159,255);stroke:rgb(76,159,255);stroke-width:4px;stroke-linecap:butt;"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Left-selector" serif:id="Left selector">
|
||||
<g transform="matrix(1.03522,0,0,1.23823,-170.092,0)">
|
||||
<path d="M185.806,161.156L185.806,67.132" style="fill:none;stroke:rgb(76,159,255);stroke-width:4px;stroke-linecap:butt;"/>
|
||||
</g>
|
||||
<g transform="matrix(1.03522,0,0,1.23823,-10.3742,28.2274)">
|
||||
<circle cx="31.523" cy="34.314" r="10.021" style="fill:rgb(76,159,255);stroke:rgb(76,159,255);stroke-width:4px;stroke-linecap:butt;"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,47 @@
|
||||
OCRmyPDF documentation
|
||||
======================
|
||||
|
||||
OCRmyPDF adds an optical character recognition (OCR) text layer to scanned PDF
|
||||
files, allowing them to be searched.
|
||||
|
||||
PDF is the best format for storing and exchanging scanned documents.
|
||||
Unfortunately, PDFs can be difficult to modify. OCRmyPDF makes it easy to apply
|
||||
image processing and OCR to existing PDFs.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
introduction
|
||||
release_notes
|
||||
installation
|
||||
optimizer
|
||||
languages
|
||||
jbig2
|
||||
|
||||
.. toctree::
|
||||
:caption: Usage
|
||||
:maxdepth: 2
|
||||
|
||||
cookbook
|
||||
docker
|
||||
advanced
|
||||
batch
|
||||
performance
|
||||
pdfsecurity
|
||||
errors
|
||||
|
||||
.. toctree::
|
||||
:caption: Developers
|
||||
:maxdepth: 2
|
||||
|
||||
api
|
||||
plugins
|
||||
apiref
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
@@ -0,0 +1,834 @@
|
||||
===================
|
||||
Installing OCRmyPDF
|
||||
===================
|
||||
|
||||
.. |latest| image:: https://img.shields.io/pypi/v/ocrmypdf.svg
|
||||
:alt: OCRmyPDF latest released version on PyPI
|
||||
|
||||
|latest|
|
||||
|
||||
The easiest way to install OCRmyPDF is to follow the steps for your operating
|
||||
system/platform. This version may be out of date, however.
|
||||
|
||||
These platforms have one-liner installs:
|
||||
|
||||
+-------------------------------+-------------------------------+
|
||||
| Debian, Ubuntu | ``apt install ocrmypdf`` |
|
||||
+-------------------------------+-------------------------------+
|
||||
| Windows Subsystem for Linux | ``apt install ocrmypdf`` |
|
||||
+-------------------------------+-------------------------------+
|
||||
| Fedora | ``dnf install ocrmypdf`` |
|
||||
+-------------------------------+-------------------------------+
|
||||
| macOS | ``brew install ocrmypdf`` |
|
||||
+-------------------------------+-------------------------------+
|
||||
| LinuxBrew | ``brew install ocrmypdf`` |
|
||||
+-------------------------------+-------------------------------+
|
||||
| FreeBSD | ``pkg install py37-ocrmypdf`` |
|
||||
+-------------------------------+-------------------------------+
|
||||
| Conda (WSL, macOS, Linux) | ``conda install ocrmypdf`` |
|
||||
+-------------------------------+-------------------------------+
|
||||
|
||||
More detailed procedures are outlined below. If you want to do a manual
|
||||
install, or install a more recent version than your platform provides, read on.
|
||||
|
||||
.. contents:: Platform-specific steps
|
||||
:depth: 2
|
||||
:local:
|
||||
|
||||
Installing on Linux
|
||||
===================
|
||||
|
||||
Debian and Ubuntu 18.04 or newer
|
||||
--------------------------------
|
||||
|
||||
.. |deb-stable| image:: https://repology.org/badge/version-for-repo/debian_stable/ocrmypdf.svg
|
||||
:alt: Debian 9 stable ("stretch")
|
||||
|
||||
.. |deb-testing| image:: https://repology.org/badge/version-for-repo/debian_testing/ocrmypdf.svg
|
||||
:alt: Debian 10 testing ("buster")
|
||||
|
||||
.. |deb-unstable| image:: https://repology.org/badge/version-for-repo/debian_unstable/ocrmypdf.svg
|
||||
:alt: Debian unstable
|
||||
|
||||
.. |ubu-1804| image:: https://repology.org/badge/version-for-repo/ubuntu_18_04/ocrmypdf.svg
|
||||
:alt: Ubuntu 18.04 LTS
|
||||
|
||||
.. |ubu-2004| image:: https://repology.org/badge/version-for-repo/ubuntu_20_04/ocrmypdf.svg
|
||||
:alt: Ubuntu 20.04 LTS
|
||||
|
||||
.. |ubu-2010| image:: https://repology.org/badge/version-for-repo/ubuntu_20_10/ocrmypdf.svg
|
||||
:alt: Ubuntu 20.10
|
||||
|
||||
+-----------------------------------------------+
|
||||
| **OCRmyPDF versions in Debian & Ubuntu** |
|
||||
+-----------------------------------------------+
|
||||
| |latest| |
|
||||
+-----------------------------------------------+
|
||||
| |deb-stable| |deb-testing| |deb-unstable| |
|
||||
+-----------------------------------------------+
|
||||
| |ubu-1804| |ubu-2004| |ubu-2010| |
|
||||
+-----------------------------------------------+
|
||||
|
||||
Users of Debian 9 ("stretch") or later, or Ubuntu 18.04 or later, including users
|
||||
of Windows Subsystem for Linux, may simply
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
apt-get install ocrmypdf
|
||||
|
||||
As indicated in the table above, Debian and Ubuntu releases may lag
|
||||
behind the latest version. If the version available for your platform is
|
||||
out of date, you could opt to install the latest version from source.
|
||||
See `Installing HEAD revision from
|
||||
sources <#installing-head-revision-from-sources>`__. Ubuntu 16.10 to 17.10
|
||||
inclusive also had ocrmypdf, but these versions are end of life.
|
||||
|
||||
For full details on version availability for your platform, check the
|
||||
`Debian Package Tracker <https://tracker.debian.org/pkg/ocrmypdf>`__ or
|
||||
`Ubuntu launchpad.net <https://launchpad.net/ocrmypdf>`__.
|
||||
|
||||
.. note::
|
||||
|
||||
OCRmyPDF for Debian and Ubuntu currently omit the JBIG2 encoder.
|
||||
OCRmyPDF works fine without it but will produce larger output files.
|
||||
If you build jbig2enc from source, ocrmypdf 7.0.0 and later will
|
||||
automatically detect it (specifically the ``jbig2`` binary) on the
|
||||
``PATH``. To add JBIG2 encoding, see :ref:`jbig2`.
|
||||
|
||||
Fedora
|
||||
------
|
||||
|
||||
.. |fedora-32| image:: https://repology.org/badge/version-for-repo/fedora_32/ocrmypdf.svg
|
||||
:alt: Fedora 32
|
||||
|
||||
.. |fedora-33| image:: https://repology.org/badge/version-for-repo/fedora_33/ocrmypdf.svg
|
||||
:alt: Fedora 33
|
||||
|
||||
.. |fedora-rawhide| image:: https://repology.org/badge/version-for-repo/fedora_rawhide/ocrmypdf.svg
|
||||
:alt: Fedore Rawhide
|
||||
|
||||
+-----------------------------------------------+
|
||||
| **OCRmyPDF version** |
|
||||
+-----------------------------------------------+
|
||||
| |latest| |
|
||||
+-----------------------------------------------+
|
||||
| |fedora-32| |fedora-33| |fedora-rawhide| |
|
||||
+-----------------------------------------------+
|
||||
|
||||
Users of Fedora 29 or later may simply
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
dnf install ocrmypdf
|
||||
|
||||
For full details on version availability, check the `Fedora Package
|
||||
Tracker <https://apps.fedoraproject.org/packages/ocrmypdf>`__.
|
||||
|
||||
If the version available for your platform is out of date, you could opt
|
||||
to install the latest version from source. See `Installing HEAD revision
|
||||
from sources <#installing-head-revision-from-sources>`__.
|
||||
|
||||
.. note::
|
||||
|
||||
OCRmyPDF for Fedora currently omits the JBIG2 encoder due to patent
|
||||
issues. OCRmyPDF works fine without it but will produce larger output
|
||||
files. If you build jbig2enc from source, ocrmypdf 7.0.0 and later
|
||||
will automatically detect it on the ``PATH``. To add JBIG2 encoding,
|
||||
see `Installing the JBIG2 encoder <jbig2>`__.
|
||||
|
||||
.. _ubuntu-lts-latest:
|
||||
|
||||
Installing the latest version on Ubuntu 20.04 LTS
|
||||
-------------------------------------------------
|
||||
|
||||
Ubuntu 20.04 includes ocrmypdf 9.6.0 - you can install that with ``apt``. To
|
||||
install a more recent version, uninstall the system-provided version of
|
||||
ocrmypdf, and install the following dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt-get -y remove ocrmypdf # remove system ocrmypdf, if installed
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install \
|
||||
ghostscript \
|
||||
icc-profiles-free \
|
||||
liblept5 \
|
||||
libxml2 \
|
||||
pngquant \
|
||||
python3-pip \
|
||||
tesseract-ocr \
|
||||
zlib1g
|
||||
|
||||
To install ocrmypdf for the system:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install ocrmypdf
|
||||
|
||||
To install for the current user only:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export PATH=$HOME/.local/bin:$PATH
|
||||
pip3 install --user ocrmypdf
|
||||
|
||||
Ubuntu 18.04 LTS
|
||||
----------------
|
||||
|
||||
Ubuntu 18.04 includes ocrmypdf 6.1.2 - you can install that with ``apt``, but
|
||||
it is quite old now. To install a more recent version, uninstall the old version
|
||||
of ocrmypdf, and install the following dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt-get -y remove ocrmypdf
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install \
|
||||
ghostscript \
|
||||
icc-profiles-free \
|
||||
liblept5 \
|
||||
libxml2 \
|
||||
pngquant \
|
||||
python3-cffi \
|
||||
python3-distutils \
|
||||
python3-pkg-resources \
|
||||
python3-reportlab \
|
||||
qpdf \
|
||||
tesseract-ocr \
|
||||
zlib1g \
|
||||
unpaper
|
||||
|
||||
We will need a newer version of ``pip`` then was available for Ubuntu 18.04:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py
|
||||
|
||||
Then install the most recent ocrmypdf for the local user and set the
|
||||
user's ``PATH`` to check for the user's Python packages.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export PATH=$HOME/.local/bin:$PATH
|
||||
python3 -m pip install --user ocrmypdf
|
||||
|
||||
To add JBIG2 encoding, see :ref:`jbig2`.
|
||||
|
||||
Ubuntu 16.04 LTS
|
||||
----------------
|
||||
|
||||
No package is available for Ubuntu 16.04. OCRmyPDF 8.0 and newer require
|
||||
Python 3.6. Ubuntu 16.04 ships Python 3.5, but you can install Python
|
||||
3.6 on it. Or, you can skip Python 3.6 and install OCRmyPDF 7.x or older
|
||||
- for that procedure, please see the installation documentation for the
|
||||
version of OCRmyPDF you plan to use.
|
||||
|
||||
**Install system packages for OCRmyPDF**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y software-properties-common python-software-properties
|
||||
sudo add-apt-repository -y \
|
||||
ppa:jonathonf/python-3.6 \
|
||||
ppa:alex-p/tesseract-ocr
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
ghostscript \
|
||||
libexempi3 \
|
||||
libffi6 \
|
||||
pngquant \
|
||||
python3.6 \
|
||||
qpdf \
|
||||
tesseract-ocr \
|
||||
unpaper
|
||||
|
||||
This will install a Python 3.6 binary at ``/usr/bin/python3.6``
|
||||
alongside the system's Python 3.5. Do not remove the system Python. This
|
||||
will also install Tesseract 4.0 from a PPA, since the version available
|
||||
in Ubuntu 16.04 is too old for OCRmyPDF.
|
||||
|
||||
Now install pip for Python 3.6. This will install the Python 3.6 version
|
||||
of ``pip`` at ``/usr/local/bin/pip``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl https://bootstrap.pypa.io/get-pip.py | sudo python3.6
|
||||
|
||||
**Install OCRmyPDF**
|
||||
|
||||
OCRmyPDF requires the locale to be set for UTF-8. **On some minimal
|
||||
Ubuntu installations**, such as the Ubuntu 16.04 Docker images it may be
|
||||
necessary to set the locale.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Optional: Only need to set these if they are not already set
|
||||
export LC_ALL=C.UTF-8
|
||||
export LANG=C.UTF-8
|
||||
|
||||
Now install OCRmyPDF for the current user, and ensure that the ``PATH``
|
||||
environment variable contains ``$HOME/.local/bin``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export PATH=$HOME/.local/bin:$PATH
|
||||
pip3.6 install --user ocrmypdf
|
||||
|
||||
To add JBIG2 encoding, see :ref:`jbig2`.
|
||||
|
||||
Arch Linux (AUR)
|
||||
----------------
|
||||
|
||||
.. image:: https://repology.org/badge/version-for-repo/aur/ocrmypdf.svg
|
||||
:alt: ArchLinux
|
||||
:target: https://repology.org/metapackage/ocrmypdf
|
||||
|
||||
There is an `Arch User Repository (AUR) package for OCRmyPDF
|
||||
<https://aur.archlinux.org/packages/ocrmypdf/>`__.
|
||||
|
||||
Installing AUR packages as root is not allowed, so you must first `setup a
|
||||
non-root user
|
||||
<https://wiki.archlinux.org/index.php/Users_and_groups#User_management>`__ and
|
||||
`configure sudo <https://wiki.archlinux.org/index.php/Sudo#Configuration>`__.
|
||||
The standard Docker image, ``archlinux/base:latest``, does **not** have a
|
||||
non-root user configured, so users of that image must follow these guides. If
|
||||
you are using a VM image, such as `the official Vagrant image
|
||||
<https://app.vagrantup.com/archlinux/boxes/archlinux>`__, this work may already
|
||||
be completed for you.
|
||||
|
||||
Next you should install the `base-devel package group
|
||||
<https://www.archlinux.org/groups/x86_64/base-devel/>`__. This includes the
|
||||
standard tooling needed to build packages, such as a compiler and binary tools.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo pacman -S base-devel
|
||||
|
||||
Now you are ready to install the OCRmyPDF package.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
curl -O https://aur.archlinux.org/cgit/aur.git/snapshot/ocrmypdf.tar.gz
|
||||
tar xvzf ocrmypdf.tar.gz
|
||||
cd ocrmypdf
|
||||
makepkg -sri
|
||||
|
||||
At this point you will have a working install of OCRmyPDF, but the Tesseract
|
||||
install won’t include any OCR language data. You can install `the
|
||||
tesseract-data package group
|
||||
<https://www.archlinux.org/groups/any/tesseract-data/>`__ to add all supported
|
||||
languages, or use that package listing to identify the appropriate package for
|
||||
your desired language.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo pacman -S tesseract-data-eng
|
||||
|
||||
As an alternative to this manual procedure, consider using an `AUR helper
|
||||
<https://wiki.archlinux.org/index.php/AUR_helpers>`__. Such a tool will
|
||||
automatically fetch, build and install the AUR package, resolve dependencies
|
||||
(including dependencies on AUR packages), and ease the upgrade procedure.
|
||||
|
||||
If you have any difficulties with installation, check the repository package
|
||||
page.
|
||||
|
||||
.. note::
|
||||
|
||||
The OCRmyPDF AUR package currently omits the JBIG2 encoder. OCRmyPDF works
|
||||
fine without it but will produce larger output files. The encoder is
|
||||
available from `the jbig2enc-git AUR package
|
||||
<https://aur.archlinux.org/packages/jbig2enc-git/>`__ and may be installed
|
||||
using the same series of steps as for the installation OCRmyPDF AUR
|
||||
package. Alternatively, it may be built manually from source following the
|
||||
instructions in `Installing the JBIG2 encoder <jbig2>`__. If JBIG2 is
|
||||
installed, OCRmyPDF 7.0.0 and later will automatically detect it.
|
||||
|
||||
Alpine Linux
|
||||
------------
|
||||
|
||||
.. image:: https://repology.org/badge/version-for-repo/alpine_edge/ocrmypdf.svg
|
||||
:alt: Alpine Linux
|
||||
:target: https://repology.org/metapackage/ocrmypdf
|
||||
|
||||
To install OCRmyPDF for Alpine Linux:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
apk add ocrmypdf
|
||||
|
||||
Mageia 7
|
||||
--------
|
||||
|
||||
There is no OS-level packaging available for Mageia, so you must install the
|
||||
dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# As root user
|
||||
urpmi.update -a
|
||||
urpmi \
|
||||
ghostscript \
|
||||
icc-profiles-openicc \
|
||||
jbig2dec \
|
||||
lib64leptonica5 \
|
||||
pngquant \
|
||||
python3-pip \
|
||||
python3-cffi \
|
||||
python3-distutils-extra \
|
||||
python3-pkg-resources \
|
||||
python3-reportlab \
|
||||
qpdf \
|
||||
tesseract \
|
||||
tesseract-osd \
|
||||
tesseract-eng \
|
||||
tesseract-fra
|
||||
|
||||
To install ocrmypdf for the system:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# As root user
|
||||
pip3 install ocrmypdf
|
||||
ldconfig
|
||||
|
||||
Or, to install for the current user only:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export PATH=$HOME/.local/bin:$PATH
|
||||
pip3 install --user ocrmypdf
|
||||
|
||||
Other Linux packages
|
||||
--------------------
|
||||
|
||||
See the
|
||||
`Repology <https://repology.org/metapackage/ocrmypdf/versions>`__ page.
|
||||
|
||||
In general, first install the OCRmyPDF package for your system, then
|
||||
optionally use the procedure `Installing with Python
|
||||
pip <#installing-with-python-pip>`__ to install a more recent version.
|
||||
|
||||
Installing on macOS
|
||||
===================
|
||||
|
||||
Homebrew
|
||||
--------
|
||||
|
||||
.. image:: https://img.shields.io/homebrew/v/ocrmypdf.svg
|
||||
:alt: homebrew
|
||||
:target: http://brewformulas.org/Ocrmypdf
|
||||
|
||||
OCRmyPDF is now a standard `Homebrew <https://brew.sh>`__ formula. To
|
||||
install on macOS:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
brew install ocrmypdf
|
||||
|
||||
This will include only the English language pack. If you need other
|
||||
languages you can optionally install them all:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
brew install tesseract-lang # Optional: Install all language packs
|
||||
|
||||
.. note::
|
||||
|
||||
Users who previously installed OCRmyPDF on macOS using
|
||||
``pip install ocrmypdf`` should remove the pip version
|
||||
(``pip3 uninstall ocrmypdf``) before switching to the Homebrew
|
||||
version.
|
||||
|
||||
.. note::
|
||||
|
||||
Users who previously installed OCRmyPDF from the private tap should
|
||||
switch to the mainline version (``brew untap jbarlow83/ocrmypdf``)
|
||||
and install from there.
|
||||
|
||||
Manual installation on macOS
|
||||
----------------------------
|
||||
|
||||
These instructions probably work on all macOS supported by Homebrew, and are
|
||||
for installing a more current version of OCRmyPDF than is available from
|
||||
Homebrew. Note that the Homebrew versions usually track the release versions
|
||||
fairly closely.
|
||||
|
||||
If it's not already present, `install Homebrew <http://brew.sh/>`__.
|
||||
|
||||
Update Homebrew:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
brew update
|
||||
|
||||
Install or upgrade the required Homebrew packages, if any are missing.
|
||||
To do this, use ``brew edit ocrmypdf`` to obtain a recent list of Homebrew
|
||||
dependencies. You could also check the ``.workflows/build.yml``.
|
||||
|
||||
This will include the English, French, German and Spanish language
|
||||
packs. If you need other languages you can optionally install them all:
|
||||
|
||||
.. _macos-all-languages:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
brew install tesseract-lang # Option 2: for all language packs
|
||||
|
||||
Update the homebrew pip:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install --upgrade pip
|
||||
|
||||
You can then install OCRmyPDF from PyPI, for the current user:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install --user ocrmypdf
|
||||
|
||||
or system-wide:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install ocrmypdf
|
||||
|
||||
The command line program should now be available:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --help
|
||||
|
||||
Installing on Windows
|
||||
=====================
|
||||
|
||||
Native Windows
|
||||
--------------
|
||||
|
||||
.. note::
|
||||
|
||||
Administrator privileges will be required for some of these steps.
|
||||
|
||||
You must install the following for Windows:
|
||||
|
||||
* Python 3.7 (64-bit) or later
|
||||
* Tesseract 4.0 or later
|
||||
* Ghostscript 9.50 or later
|
||||
|
||||
Using the `Chocolatey <https://chocolatey.org/>`_ package manager, install the
|
||||
following when running in an Administrator command prompt:
|
||||
|
||||
* ``choco install python3``
|
||||
* ``choco install --pre tesseract``
|
||||
* ``choco install ghostscript``
|
||||
* ``choco install pngquant`` (optional)
|
||||
|
||||
The commands above will install Python 3.x (latest version), Tesseract, Ghostscript
|
||||
and pngquant. Chocolatey may also need to install the Windows Visual C++ Runtime
|
||||
DLLs or other Windows patches, and may require a reboot.
|
||||
|
||||
You may then use ``pip`` to install ocrmypdf. (This can performed by a user or
|
||||
Administrator.):
|
||||
|
||||
* ``pip install ocrmypdf``
|
||||
|
||||
Chocolatey automatically selects appropriate versions of these applications. If you
|
||||
are installing them manually, please install 64-bit versions of all applications for
|
||||
64-bit Windows, or 32-bit versions of all applications for 32-bit Windows. Mixing
|
||||
the "bitness" of these programs will lead to errors.
|
||||
|
||||
OCRmyPDF will check the Windows Registry and standard locations in your Program Files
|
||||
for third party software it needs (specifically, Tesseract and Ghostscript). To
|
||||
override the versions OCRmyPDF selects, you can modify the ``PATH`` environment
|
||||
variable. `Follow these directions <https://www.computerhope.com/issues/ch000549.htm#dospath>`_
|
||||
to change the PATH.
|
||||
|
||||
.. warning::
|
||||
|
||||
As of early 2021, users have reported problems with the Microsoft Store version of
|
||||
Python and OCRmyPDF. These issues affect many other third party Python packages.
|
||||
Please download Python from Python.org or Chocolatey instead, and do not use the
|
||||
Microsoft Store version.
|
||||
|
||||
Windows Subsystem for Linux
|
||||
---------------------------
|
||||
|
||||
#. Install Ubuntu 18.04 for Windows Subsystem for Linux, if not already installed.
|
||||
#. Follow the procedure to install :ref:`OCRmyPDF on Ubuntu 18.04 <ubuntu-lts-latest>`.
|
||||
#. Open the Windows command prompt and create a symlink:
|
||||
|
||||
.. code-block:: powershell
|
||||
|
||||
wsl sudo ln -s /home/$USER/.local/bin/ocrmypdf /usr/local/bin/ocrmypdf
|
||||
|
||||
Then confirm that the expected version from PyPI (|latest|) is installed:
|
||||
|
||||
.. code-block:: powershell
|
||||
|
||||
wsl ocrmypdf --version
|
||||
|
||||
You can then run OCRmyPDF in the Windows command prompt or Powershell, prefixing
|
||||
``wsl``, and call it from Windows programs or batch files.
|
||||
|
||||
Cygwin64
|
||||
--------
|
||||
|
||||
First install the the following prerequisite Cygwin packages using ``setup-x86_64.exe``::
|
||||
|
||||
python36 (or later)
|
||||
python3?-devel
|
||||
python3?-pip
|
||||
python3?-lxml
|
||||
python3?-imaging
|
||||
|
||||
(where 3? means match the version of python3 you installed)
|
||||
|
||||
gcc-g++
|
||||
ghostscript (<=9.50 or >=9.52-2 see note below)
|
||||
libexempi3
|
||||
libexempi-devel
|
||||
libffi6
|
||||
libffi-devel
|
||||
pngquant
|
||||
qpdf
|
||||
libqpdf-devel
|
||||
tesseract-ocr
|
||||
tesseract-ocr-devel
|
||||
|
||||
.. note::
|
||||
|
||||
The Cygwin package for Ghostscript in versions 9.52 and
|
||||
9.52-1 contained a bug that caused an exception to occur when
|
||||
ocrmypdf invoked gs. Make sure you have either 9.50 (or earlier)
|
||||
or 9.52-2 (or later).
|
||||
|
||||
Then open a Cygwin terminal (i.e. ``mintty``), run the following commands. Note
|
||||
that if you are using the version of ``pip`` that was installed with the Cygwin
|
||||
Python package, the command name will be ``pip3``. If you have since updated
|
||||
``pip`` (with, for instance ``pip3 install --upgrade pip``) the the command is
|
||||
likely just ``pip`` instead of ``pip3``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install wheel
|
||||
pip3 install ocrmypdf
|
||||
|
||||
The optional dependency "unpaper" that is currently not available under Cygwin.
|
||||
Without it, certain options such as ``--clean`` will produce an error message.
|
||||
However, the OCR-to-text-layer functionality is available.
|
||||
|
||||
Docker
|
||||
------
|
||||
|
||||
You can also :ref:`Install the Docker <docker>` container on Windows. Ensure that
|
||||
your command prompt can run the docker "hello world" container.
|
||||
|
||||
Installing on FreeBSD
|
||||
=====================
|
||||
|
||||
.. image:: https://repology.org/badge/version-for-repo/freebsd/python:ocrmypdf.svg
|
||||
:alt: FreeBSD
|
||||
:target: https://repology.org/project/python:ocrmypdf/versions
|
||||
|
||||
FreeBSD 11.3, 12.0, 12.1-RELEASE and 13.0-CURRENT are supported. Other
|
||||
versions likely work but have not been tested.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pkg install py37-ocrmypdf
|
||||
|
||||
To install a more recent version, you could attempt to first install the system
|
||||
version with ``pkg``, then use ``pip install --user ocrmypdf``.
|
||||
|
||||
Installing the Docker image
|
||||
===========================
|
||||
|
||||
For some users, installing the Docker image will be easier than
|
||||
installing all of OCRmyPDF's dependencies.
|
||||
|
||||
See :ref:`docker` for more information.
|
||||
|
||||
Installing with Python pip
|
||||
==========================
|
||||
|
||||
OCRmyPDF is delivered by PyPI because it is a convenient way to install
|
||||
the latest version. However, PyPI and ``pip`` cannot address the fact
|
||||
that ``ocrmypdf`` depends on certain non-Python system libraries and
|
||||
programs being installed.
|
||||
|
||||
.. warning::
|
||||
|
||||
Debian and Ubuntu users: unfortunately, Debian and Ubuntu customize
|
||||
Python in non-standard ways, and the nature of these customizations
|
||||
varies from release to release. This can make for a frustrating
|
||||
user experience. The instructions below work on almost all platforms that
|
||||
have Python installed, except for Debian and Ubuntu, where you may need
|
||||
to take additional steps. For best results on Debian and Ubuntu, use the
|
||||
``apt`` packages; or if these are too old, run
|
||||
``apt install python3-pip python3-venv``, create a virtual environment,
|
||||
and install OCRmyPDF in that environment.
|
||||
|
||||
`See here for more inforation on Debian-Python issues
|
||||
<https://gist.github.com/tiran/2dec9e03c6f901814f6d1e8dad09528e>`__.
|
||||
|
||||
For best results, first install `your platform's
|
||||
version <https://repology.org/metapackage/ocrmypdf/versions>`__ of
|
||||
``ocrmypdf``, using the instructions elsewhere in this document. Then
|
||||
you can use ``pip`` to get the latest version if your platform version
|
||||
is out of date. Chances are that this will satisfy most dependencies.
|
||||
|
||||
Use ``ocrmypdf --version`` to confirm what version was installed.
|
||||
|
||||
Then you can install the latest OCRmyPDF from the Python wheels. First
|
||||
try:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install --user ocrmypdf
|
||||
|
||||
You should then be able to run ``ocrmypdf --version`` and see that the
|
||||
latest version was located.
|
||||
|
||||
Since ``pip3 install --user`` does not work correctly on some platforms,
|
||||
notably Ubuntu 16.04 and older, and the Homebrew version of Python,
|
||||
instead use this for a system wide installation:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install ocrmypdf
|
||||
|
||||
.. note::
|
||||
|
||||
AArch64 (ARM64) users: this process will be difficult because most
|
||||
Python packages are not available as binary wheels for your platform.
|
||||
You're probably better off using a platform install on Debian, Ubuntu,
|
||||
or Fedora.
|
||||
|
||||
Requirements for pip and HEAD install
|
||||
-------------------------------------
|
||||
|
||||
OCRmyPDF currently requires these external programs and libraries to be
|
||||
installed, and must be satisfied using the operating system package
|
||||
manager. ``pip`` cannot provide them.
|
||||
|
||||
- Python 3.6 or newer
|
||||
- Ghostscript 9.15 or newer
|
||||
- qpdf 8.1.0 or newer
|
||||
- Tesseract 4.0.0-beta or newer
|
||||
|
||||
As of ocrmypdf 7.2.1, the following versions are recommended:
|
||||
|
||||
- Python 3.7 or 3.8
|
||||
- Ghostscript 9.23 or newer
|
||||
- qpdf 8.2.1
|
||||
- Tesseract 4.0.0 or newer
|
||||
- jbig2enc 0.29 or newer
|
||||
- pngquant 2.5 or newer
|
||||
- unpaper 6.1
|
||||
|
||||
jbig2enc, pngquant, and unpaper are optional. If missing certain
|
||||
features are disabled. OCRmyPDF will discover them as soon as they are
|
||||
available.
|
||||
|
||||
**jbig2enc**, if present, will be used to optimize the encoding of
|
||||
monochrome images. This can significantly reduce the file size of the
|
||||
output file. It is not required.
|
||||
`jbig2enc <https://github.com/agl/jbig2enc>`__ is not generally
|
||||
available for Ubuntu or Debian due to lingering concerns about patent
|
||||
issues, but can easily be built from source. To add JBIG2 encoding, see
|
||||
:ref:`jbig2`.
|
||||
|
||||
**pngquant**, if present, is optionally used to optimize the encoding of
|
||||
PNG-style images in PDFs (actually, any that are that losslessly
|
||||
encoded) by lossily quantizing to a smaller color palette. It is only
|
||||
activated then the ``--optimize`` argument is ``2`` or ``3``.
|
||||
|
||||
**unpaper**, if present, enables the ``--clean`` and ``--clean-final``
|
||||
command line options.
|
||||
|
||||
These are in addition to the Python packaging dependencies, meaning that
|
||||
unfortunately, the ``pip install`` command cannot satisfy all of them.
|
||||
|
||||
Installing HEAD revision from sources
|
||||
=====================================
|
||||
|
||||
If you have ``git`` and Python 3.6 or newer installed, you can install
|
||||
from source. When the ``pip`` installer runs, it will alert you if
|
||||
dependencies are missing.
|
||||
|
||||
If you prefer to build every from source, you will need to `build
|
||||
pikepdf from
|
||||
source <https://pikepdf.readthedocs.io/en/latest/installation.html#building-from-source>`__.
|
||||
First ensure you can build and install pikepdf.
|
||||
|
||||
To install the HEAD revision from sources in the current Python 3
|
||||
environment:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install git+https://github.com/jbarlow83/OCRmyPDF.git
|
||||
|
||||
Or, to install in `development
|
||||
mode <https://pythonhosted.org/setuptools/setuptools.html#development-mode>`__,
|
||||
allowing customization of OCRmyPDF, use the ``-e`` flag:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip3 install -e git+https://github.com/jbarlow83/OCRmyPDF.git
|
||||
|
||||
You may find it easiest to install in a virtual environment, rather than
|
||||
system-wide:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone -b master https://github.com/jbarlow83/OCRmyPDF.git
|
||||
python3 -m venv
|
||||
source venv/bin/activate
|
||||
cd OCRmyPDF
|
||||
pip3 install .
|
||||
|
||||
However, ``ocrmypdf`` will only be accessible on the system PATH when
|
||||
you activate the virtual environment.
|
||||
|
||||
To run the program:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --help
|
||||
|
||||
If not yet installed, the script will notify you about dependencies that
|
||||
need to be installed. The script requires specific versions of the
|
||||
dependencies. Older version than the ones mentioned in the release notes
|
||||
are likely not to be compatible to OCRmyPDF.
|
||||
|
||||
For development
|
||||
---------------
|
||||
|
||||
To install all of the development and test requirements:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone -b master https://github.com/jbarlow83/OCRmyPDF.git
|
||||
python3 -m venv
|
||||
source venv/bin/activate
|
||||
cd OCRmyPDF
|
||||
pip install -e .
|
||||
pip install -r requirements/dev.txt -r requirements/test.txt
|
||||
|
||||
To add JBIG2 encoding, see :ref:`jbig2`.
|
||||
|
||||
Shell completions
|
||||
=================
|
||||
|
||||
Completions for ``bash`` and ``fish`` are available in the project's
|
||||
``misc/completion`` folder. The ``bash`` completions are likely ``zsh``
|
||||
compatible but this has not been confirmed. Package maintainers, please
|
||||
install these at the appropriate locations for your system.
|
||||
|
||||
To manually install the ``bash`` completion, copy
|
||||
``misc/completion/ocrmypdf.bash`` to ``/etc/bash_completion.d/ocrmypdf``
|
||||
(rename the file).
|
||||
|
||||
To manually install the ``fish`` completion, copy
|
||||
``misc/completion/ocrmypdf.fish`` to
|
||||
``~/.config/fish/completions/ocrmypdf.fish``.
|
||||
@@ -0,0 +1,233 @@
|
||||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
OCRmyPDF is a Python 3 application and library that adds OCR layers to PDFs.
|
||||
|
||||
About OCR
|
||||
=========
|
||||
|
||||
`Optical character
|
||||
recognition <https://en.wikipedia.org/wiki/Optical_character_recognition>`__
|
||||
is technology that converts images of typed or handwritten text, such as
|
||||
in a scanned document, to computer text that can be selected, searched and copied.
|
||||
|
||||
OCRmyPDF uses
|
||||
`Tesseract <https://github.com/tesseract-ocr/tesseract>`__, the best
|
||||
available open source OCR engine, to perform OCR.
|
||||
|
||||
.. _raster-vector:
|
||||
|
||||
About PDFs
|
||||
==========
|
||||
|
||||
PDFs are page description files that attempts to preserve a layout
|
||||
exactly. They contain `vector
|
||||
graphics <http://vector-conversions.com/vectorizing/raster_vs_vector.html>`__
|
||||
that can contain raster objects such as scanned images. Because PDFs can
|
||||
contain multiple pages (unlike many image formats) and can contain fonts
|
||||
and text, it is a good formats for exchanging scanned documents.
|
||||
|
||||
|image|
|
||||
|
||||
A PDF page might contain multiple images, even if it only appears to
|
||||
have one image. Some scanners or scanning software will segment pages
|
||||
into monochromatic text and color regions for example, to improve the
|
||||
compression ratio and appearance of the page.
|
||||
|
||||
Rasterizing a PDF is the process of generating an image suitable for
|
||||
display or analyzing with an OCR engine. OCR engines like Tesseract work
|
||||
with images, not vector objects.
|
||||
|
||||
About PDF/A
|
||||
===========
|
||||
|
||||
`PDF/A <https://en.wikipedia.org/wiki/PDF/A>`__ is an ISO-standardized
|
||||
subset of the full PDF specification that is designed for archiving (the
|
||||
'A' stands for Archive). PDF/A differs from PDF primarily by omitting
|
||||
features that would make it difficult to read the file in the future,
|
||||
such as embedded Javascript, video, audio and references to external
|
||||
fonts. All fonts and resources needed to interpret the PDF must be
|
||||
contained within it. Because PDF/A disables Javascript and other types
|
||||
of embedded content, it is probably more secure.
|
||||
|
||||
There are various conformance levels and versions, such as "PDF/A-2b".
|
||||
|
||||
Generally speaking, the best format for scanned documents is PDF/A. Some
|
||||
governments and jurisdictions, US Courts in particular, `mandate the use
|
||||
of PDF/A <https://pdfblog.com/2012/02/13/what-is-pdfa/>`__ for scanned
|
||||
documents.
|
||||
|
||||
Since most people who scan documents are interested in reading them
|
||||
indefinitely into the future, OCRmyPDF generates PDF/A-2b by default.
|
||||
|
||||
PDF/A has a few drawbacks. Some PDF viewers include an alert that the
|
||||
file is a PDF/A, which may confuse some users. It also tends to produce
|
||||
larger files than PDF, because it embeds certain resources even if they
|
||||
are commonly available. PDF/A files can be digitally signed, but may not
|
||||
be encrypted, to ensure they can be read in the future. Fortunately,
|
||||
converting from PDF/A to a regular PDF is trivial, and any PDF viewer
|
||||
can view PDF/A.
|
||||
|
||||
What OCRmyPDF does
|
||||
==================
|
||||
|
||||
OCRmyPDF analyzes each page of a PDF to determine the colorspace and
|
||||
resolution (DPI) needed to capture all of the information on that page
|
||||
without losing content. It uses
|
||||
`Ghostscript <http://ghostscript.com/>`__ to rasterize the page, and
|
||||
then performs on OCR on the rasterized image to create an OCR "layer".
|
||||
The layer is then grafted back onto the original PDF.
|
||||
|
||||
While one can use a program like Ghostscript or ImageMagick to get an
|
||||
image and put the image through Tesseract, that actually creates a new
|
||||
PDF and many details may be lost. OCRmyPDF can produce a minimally
|
||||
changed PDF as output.
|
||||
|
||||
OCRmyPDF also some image processing options like deskew which improve
|
||||
the appearance of files and quality of OCR. When these are used, the OCR
|
||||
layer is grafted onto the processed image instead.
|
||||
|
||||
By default, OCRmyPDF produces archival PDFs – PDF/A, which are a
|
||||
stricter subset of PDF features designed for long term archives. If
|
||||
regular PDFs are desired, this can be disabled with
|
||||
``--output-type pdf``.
|
||||
|
||||
Why you shouldn't do this manually
|
||||
==================================
|
||||
|
||||
A PDF is similar to an HTML file, in that it contains document structure
|
||||
along with images. Sometimes a PDF does nothing more than present a full
|
||||
page image, but often there is additional content that would be lost.
|
||||
|
||||
A manual process could work like either of these:
|
||||
|
||||
1. Rasterize each page as an image, OCR the images, and combine the
|
||||
output into a PDF. This preserves the layout of each page, but
|
||||
resamples all images (possibly losing quality, increasing file size,
|
||||
introducing compression artifacts, etc.).
|
||||
2. Extract each image, OCR, and combine the output into a PDF. This
|
||||
loses the context in which images are used in the PDF, meaning that
|
||||
cropping, rotation and scaling of pages may be lost. Some scanned
|
||||
PDFs use multiple images segmented into black and white, grayscale
|
||||
and color regions, with stencil masks to prevent overlap, as this can
|
||||
enhance the appearance of a file while reducing file size. Clearly,
|
||||
reassembling these images will be easy. This also loses and text or
|
||||
vector art on any pages in a PDF with both scanned and pure digital
|
||||
content.
|
||||
|
||||
In the case of a PDF that is nothing other than a container of images
|
||||
(no rotation, scaling, cropping, one image per page), the second
|
||||
approach can be lossless.
|
||||
|
||||
OCRmyPDF uses several strategies depending on input options and the
|
||||
input PDF itself, but generally speaking it rasterizes a page for OCR
|
||||
and then grafts the OCR back onto the original. As such it can handle
|
||||
complex PDFs and still preserve their contents as much as possible.
|
||||
|
||||
OCRmyPDF also supports a many, many edge cases that have cropped over
|
||||
several years of development. We support PDF features like images inside
|
||||
of Form XObjects, and pages with UserUnit scaling. We support rare image
|
||||
formats like non-monochrome 1-bit images. We warn about files you may
|
||||
not to OCR. Thanks to pikepdf and QPDF, we auto-repair PDFs that are
|
||||
damaged. (Not that you need to know what any of these are! You should be
|
||||
able to throw any PDF at it.)
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
OCRmyPDF is limited by the Tesseract OCR engine. As such it experiences
|
||||
these limitations, as do any other programs that rely on Tesseract:
|
||||
|
||||
- The OCR is not as accurate as commercial solutions such as Abbyy.
|
||||
- It is not capable of recognizing handwriting.
|
||||
- It may find gibberish and report this as OCR output.
|
||||
- If a document contains languages outside of those given in the
|
||||
``-l LANG`` arguments, results may be poor.
|
||||
- It is not always good at analyzing the natural reading order of
|
||||
documents. For example, it may fail to recognize that a document
|
||||
contains two columns, and may try to join text across columns.
|
||||
- Poor quality scans may produce poor quality OCR. Garbage in, garbage
|
||||
out.
|
||||
- It does not expose information about what font family text belongs
|
||||
to.
|
||||
|
||||
OCRmyPDF is also limited by the PDF specification:
|
||||
|
||||
- PDF encodes the position of text glyphs but does not encode document
|
||||
structure. There is no markup that divides a document in sections,
|
||||
paragraphs, sentences, or even words (since blank spaces are not
|
||||
represented). As such all elements of document structure including
|
||||
the spaces between words must be derived heuristically. Some PDF
|
||||
viewers do a better job of this than others.
|
||||
- Because some popular open source PDF viewers have a particularly hard
|
||||
time with spaces between words, OCRmyPDF appends a space to each text
|
||||
element as a workaround (when using ``--pdf-renderer hocr``). While
|
||||
this mixes document structure with graphical information that ideally
|
||||
should be left to the PDF viewer to interpret, it improves
|
||||
compatibility with some viewers and does not cause problems for
|
||||
better ones.
|
||||
|
||||
Ghostscript also imposes some limitations:
|
||||
|
||||
- PDFs containing JBIG2-encoded content will be converted to CCITT
|
||||
Group4 encoding, which has lower compression ratios, if Ghostscript
|
||||
PDF/A is enabled.
|
||||
- PDFs containing JPEG 2000-encoded content will be converted to JPEG
|
||||
encoding, which may introduce compression artifacts, if Ghostscript
|
||||
PDF/A is enabled.
|
||||
- Ghostscript may transcode grayscale and color images, either lossy to
|
||||
lossless or lossless to lossy, based on an internal algorithm. This
|
||||
behavior can be suppressed by setting ``--pdfa-image-compression`` to
|
||||
``jpeg`` or ``lossless`` to set all images to one type or the other.
|
||||
Ghostscript has no option to maintain the input image's format.
|
||||
(Ghostscript 9.25+ can copy JPEG images without transcoding them;
|
||||
earlier versions will transcode.)
|
||||
- Ghostscript's PDF/A conversion removes any XMP metadata that is not
|
||||
one of the standard XMP metadata namespaces for PDFs. In particular,
|
||||
PRISM Metdata is removed.
|
||||
- Ghostscript's PDF/A conversion seems to remove or deactivate
|
||||
hyperlinks and other active content.
|
||||
|
||||
You can use ``--output-type pdf`` to disable PDF/A conversion and produce
|
||||
a standard, non-archival PDF.
|
||||
|
||||
Regarding OCRmyPDF itself:
|
||||
|
||||
- PDFs that use transparency are not currently represented in the test
|
||||
suite
|
||||
|
||||
Similar programs
|
||||
================
|
||||
|
||||
To the author's knowledge, OCRmyPDF is the most feature-rich and
|
||||
thoroughly tested command line OCR PDF conversion tool. If it does not
|
||||
meet your needs, contributions and suggestions are welcome. If not,
|
||||
consider one of these similar open source programs:
|
||||
|
||||
- pdf2pdfocr
|
||||
- pdfsandwich
|
||||
- pypdfocr
|
||||
- pdfbeads
|
||||
|
||||
Web front-ends
|
||||
==============
|
||||
|
||||
The Docker image ``ocrmypdf`` provides a web service front-end
|
||||
that allows files to submitted over HTTP and the results "downloaded".
|
||||
This is an HTTP server intended to simplify web services deployments; it
|
||||
is not intended to be deployed on the public internet and no real
|
||||
security measures to speak of.
|
||||
|
||||
In addition, the following third-party integrations are available:
|
||||
|
||||
- `Nextcloud OCR <https://github.com/janis91/ocr>`__ is a free software
|
||||
plugin for the Nextcloud private cloud software
|
||||
|
||||
OCRmyPDF is not designed to be secure against malware-bearing PDFs (see
|
||||
`Using OCRmyPDF online <ocr-service>`__). Users should ensure they
|
||||
comply with OCRmyPDF's licenses and the licenses of all dependencies. In
|
||||
particular, OCRmyPDF requires Ghostscript, which is licensed under
|
||||
AGPLv3.
|
||||
|
||||
.. |image| image:: images/bitmap_vs_svg.svg
|
||||
@@ -0,0 +1,55 @@
|
||||
.. _jbig2:
|
||||
|
||||
============================
|
||||
Installing the JBIG2 encoder
|
||||
============================
|
||||
|
||||
Most Linux distributions do not include a JBIG2 encoder since JBIG2
|
||||
encoding was patented for a long time. All known JBIG2 US patents have
|
||||
expired as of 2017, but it is possible that unknown patents exist.
|
||||
|
||||
JBIG2 encoding is recommended for OCRmyPDF and is used to losslessly
|
||||
create smaller PDFs. If JBIG2 encoding not available, lower quality
|
||||
encodings will be used.
|
||||
|
||||
JBIG2 decoding is not patented and is performed automatically by most
|
||||
PDF viewers. It is widely supported has been part of the PDF
|
||||
specification since 2001.
|
||||
|
||||
On macOS, Homebrew packages jbig2enc and OCRmyPDF includes it by
|
||||
default. The Docker image for OCRmyPDF also builds its own JBIG2 encoder
|
||||
from source.
|
||||
|
||||
For all other Linux, you must build a JBIG2 encoder from source:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/agl/jbig2enc
|
||||
cd jbig2enc
|
||||
./autogen.sh
|
||||
./configure && make
|
||||
[sudo] make install
|
||||
|
||||
.. _jbig2-lossy:
|
||||
|
||||
Lossy mode JBIG2
|
||||
================
|
||||
|
||||
OCRmyPDF provides lossy mode JBIG2 as an advanced feature. Users should
|
||||
`review the technical concerns with JBIG2 in lossy
|
||||
mode <https://abbyy.technology/en:kb:tip:jbig2_compression_and_ocr>`__
|
||||
and decide if this feature is acceptable for their use case.
|
||||
|
||||
JBIG2 lossy mode does achieve higher compression ratios than any other
|
||||
monochrome (bitonal) compression technology; for large text documents
|
||||
the savings are considerable. JBIG2 lossless still gives great
|
||||
compression ratios and is a major improvement over the older CCITT G4
|
||||
standard. As explained above, there is some risk of substitution errors.
|
||||
|
||||
To turn on JBIG2 lossy mode, add the argument ``--jbig2-lossy``.
|
||||
``--optimize {1,2,3}`` are necessary for the argument to take effect
|
||||
also required. Also, a JBIG2 encoder must be installed as described in
|
||||
the previous section.
|
||||
|
||||
*Due to an oversight, ocrmypdf v7.0 and v7.1 used lossy mode by
|
||||
default.*
|
||||
@@ -0,0 +1,76 @@
|
||||
.. _lang-packs:
|
||||
|
||||
====================================
|
||||
Installing additional language packs
|
||||
====================================
|
||||
|
||||
OCRmyPDF uses Tesseract for OCR, and relies on its language packs for all languages.
|
||||
On most platforms, English is installed with Tesseract by default, but not always.
|
||||
|
||||
Tesseract supports `most
|
||||
languages <https://github.com/tesseract-ocr/tesseract/blob/master/doc/tesseract.1.asc#languages>`__.
|
||||
Languages are identified by standardized three-letter codes (called ISO 639-2 Alpha-3).
|
||||
Tesseract's documentation also lists the three-letter code for your language.
|
||||
Some are anglicized, e.g. Spanish is ``spa`` rather than ``esp``, while others
|
||||
are not, e.g. German is ``deu``.
|
||||
|
||||
After you have installed a language pack, you can use it ``ocrmypdf -l <language>``,
|
||||
for example ``ocrmypdf -l spa``. For multilingual documents, you can specify
|
||||
all languages to be expected, e.g. ``ocrmypdf -l eng+fra`` for English and French.
|
||||
English is assumed by default unless other language(s) are specified.
|
||||
|
||||
For Linux users, you can often find packages that provide language
|
||||
packs:
|
||||
|
||||
Debian and Ubuntu users
|
||||
=======================
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Display a list of all Tesseract language packs
|
||||
apt-cache search tesseract-ocr
|
||||
|
||||
# Install Chinese Simplified language pack
|
||||
apt-get install tesseract-ocr-chi-sim
|
||||
|
||||
You can then pass the ``-l LANG`` argument to OCRmyPDF to give a hint as
|
||||
to what languages it should search for. Multiple languages can be
|
||||
requested using either ``-l eng+fre`` (English and French) or
|
||||
``-l eng -l fre``.
|
||||
|
||||
Fedora users
|
||||
============
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Display a list of all Tesseract language packs
|
||||
dnf search tesseract
|
||||
|
||||
# Install Chinese Simplified language pack
|
||||
dnf install tesseract-langpack-chi_sim
|
||||
|
||||
You can then pass the ``-l LANG`` argument to OCRmyPDF to give a hint as
|
||||
to what languages it should search for. Multiple languages can be
|
||||
requested using either ``-l eng+fre`` (English and French) or
|
||||
``-l eng -l fre``.
|
||||
|
||||
macOS users
|
||||
===========
|
||||
|
||||
You can install additional language packs by
|
||||
:ref:`installing Tesseract using Homebrew with all language packs <macos-all-languages>`.
|
||||
|
||||
Docker users
|
||||
============
|
||||
|
||||
Users of the OCRmyPDF Docker image should install language packs into a
|
||||
derived Docker image as
|
||||
:ref:`described in that section <docker-lang-packs>`.
|
||||
|
||||
Windows users
|
||||
=============
|
||||
|
||||
The Tesseract installer provided by Chocolatey currently includes only English language.
|
||||
To install other languages, download the respective language pack (``.traineddata`` file)
|
||||
from https://github.com/tesseract-ocr/tessdata/ and place it in
|
||||
``C:\\Program Files\\Tesseract-OCR\\tessdata`` (or wherever Tesseract OCR is installed).
|
||||
@@ -0,0 +1,75 @@
|
||||
================
|
||||
PDF optimization
|
||||
================
|
||||
|
||||
OCRmyPDF includes an image-oriented PDF optimizer. By default, the optimizer
|
||||
runs with safe settings with the goal of improving compression at no loss of
|
||||
quality. At higher optimization levels, lossy optimizations may be applied and
|
||||
tuned. Optimization occurs after OCR, and only if OCR succeeded. It does not
|
||||
perform other possible optimizations such as deduplicating resources,
|
||||
consolidating fonts, simplifying vector drawings, or anything of that nature.
|
||||
|
||||
Optimization ranges from ``-O0`` through ``-O3``, where ``0`` disables
|
||||
optimization and ``3`` implements all options. ``1``, the default, performs only
|
||||
safe and lossless optimizations. (This is similar to GCC's optimization
|
||||
parameter.) The exact type of optimizations performed will vary over time.
|
||||
|
||||
PDF optimization requires third-party, optional tools for certain optimizations.
|
||||
If these are not installed or cannot be found by OCRmyPDF, optimization will not
|
||||
be as good.
|
||||
|
||||
Optimizations that always occurs
|
||||
================================
|
||||
|
||||
OCRmyPDF will automatically replace obsolete or inferior compression schemes
|
||||
such as RLE or LZW with superior schemes such as Deflate and converting
|
||||
monochrome images to CCITT G4. Since this is harmless it always occurs and there
|
||||
is no way to disable it. Other non-image compressed objects are compressed as
|
||||
well.
|
||||
|
||||
Fast web view
|
||||
=============
|
||||
|
||||
OCRmyPDF automatically optimizes PDFs for "fast web view" in Adobe Acrobat's
|
||||
parlance, or equivalently, linearizes PDFs so that the resources they reference
|
||||
are presented in the order a viewer needs them for sequential display. This
|
||||
reduces the latency of viewing a PDF both online and from local storage. This
|
||||
actually slightly increases the file size.
|
||||
|
||||
To disable this optimization and all others, use ``ocrmypdf --optimize 0 ...``
|
||||
or the shorthand ``-O0``.
|
||||
|
||||
Lossless optimizations
|
||||
======================
|
||||
|
||||
At optimization level ``-O1`` (the default), OCRmyPDF will also attempt lossless
|
||||
image optimization.
|
||||
|
||||
If a JBIG2 encoder is available, then monochrome images will be converted to
|
||||
JBIG2, with the potential for huge savings on large black and white images,
|
||||
since JBIG2 is far more efficient than any other monochrome (bi-level)
|
||||
compression. (All known US patents related to JBIG2 have probably expired, but
|
||||
it remains the responsibility of the user to supply a JBIG2 encoder such as
|
||||
`jbig2enc <https://github.com/agl/jbig2enc>`__. OCRmyPDF does not implement
|
||||
JBIG2 encoding on its own.)
|
||||
|
||||
OCRmyPDF currently does not attempt to recompress losslessly compressed objects
|
||||
more aggressively.
|
||||
|
||||
Lossy optimizations
|
||||
===================
|
||||
|
||||
At optimization level ``-O2`` and ``-O3``, OCRmyPDF will some attempt lossy
|
||||
image optimization.
|
||||
|
||||
If ``pngquant`` is installed, OCRmyPDF will use it to perform quantize paletted
|
||||
images to reduce their size.
|
||||
|
||||
The quality of JPEGs may be lowered, on the assumption that a lower quality
|
||||
image may be suitable for storage after OCR.
|
||||
|
||||
It is not possible to optimize all image types. Uncommon image types may be
|
||||
skipped by the optimizer.
|
||||
|
||||
OCRmyPDF provides :ref:`lossy mode JBIG2 <jbig2-lossy>` as an advanced feature
|
||||
that additional requires the argument ``--jbig2-lossy``.
|
||||
@@ -0,0 +1,161 @@
|
||||
===================
|
||||
PDF security issues
|
||||
===================
|
||||
|
||||
OCRmyPDF should only be used on PDFs you trust. It is not designed to
|
||||
protect you against malware.
|
||||
|
||||
Recognizing that many users have an interest in handling PDFs and
|
||||
applying OCR to PDFs they did not generate themselves, this article
|
||||
discusses the security implications of PDFs and how users can protect
|
||||
themselves.
|
||||
|
||||
The disclaimer applies: this software has no warranties of any kind.
|
||||
|
||||
PDFs may contain malware
|
||||
========================
|
||||
|
||||
PDF is a rich, complex file format. The official PDF 1.7 specification,
|
||||
ISO 32000:2008, is hundreds of pages long and references several annexes
|
||||
each of which are similar in length. PDFs can contain video, audio, XML,
|
||||
JavaScript and other programming, and forms. In some cases, they can
|
||||
open internet connections to pre-selected URLs. All of these possible
|
||||
attack vectors.
|
||||
|
||||
In short, PDFs `may contain
|
||||
viruses <https://security.stackexchange.com/questions/64052/can-a-pdf-file-contain-a-virus>`__.
|
||||
|
||||
This
|
||||
`article <https://theinvisiblethings.blogspot.ca/2013/02/converting-untrusted-pdfs-into-trusted.html>`__
|
||||
describes a high-paranoia method which allows potentially hostile PDFs
|
||||
to be viewed and rasterized safely in a disposable virtual machine. A
|
||||
trusted PDF created in this manner is converted to images and loses all
|
||||
information making it searchable and losing all compression. OCRmyPDF
|
||||
could be used restore searchability.
|
||||
|
||||
How OCRmyPDF processes PDFs
|
||||
===========================
|
||||
|
||||
OCRmyPDF must open and interpret your PDF in order to insert an OCR
|
||||
layer. First, it runs all PDFs through
|
||||
`pikepdf <https://github.com/pikepdf/pikepdf>`__, a library based on
|
||||
`qpdf <https://github.com/qpdf/qpdf>`__, a program that repairs PDFs
|
||||
with syntax errors. This is done because, in the author's experience, a
|
||||
significant number of PDFs in the wild especially those created by
|
||||
scanners are not well-formed files. qpdf makes it more likely that
|
||||
OCRmyPDF will succeed, but offers no security guarantees. qpdf is also
|
||||
used to split the PDF into single page PDFs.
|
||||
|
||||
Finally, OCRmyPDF rasterizes each page of the PDF using
|
||||
`Ghostscript <http://ghostscript.com/>`__ in ``-dSAFER`` mode.
|
||||
|
||||
Depending on the options specified, OCRmyPDF may graft the OCR layer
|
||||
into the existing PDF or it may essentially reconstruct ("re-fry") a
|
||||
visually identical PDF that may be quite different at the binary level.
|
||||
That said, OCRmyPDF is not a tool designed for sanitizing PDFs.
|
||||
|
||||
.. _ocr-service:
|
||||
|
||||
Using OCRmyPDF online or as a service
|
||||
=====================================
|
||||
|
||||
OCRmyPDF is not designed for use as a public web service where a
|
||||
malicious user could upload a chosen PDF. In particular, it is not
|
||||
necessarily secure against PDF malware or PDFs that cause denial of
|
||||
service. OCRmyPDF relies on Ghostscript, and therefore, if deployed
|
||||
online one should be prepared to comply with Ghostscript's Affero GPL
|
||||
license, and any other licenses.
|
||||
|
||||
Setting aside these concerns, a side effect of OCRmyPDF is it may
|
||||
incidentally sanitize PDFs that contain certain types of malware. It
|
||||
repairs the PDF with pikepdf/libqpdf, which could correct malformed PDF
|
||||
structures that are part of an attack. When PDF/A output is selected
|
||||
(the default), the input PDF is partially reconstructed by Ghostscript.
|
||||
When ``--force-ocr`` is used, all pages are rasterized and reconverted
|
||||
to PDF, which could remove malware in embedded images.
|
||||
|
||||
OCRmyPDF should be relatively safe to use in a trusted intranet, with
|
||||
some considerations:
|
||||
|
||||
Limiting CPU usage
|
||||
------------------
|
||||
|
||||
OCRmyPDF will attempt to use all available CPUs and storage, so
|
||||
executing ``nice ocrmypdf`` or limiting the number of jobs with the
|
||||
``-j`` argument may ensure the server remains available. Another option
|
||||
would be run OCRmyPDF jobs inside a Docker container, a virtual machine,
|
||||
or a cloud instance, which can impose its own limits on CPU usage and be
|
||||
terminated "from orbit" if it fails to complete.
|
||||
|
||||
Temporary storage requirements
|
||||
------------------------------
|
||||
|
||||
OCRmyPDF will use a large amount of temporary storage for its work,
|
||||
proportional to the total number of pixels needed to rasterize the PDF.
|
||||
The raster image of a 8.5×11" color page at 300 DPI takes 25 MB
|
||||
uncompressed; OCRmyPDF saves its intermediates as PNG, but that still
|
||||
means it requires about 9 MB per intermediate based on average
|
||||
compression ratios. Multiple intermediates per page are also required,
|
||||
depending on the command line given. A rule of thumb would be to allow
|
||||
100 MB of temporary storage per page in a file – meaning that a small
|
||||
cloud servers or small VM partitions should be provisioned with plenty
|
||||
of extra space, if say, a 500 page file might be sent.
|
||||
|
||||
To check temporary storage usage on actual files, run
|
||||
``ocrmypdf -k ...`` which will preserve and print the path to temporary
|
||||
storage when the job is done.
|
||||
|
||||
To change where temporary files are stored, change the ``TMPDIR``
|
||||
environment variable for ocrmypdf's environment. (Python's
|
||||
``tempfile.gettempdir()`` returns the root directory in which temporary
|
||||
files will be stored.) For example, one could redirect ``TMPDIR`` to a
|
||||
large RAM disk to avoid wear on HDD/SSD and potentially improve
|
||||
performance. On Amazon Web Services, ``TMPDIR`` can be set to `empheral
|
||||
storage <https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html>`__.
|
||||
|
||||
Timeouts
|
||||
--------
|
||||
|
||||
To prevent excessively long OCR jobs consider setting
|
||||
``--tesseract-timeout`` and/or ``--skip-big`` arguments. ``--skip-big``
|
||||
is particularly helpful if your PDFs include documents such as reports
|
||||
on standard page sizes with large images attached - often large images
|
||||
are not worth OCR'ing anyway.
|
||||
|
||||
Commercial alternatives
|
||||
-----------------------
|
||||
|
||||
The author also provides professional services that include OCR and
|
||||
building databases around PDFs, and is happy to provide consultation.
|
||||
|
||||
Abbyy Cloud OCR is a viable commercial alternative with a web services
|
||||
API.
|
||||
|
||||
Password protection, digital signatures and certification
|
||||
=========================================================
|
||||
|
||||
Password protected PDFs usually have two passwords, and owner and user
|
||||
password. When the user password is set to empty, PDF readers will open
|
||||
the file automatically and marked it as "(SECURED)". While not as
|
||||
reliable as a digital signature, this indicates that whoever set the
|
||||
password approved of the file at that time. When the user password is
|
||||
set, the document cannot be viewed without the password.
|
||||
|
||||
Either way, OCRmyPDF does not remove passwords from PDFs and exits with
|
||||
an error on encountering them.
|
||||
|
||||
``qpdf`` can remove passwords. If the owner and user password are set, a
|
||||
password is required for ``qpdf``. If only the owner password is set, then the
|
||||
password can be stripped, even if one does not have the owner password.
|
||||
|
||||
After OCR is applied, password protection is not permitted on PDF/A
|
||||
documents but the file can be converted to regular PDF.
|
||||
|
||||
Many programs exist which are capable of inserting an image of someone's
|
||||
signature. On its own, this offers no security guarantees. It is trivial
|
||||
to remove the signature image and apply it to other files. This practice
|
||||
offers no real security.
|
||||
|
||||
Important documents can be digitally signed and certified to attest to
|
||||
their authorship. OCRmyPDF cannot do this. Open source tools such as
|
||||
pdfbox (Java) have this capability as does Adobe Acrobat.
|
||||
@@ -0,0 +1,22 @@
|
||||
===========
|
||||
Performance
|
||||
===========
|
||||
|
||||
Some users have noticed that current versions of OCRmyPDF do not run as quickly
|
||||
as some older versions (specifically 6.x and older). This is because OCRmyPDF
|
||||
added image optimization as a postprocessing step, and it is enabled by default.
|
||||
|
||||
Speed
|
||||
=====
|
||||
|
||||
If running OCRmyPDF quickly is your main goal, you can use settings such as:
|
||||
|
||||
* ``--optimize 0`` to disable file size optimization
|
||||
* ``--output-type pdf`` to disable PDF/A generation
|
||||
* ``--fast-web-view 0`` to disable fast web view optimization
|
||||
* ``--skip-big`` to skip large images, if some pages have large images
|
||||
|
||||
You can also avoid:
|
||||
|
||||
* ``--force-ocr``
|
||||
* Image preprocessing
|
||||
@@ -0,0 +1,392 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
|
||||
-->
|
||||
<!-- Title: Pipeline: Pages: 1 -->
|
||||
<svg width="1484pt" height="1277pt"
|
||||
viewBox="0.00 0.00 1484.00 1277.20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1273.1977)">
|
||||
<title>Pipeline:</title>
|
||||
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-1273.1977 1480,-1273.1977 1480,4 -4,4"/>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>clustertasks</title>
|
||||
<polygon fill="none" stroke="#000000" points="8,-8 8,-1261.1977 1468,-1261.1977 1468,-8 8,-8"/>
|
||||
<text text-anchor="middle" x="738" y="-1233.1977" font-family="Times,serif" font-size="30.00" fill="#ff3232">Pipeline:</text>
|
||||
</g>
|
||||
<!-- t0 -->
|
||||
<g id="node1" class="node">
|
||||
<title>t0</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1215.7053,-1215.1977 1006.2947,-1215.1977 1002.2947,-1211.1977 1002.2947,-1179.1977 1211.7053,-1179.1977 1215.7053,-1183.1977 1215.7053,-1215.1977"/>
|
||||
<polyline fill="none" stroke="#000000" points="1211.7053,-1211.1977 1002.2947,-1211.1977 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1211.7053,-1211.1977 1211.7053,-1179.1977 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1211.7053,-1211.1977 1215.7053,-1215.1977 "/>
|
||||
<text text-anchor="middle" x="1109" y="-1191.1977" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.triage</text>
|
||||
</g>
|
||||
<!-- t1 -->
|
||||
<g id="node2" class="node">
|
||||
<title>t1</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1280.0433,-1157.1977 941.9567,-1157.1977 937.9567,-1153.1977 937.9567,-1121.1977 1276.0433,-1121.1977 1280.0433,-1125.1977 1280.0433,-1157.1977"/>
|
||||
<polyline fill="none" stroke="#000000" points="1276.0433,-1153.1977 937.9567,-1153.1977 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1276.0433,-1153.1977 1276.0433,-1121.1977 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1276.0433,-1153.1977 1280.0433,-1157.1977 "/>
|
||||
<text text-anchor="middle" x="1109" y="-1133.1977" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.repair_and_parse_pdf</text>
|
||||
</g>
|
||||
<!-- t0->t1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>t0->t1</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1109,-1179.1641C1109,-1175.4895 1109,-1171.5395 1109,-1167.604"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1112.5001,-1167.4199 1109,-1157.4199 1105.5001,-1167.42 1112.5001,-1167.4199"/>
|
||||
</g>
|
||||
<!-- t2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>t2</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1030.0926,-1078.2732 785,-1095.1731 539.9074,-1078.2732 540.1362,-1050.9285 1029.8638,-1050.9285 1030.0926,-1078.2732"/>
|
||||
<polygon fill="none" stroke="#000000" points="1034.1249,-1082.0021 785,-1099.1801 535.8751,-1082.0021 536.1685,-1046.931 1033.8315,-1046.931 1034.1249,-1082.0021"/>
|
||||
<text text-anchor="middle" x="785" y="-1064.7153" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.marker_pages</text>
|
||||
</g>
|
||||
<!-- t1->t2 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>t1->t2</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1023.449,-1121.1152C984.5695,-1112.8974 938.0675,-1103.0685 896.4957,-1094.2816"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="897.1066,-1090.8335 886.5989,-1092.1898 895.6589,-1097.6822 897.1066,-1090.8335"/>
|
||||
</g>
|
||||
<!-- t16 -->
|
||||
<g id="node17" class="node">
|
||||
<title>t16</title>
|
||||
<polygon fill="#00cc66" stroke="#000000" points="1215.5059,-328.1861 942.4941,-328.1861 938.4941,-324.1861 938.4941,-292.1861 1211.5059,-292.1861 1215.5059,-296.1861 1215.5059,-328.1861"/>
|
||||
<polyline fill="none" stroke="#000000" points="1211.5059,-324.1861 938.4941,-324.1861 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1211.5059,-324.1861 1211.5059,-292.1861 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1211.5059,-324.1861 1215.5059,-328.1861 "/>
|
||||
<text text-anchor="middle" x="1077" y="-304.1861" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.weave_layers</text>
|
||||
</g>
|
||||
<!-- t1->t16 -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>t1->t16</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1097.2373,-1120.9576C1077.987,-1088.7184 1043.7317,-1019.7372 1063,-963.2656 1106.87,-834.6914 1482.8098,-573.3183 1409,-459.2656 1362.7595,-387.8137 1273.2613,-350.2799 1198.8305,-330.7528"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1199.4555,-327.3005 1188.9015,-328.2301 1197.7316,-334.0849 1199.4555,-327.3005"/>
|
||||
</g>
|
||||
<!-- t17 -->
|
||||
<g id="node18" class="node">
|
||||
<title>t17</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1439.5156,-1009.7492 1076.4844,-1009.7492 1072.4844,-1005.7492 1072.4844,-973.7492 1435.5156,-973.7492 1439.5156,-977.7492 1439.5156,-1009.7492"/>
|
||||
<polyline fill="none" stroke="#000000" points="1435.5156,-1005.7492 1072.4844,-1005.7492 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1435.5156,-1005.7492 1435.5156,-973.7492 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1435.5156,-1005.7492 1439.5156,-1009.7492 "/>
|
||||
<text text-anchor="middle" x="1256" y="-985.7492" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.generate_postscript_stub</text>
|
||||
</g>
|
||||
<!-- t1->t17 -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>t1->t17</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1127.0251,-1121.1176C1153.0342,-1095.0292 1201.2007,-1046.7157 1230.7429,-1017.0834"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1233.2458,-1019.5302 1237.8275,-1009.9772 1228.2885,-1014.5879 1233.2458,-1019.5302"/>
|
||||
</g>
|
||||
<!-- t18 -->
|
||||
<g id="node19" class="node">
|
||||
<title>t18</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1070.189,-214.4288 1263,-187.1099 1455.811,-214.4288 1455.631,-258.6317 1070.369,-258.6317 1070.189,-214.4288"/>
|
||||
<polygon fill="none" stroke="#000000" points="1066.1715,-210.9543 1263,-183.0662 1459.8285,-210.9543 1459.6181,-262.6353 1066.3819,-262.6353 1066.1715,-210.9543"/>
|
||||
<text text-anchor="middle" x="1263" y="-220.6461" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.metadata_fixup</text>
|
||||
</g>
|
||||
<!-- t1->t18 -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>t1->t18</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1241.1115,-1121.1192C1311.0076,-1105.2558 1393.5851,-1075.5895 1449,-1020.2329 1458.4922,-1010.7507 1459,-1005.1661 1459,-991.7492 1459,-991.7492 1459,-991.7492 1459,-393.7258 1459,-341.9727 1441.8377,-325.2216 1402,-292.1861 1390.9869,-283.0534 1378.4885,-274.871 1365.6104,-267.6415"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1367.1079,-264.4723 1356.6476,-262.7888 1363.775,-270.6279 1367.1079,-264.4723"/>
|
||||
</g>
|
||||
<!-- t3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>t3</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1015.5194,-999.3074 785,-1016.2081 554.4806,-999.3074 554.6958,-971.9616 1015.3042,-971.9616 1015.5194,-999.3074"/>
|
||||
<polygon fill="none" stroke="#000000" points="1019.5491,-1003.0204 785,-1020.2165 550.4509,-1003.0204 550.7267,-967.9639 1019.2733,-967.9639 1019.5491,-1003.0204"/>
|
||||
<text text-anchor="middle" x="785" y="-985.7492" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.ocr_or_skip</text>
|
||||
</g>
|
||||
<!-- t2->t3 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>t2->t3</title>
|
||||
<path fill="none" stroke="#0044a0" d="M785,-1046.5938C785,-1041.5635 785,-1036.139 785,-1030.7273"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="788.5001,-1030.4427 785,-1020.4427 781.5001,-1030.4428 788.5001,-1030.4427"/>
|
||||
</g>
|
||||
<!-- t4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>t4</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="889.3166,-941.2656 582.6834,-941.2656 578.6834,-937.2656 578.6834,-905.2656 885.3166,-905.2656 889.3166,-909.2656 889.3166,-941.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="885.3166,-937.2656 578.6834,-937.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="885.3166,-937.2656 885.3166,-905.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="885.3166,-937.2656 889.3166,-941.2656 "/>
|
||||
<text text-anchor="middle" x="734" y="-917.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.rasterize_preview</text>
|
||||
</g>
|
||||
<!-- t3->t4 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>t3->t4</title>
|
||||
<path fill="none" stroke="#0044a0" d="M767.1627,-967.797C762.8396,-961.9919 758.1927,-955.7519 753.7858,-949.8343"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="756.3465,-947.4129 747.5666,-941.483 750.7323,-951.5939 756.3465,-947.4129"/>
|
||||
</g>
|
||||
<!-- t5 -->
|
||||
<g id="node6" class="node">
|
||||
<title>t5</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1028.0824,-883.2656 769.9176,-883.2656 765.9176,-879.2656 765.9176,-847.2656 1024.0824,-847.2656 1028.0824,-851.2656 1028.0824,-883.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="1024.0824,-879.2656 765.9176,-879.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1024.0824,-879.2656 1024.0824,-847.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1024.0824,-879.2656 1028.0824,-883.2656 "/>
|
||||
<text text-anchor="middle" x="897" y="-859.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.orient_page</text>
|
||||
</g>
|
||||
<!-- t3->t5 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>t3->t5</title>
|
||||
<path fill="none" stroke="#0044a0" d="M869.1177,-967.8063C880.553,-961.0264 890.81,-952.3527 898,-941.2656 907.042,-927.3226 906.9457,-908.7053 904.5139,-893.387"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="907.914,-892.5383 902.5408,-883.4071 901.0469,-893.8961 907.914,-892.5383"/>
|
||||
</g>
|
||||
<!-- t4->t5 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>t4->t5</title>
|
||||
<path fill="none" stroke="#0044a0" d="M784.6807,-905.2319C801.0865,-899.3943 819.4462,-892.8614 836.4913,-886.7963"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="838.1026,-889.938 846.3506,-883.288 835.7559,-883.343 838.1026,-889.938"/>
|
||||
</g>
|
||||
<!-- t6 -->
|
||||
<g id="node7" class="node">
|
||||
<title>t6</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1064.7325,-825.2656 689.2675,-825.2656 685.2675,-821.2656 685.2675,-789.2656 1060.7325,-789.2656 1064.7325,-793.2656 1064.7325,-825.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="1060.7325,-821.2656 685.2675,-821.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1060.7325,-821.2656 1060.7325,-789.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1060.7325,-821.2656 1064.7325,-825.2656 "/>
|
||||
<text text-anchor="middle" x="875" y="-801.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.rasterize_with_ghostscript</text>
|
||||
</g>
|
||||
<!-- t5->t6 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>t5->t6</title>
|
||||
<path fill="none" stroke="#0044a0" d="M890.1597,-847.2319C888.6839,-843.3412 887.0909,-839.1417 885.5115,-834.9776"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="888.731,-833.5965 881.9119,-825.4878 882.186,-836.0791 888.731,-833.5965"/>
|
||||
</g>
|
||||
<!-- t13 -->
|
||||
<g id="node16" class="node">
|
||||
<title>t13</title>
|
||||
<polygon fill="#00cc66" stroke="#000000" points="1077,-515.2656 754.4141,-487.2656 1077,-459.2656 1399.5859,-487.2656 1077,-515.2656"/>
|
||||
<text text-anchor="middle" x="1077" y="-481.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.select_image_layer</text>
|
||||
</g>
|
||||
<!-- t5->t13 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>t5->t13</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1000.2704,-847.241C1031.2359,-840.6873 1060.5415,-832.9862 1074,-825.2656 1114.0954,-802.2644 1145,-795.4899 1145,-749.2656 1145,-749.2656 1145,-749.2656 1145,-633.2656 1145,-590.368 1154.8687,-575.2844 1135,-537.2656 1131.571,-530.7041 1126.8893,-524.6314 1121.6622,-519.1451"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1123.8989,-516.4405 1114.2626,-512.0367 1119.0494,-521.4885 1123.8989,-516.4405"/>
|
||||
</g>
|
||||
<!-- t7 -->
|
||||
<g id="node8" class="node">
|
||||
<title>t7</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="856.0801,-767.2656 431.9199,-767.2656 427.9199,-763.2656 427.9199,-731.2656 852.0801,-731.2656 856.0801,-735.2656 856.0801,-767.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="852.0801,-763.2656 427.9199,-763.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="852.0801,-763.2656 852.0801,-731.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="852.0801,-763.2656 856.0801,-767.2656 "/>
|
||||
<text text-anchor="middle" x="642" y="-743.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.preprocess_remove_background</text>
|
||||
</g>
|
||||
<!-- t6->t7 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>t6->t7</title>
|
||||
<path fill="none" stroke="#0044a0" d="M802.5546,-789.2319C777.7884,-783.067 749.9071,-776.1266 724.4138,-769.7806"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="724.95,-766.3073 714.4006,-767.288 723.259,-773.1 724.95,-766.3073"/>
|
||||
</g>
|
||||
<!-- t12 -->
|
||||
<g id="node15" class="node">
|
||||
<title>t12</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="742,-593.2656 358.1874,-565.2656 742,-537.2656 1125.8126,-565.2656 742,-593.2656"/>
|
||||
<text text-anchor="middle" x="742" y="-559.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.select_visible_page_image</text>
|
||||
</g>
|
||||
<!-- t6->t12 -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>t6->t12</title>
|
||||
<path fill="none" stroke="#0044a0" d="M875.1443,-789.1129C874.6867,-773.2956 872.5831,-750.0189 865,-731.2656 844.2991,-680.0716 804.0126,-630.4165 775.1838,-598.9641"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="777.4937,-596.3085 768.1202,-591.3701 772.3682,-601.076 777.4937,-596.3085"/>
|
||||
</g>
|
||||
<!-- t8 -->
|
||||
<g id="node9" class="node">
|
||||
<title>t8</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="732.6759,-709.2656 413.3241,-709.2656 409.3241,-705.2656 409.3241,-673.2656 728.6759,-673.2656 732.6759,-677.2656 732.6759,-709.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="728.6759,-705.2656 409.3241,-705.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="728.6759,-705.2656 728.6759,-673.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="728.6759,-705.2656 732.6759,-709.2656 "/>
|
||||
<text text-anchor="middle" x="571" y="-685.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.preprocess_deskew</text>
|
||||
</g>
|
||||
<!-- t7->t8 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>t7->t8</title>
|
||||
<path fill="none" stroke="#0044a0" d="M619.9243,-731.2319C613.9709,-726.3685 607.4267,-721.0226 601.115,-715.8666"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="603.2653,-713.1037 593.3065,-709.4878 598.8367,-718.5248 603.2653,-713.1037"/>
|
||||
</g>
|
||||
<!-- t7->t12 -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>t7->t12</title>
|
||||
<path fill="none" stroke="#0044a0" d="M717.0346,-731.1646C726.8757,-725.6884 735.7103,-718.5557 742,-709.2656 763.0291,-678.205 759.4083,-634.0888 752.8082,-602.8898"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="756.1481,-601.7976 750.487,-592.842 749.3278,-603.3733 756.1481,-601.7976"/>
|
||||
</g>
|
||||
<!-- t9 -->
|
||||
<g id="node10" class="node">
|
||||
<title>t9</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="712.8828,-651.2656 411.1172,-651.2656 407.1172,-647.2656 407.1172,-615.2656 708.8828,-615.2656 712.8828,-619.2656 712.8828,-651.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="708.8828,-647.2656 407.1172,-647.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="708.8828,-647.2656 708.8828,-615.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="708.8828,-647.2656 712.8828,-651.2656 "/>
|
||||
<text text-anchor="middle" x="560" y="-627.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.preprocess_clean</text>
|
||||
</g>
|
||||
<!-- t8->t9 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>t8->t9</title>
|
||||
<path fill="none" stroke="#0044a0" d="M567.5798,-673.2319C566.8624,-669.4493 566.0897,-665.3747 565.3216,-661.3247"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="568.7581,-660.6605 563.4559,-651.4878 561.8807,-661.9649 568.7581,-660.6605"/>
|
||||
</g>
|
||||
<!-- t8->t12 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>t8->t12</title>
|
||||
<path fill="none" stroke="#0044a0" d="M670.0045,-673.2618C693.2528,-667.2338 713.6919,-659.8307 722,-651.2656 734.1971,-638.6912 739.4901,-620.2051 741.6123,-603.5914"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="745.1041,-603.8427 742.5574,-593.5585 738.1349,-603.1862 745.1041,-603.8427"/>
|
||||
</g>
|
||||
<!-- t10 -->
|
||||
<g id="node11" class="node">
|
||||
<title>t10</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="340.1094,-583.2656 35.8906,-583.2656 31.8906,-579.2656 31.8906,-547.2656 336.1094,-547.2656 340.1094,-551.2656 340.1094,-583.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="336.1094,-579.2656 31.8906,-579.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="336.1094,-579.2656 336.1094,-547.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="336.1094,-579.2656 340.1094,-583.2656 "/>
|
||||
<text text-anchor="middle" x="186" y="-559.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.select_ocr_image</text>
|
||||
</g>
|
||||
<!-- t9->t10 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>t9->t10</title>
|
||||
<path fill="none" stroke="#0044a0" d="M460.7568,-615.2213C409.7279,-605.9434 347.4237,-594.6153 295.0537,-585.0935"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="295.5223,-581.6214 285.0575,-583.276 294.2701,-588.5085 295.5223,-581.6214"/>
|
||||
</g>
|
||||
<!-- t9->t12 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>t9->t12</title>
|
||||
<path fill="none" stroke="#0044a0" d="M608.2948,-615.2213C627.0226,-608.2242 648.8712,-600.0609 669.4134,-592.3859"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="670.9148,-595.5613 679.0573,-588.7826 668.4648,-589.004 670.9148,-595.5613"/>
|
||||
</g>
|
||||
<!-- t11 -->
|
||||
<g id="node12" class="node">
|
||||
<title>t11</title>
|
||||
<polygon fill="#00cc66" stroke="#000000" points="334.0996,-505.2656 19.9004,-505.2656 15.9004,-501.2656 15.9004,-469.2656 330.0996,-469.2656 334.0996,-473.2656 334.0996,-505.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="330.0996,-501.2656 15.9004,-501.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="330.0996,-501.2656 330.0996,-469.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="330.0996,-501.2656 334.0996,-505.2656 "/>
|
||||
<text text-anchor="middle" x="175" y="-481.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.ocr_tesseract_hocr</text>
|
||||
</g>
|
||||
<!-- t10->t11 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>t10->t11</title>
|
||||
<path fill="none" stroke="#0044a0" d="M183.4487,-547.1748C182.1254,-537.7914 180.4788,-526.1154 178.9917,-515.5701"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="182.4378,-514.9417 177.5755,-505.5285 175.5064,-515.9193 182.4378,-514.9417"/>
|
||||
</g>
|
||||
<!-- t15 -->
|
||||
<g id="node14" class="node">
|
||||
<title>t15</title>
|
||||
<polygon fill="#ff69b4" stroke="#000000" points="736.2696,-505.2656 355.7304,-505.2656 351.7304,-501.2656 351.7304,-469.2656 732.2696,-469.2656 736.2696,-473.2656 736.2696,-505.2656"/>
|
||||
<polyline fill="none" stroke="#000000" points="732.2696,-501.2656 351.7304,-501.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="732.2696,-501.2656 732.2696,-469.2656 "/>
|
||||
<polyline fill="none" stroke="#000000" points="732.2696,-501.2656 736.2696,-505.2656 "/>
|
||||
<text text-anchor="middle" x="544" y="-481.2656" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.ocr_tesseract_textonly_pdf</text>
|
||||
</g>
|
||||
<!-- t10->t15 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>t10->t15</title>
|
||||
<path fill="none" stroke="#0044a0" d="M269.0322,-547.1748C323.4947,-535.3086 394.7854,-519.776 451.1284,-507.5002"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="452.0829,-510.8744 461.1086,-505.3257 450.5927,-504.0348 452.0829,-510.8744"/>
|
||||
</g>
|
||||
<!-- t14 -->
|
||||
<g id="node13" class="node">
|
||||
<title>t14</title>
|
||||
<polygon fill="#00cc66" stroke="#000000" points="330.0433,-411.7258 21.9567,-411.7258 17.9567,-407.7258 17.9567,-375.7258 326.0433,-375.7258 330.0433,-379.7258 330.0433,-411.7258"/>
|
||||
<polyline fill="none" stroke="#000000" points="326.0433,-407.7258 17.9567,-407.7258 "/>
|
||||
<polyline fill="none" stroke="#000000" points="326.0433,-407.7258 326.0433,-375.7258 "/>
|
||||
<polyline fill="none" stroke="#000000" points="326.0433,-407.7258 330.0433,-411.7258 "/>
|
||||
<text text-anchor="middle" x="174" y="-387.7258" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.render_hocr_page</text>
|
||||
</g>
|
||||
<!-- t11->t14 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>t11->t14</title>
|
||||
<path fill="none" stroke="#0044a0" d="M174.8072,-469.2302C174.6642,-455.8584 174.4666,-437.3702 174.3027,-422.0357"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="177.8024,-421.987 174.1956,-412.025 170.8028,-422.0619 177.8024,-421.987"/>
|
||||
</g>
|
||||
<!-- t19 -->
|
||||
<g id="node22" class="node">
|
||||
<title>t19</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="351.7205,-381.5085 545,-354.1897 738.2795,-381.5085 738.0991,-425.7112 351.9009,-425.7112 351.7205,-381.5085"/>
|
||||
<polygon fill="none" stroke="#000000" points="347.7033,-378.0329 545,-350.1463 742.2967,-378.0329 742.0858,-429.7148 347.9142,-429.7148 347.7033,-378.0329"/>
|
||||
<text text-anchor="middle" x="545" y="-387.7258" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.merge_sidecars</text>
|
||||
</g>
|
||||
<!-- t11->t19 -->
|
||||
<g id="edge32" class="edge">
|
||||
<title>t11->t19</title>
|
||||
<path fill="none" stroke="#0044a0" d="M246.3397,-469.2302C287.966,-458.7066 342.1269,-445.0142 392.8772,-432.184"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="393.8058,-435.5594 402.6429,-429.7151 392.0901,-428.773 393.8058,-435.5594"/>
|
||||
</g>
|
||||
<!-- t14->t16 -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>t14->t16</title>
|
||||
<path fill="none" stroke="#0044a0" d="M230.6615,-375.7128C262.2207,-366.4581 302.4172,-355.9425 339,-350.1861 448.3957,-332.9725 745.7869,-320.7866 927.9215,-314.6743"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="928.248,-318.1655 938.1258,-314.3342 928.0148,-311.1693 928.248,-318.1655"/>
|
||||
</g>
|
||||
<!-- t15->t16 -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>t15->t16</title>
|
||||
<path fill="none" stroke="#0044a0" d="M630.0636,-469.2083C667.5329,-460.6467 711.76,-449.5912 751,-437.2656 850.4985,-406.0121 963.1653,-359.5222 1026.586,-332.2894"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1028.1566,-335.4238 1035.9553,-328.2523 1025.3866,-328.9951 1028.1566,-335.4238"/>
|
||||
</g>
|
||||
<!-- t15->t19 -->
|
||||
<g id="edge31" class="edge">
|
||||
<title>t15->t19</title>
|
||||
<path fill="none" stroke="#0044a0" d="M544.1928,-469.2302C544.2822,-460.8687 544.393,-450.5066 544.5035,-440.166"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="548.006,-439.9443 544.6132,-429.9075 541.0064,-439.8694 548.006,-439.9443"/>
|
||||
</g>
|
||||
<!-- t12->t13 -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>t12->t13</title>
|
||||
<path fill="none" stroke="#0044a0" d="M833.9833,-543.8486C879.0975,-533.3444 933.4556,-520.6879 979.3116,-510.0109"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="980.3156,-513.3709 989.2614,-507.6943 978.7282,-506.5532 980.3156,-513.3709"/>
|
||||
</g>
|
||||
<!-- t13->t16 -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>t13->t16</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1077,-459.2068C1077,-426.2624 1077,-371.9187 1077,-338.7552"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1080.5001,-338.3818 1077,-328.3819 1073.5001,-338.3819 1080.5001,-338.3818"/>
|
||||
</g>
|
||||
<!-- t16->t18 -->
|
||||
<g id="edge27" class="edge">
|
||||
<title>t16->t18</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1117.3592,-292.0592C1133.8695,-284.6437 1153.6803,-275.7459 1173.2953,-266.9361"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1174.8979,-270.0531 1182.586,-262.7632 1172.0299,-263.6676 1174.8979,-270.0531"/>
|
||||
</g>
|
||||
<!-- t17->t18 -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>t17->t18</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1326.2292,-973.7283C1377.8362,-955.768 1439,-922.4247 1439,-865.2656 1439,-865.2656 1439,-865.2656 1439,-393.7258 1439,-338.7092 1393.2056,-296.3464 1348.3356,-268.0433"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1350.0403,-264.9831 1339.6842,-262.7465 1346.3852,-270.9531 1350.0403,-264.9831"/>
|
||||
</g>
|
||||
<!-- t20 -->
|
||||
<g id="node20" class="node">
|
||||
<title>t20</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1400.3184,-161.1062 1129.6816,-161.1062 1125.6816,-157.1062 1125.6816,-125.1062 1396.3184,-125.1062 1400.3184,-129.1062 1400.3184,-161.1062"/>
|
||||
<polyline fill="none" stroke="#000000" points="1396.3184,-157.1062 1125.6816,-157.1062 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1396.3184,-157.1062 1396.3184,-125.1062 "/>
|
||||
<polyline fill="none" stroke="#000000" points="1396.3184,-157.1062 1400.3184,-161.1062 "/>
|
||||
<text text-anchor="middle" x="1263" y="-137.1062" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.optimize_pdf</text>
|
||||
</g>
|
||||
<!-- t18->t20 -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>t18->t20</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1263,-182.9188C1263,-179.129 1263,-175.3607 1263,-171.739"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1266.5001,-171.4394 1263,-161.4394 1259.5001,-171.4394 1266.5001,-171.4394"/>
|
||||
</g>
|
||||
<!-- t21 -->
|
||||
<g id="node21" class="node">
|
||||
<title>t21</title>
|
||||
<polygon fill="#efa03b" stroke="#000000" points="1096.0652,-47.332 1263,-20.0049 1429.9348,-47.332 1429.779,-91.5483 1096.221,-91.5483 1096.0652,-47.332"/>
|
||||
<polygon fill="none" stroke="#000000" points="1092.0538,-43.9306 1263,-15.9468 1433.9462,-43.9306 1433.7643,-95.5532 1092.2357,-95.5532 1092.0538,-43.9306"/>
|
||||
<text text-anchor="middle" x="1263" y="-53.5531" font-family="Times,serif" font-size="20.00" fill="#000000">ocrmypdf.pipeline.copy_final</text>
|
||||
</g>
|
||||
<!-- t20->t21 -->
|
||||
<g id="edge30" class="edge">
|
||||
<title>t20->t21</title>
|
||||
<path fill="none" stroke="#0044a0" d="M1263,-124.9764C1263,-119.37 1263,-112.9163 1263,-106.2938"/>
|
||||
<polygon fill="#0044a0" stroke="#0044a0" points="1266.5001,-105.8456 1263,-95.8457 1259.5001,-105.8457 1266.5001,-105.8456"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,200 @@
|
||||
=======
|
||||
Plugins
|
||||
=======
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
|
||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
|
||||
"OPTIONAL" in this document are to be interpreted as described in
|
||||
RFC 2119.
|
||||
|
||||
You can use plugins to customize the behavior of OCRmyPDF at certain points of
|
||||
interest.
|
||||
|
||||
Currently, it is possible to:
|
||||
|
||||
- add new command line arguments
|
||||
- override the decision for whether or not to perform OCR on a particular file
|
||||
- modify the image is about to be sent for OCR
|
||||
- modify the page image before it is converted to PDF
|
||||
- replace the Tesseract OCR with another OCR engine that has similar behavior
|
||||
- replace Ghostscript with another PDF to image converter (rasterizer) or
|
||||
PDF/A generator
|
||||
|
||||
OCRmyPDF plugins are based on the Python ``pluggy`` package and conform to its
|
||||
conventions. Note that: plugins installed with as setuptools entrypoints are
|
||||
not checked currently, because OCRmyPDF assumes you may not want to enable
|
||||
plugins for all files.
|
||||
|
||||
Script plugins
|
||||
==============
|
||||
|
||||
Script plugins may be called from the command line, by specifying the name of a file.
|
||||
Script plugins may be convenient for informal or "one-off" plugins, when a certain
|
||||
batch of files needs a special processing step for example.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --plugin ocrmypdf_example_plugin.py input.pdf output.pdf
|
||||
|
||||
Multiple plugins may be installed by issuing the ``--plugin`` argument multiple times.
|
||||
|
||||
Packaged plugins
|
||||
================
|
||||
|
||||
Installed plugins may be installed into the same virtual environment as OCRmyPDF
|
||||
is installed into. They may be invoked using Python standard module naming.
|
||||
If you are intending to distribute a plugin, please package it.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
ocrmypdf --plugin ocrmypdf_fancypants.pockets.contents input.pdf output.pdf
|
||||
|
||||
OCRmyPDF does not automatically import plugins, because the assumption is that
|
||||
plugins affect different files differently and you may not want them activated
|
||||
all the time. The command line or ``ocrmypdf.ocr(plugin='...')`` must call
|
||||
for them.
|
||||
|
||||
Third parties that wish to distribute packages for ocrmypdf should package them
|
||||
as packaged plugins, and these modules should begin with the name ``ocrmypdf_``
|
||||
similar to ``pytest`` packages such as ``pytest-cov`` (the package) and
|
||||
``pytest_cov`` (the module).
|
||||
|
||||
.. note::
|
||||
|
||||
We strongly recommend plugin authors name their plugins with the prefix
|
||||
``ocrmypdf-`` (for the package name on PyPI) and ``ocrmypdf_`` (for the
|
||||
module), just like pytest plugins.
|
||||
|
||||
Setuptools plugins
|
||||
==================
|
||||
|
||||
You can also create a plugin that OCRmyPDF will always automatically load if both are
|
||||
installed in the same virtual environment, using a setuptools entrypoint.
|
||||
|
||||
Your package's ``setup.py`` would need to contain the following, for a plugin
|
||||
named ``ocrmypdf-exampleplugin``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# sample ./setup.py file
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name="ocrmypdf-exampleplugin",
|
||||
packages=["exampleplugin"],
|
||||
# the following makes a plugin available to pytest
|
||||
entry_points={"ocrmypdf": ["exampleplugin = exampleplugin.pluginmodule"]},
|
||||
)
|
||||
|
||||
Plugin requirements
|
||||
===================
|
||||
|
||||
OCRmyPDF generally uses multiple worker processes. When a new worker is started,
|
||||
Python will import all plugins again, including all plugins that were imported earlier.
|
||||
This means that the global state of a plugin in one worker will not be shared with
|
||||
other workers. As such, plugin hook implementations should be stateless, relying
|
||||
only on their inputs. Hook implementations may use their input parameters to
|
||||
to obtain a reference to shared state prepared by another hook implementation.
|
||||
Plugins must expect that other instances of the plugin will be running
|
||||
simultaneously.
|
||||
|
||||
The ``context`` object that is passed to many hooks can be used to share information
|
||||
about a file being worked on. Plugins must write private, plugin-specific data to
|
||||
a subfolder named ``{options.work_folder}/ocrmypdf-plugin-name``. Plugins MAY
|
||||
read and write files in ``options.work_folder``, but should be aware that their
|
||||
semantics are subject to change.
|
||||
|
||||
OCRmyPDF will delete ``options.work_folder`` when it has finished OCRing
|
||||
a file, unless invoked with ``--keep-temporary-files``.
|
||||
|
||||
The documentation for some plugin hooks contain a detailed description of the
|
||||
execution context in which they will be called.
|
||||
|
||||
Plugins should be prepared to work whether executed in worker threads or worker
|
||||
processes. Generally, OCRmyPDF uses processes, but has a semi-hidden threaded
|
||||
argument that simplifies debugging.
|
||||
|
||||
|
||||
Plugin hooks
|
||||
============
|
||||
|
||||
A plugin may provide the following hooks. Hooks must be decorated with
|
||||
``ocrmypdf.hookimpl``, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from ocrmpydf import hookimpl
|
||||
|
||||
@hookimpl
|
||||
def add_options(parser):
|
||||
pass
|
||||
|
||||
The following is a complete list of hooks that are available, and when
|
||||
they are called.
|
||||
|
||||
.. _firstresult:
|
||||
|
||||
**Note on firstresult hooks**
|
||||
|
||||
If multiple plugins install implementations for this hook, they will be called in
|
||||
the reverse of the order in which they are installed (i.e., last plugin wins).
|
||||
When each hook implementation is called in order, the first implementation that
|
||||
returns a value other than ``None`` will "win" and prevent execution of all other
|
||||
hooks. As such, you cannot "chain" a series of plugin filters together in this
|
||||
way. Instead, a single hook implementation should be responsible for any such
|
||||
chaining operations.
|
||||
|
||||
Custom command line arguments
|
||||
-----------------------------
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.add_options
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.check_options
|
||||
|
||||
Execution and progress reporting
|
||||
--------------------------------
|
||||
|
||||
.. autoclass: ocrmypdf.pluginspec.Executor
|
||||
:members:
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.get_logging_console
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.get_executor
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.get_progressbar_class
|
||||
|
||||
Applying special behavior before processing
|
||||
-------------------------------------------
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.validate
|
||||
|
||||
PDF page to image
|
||||
-----------------
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.rasterize_pdf_page
|
||||
|
||||
Modifying intermediate images
|
||||
-----------------------------
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.filter_ocr_image
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.filter_page_image
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.filter_pdf_page
|
||||
|
||||
OCR engine
|
||||
----------
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.get_ocr_engine
|
||||
|
||||
.. autoclass:: ocrmypdf.pluginspec.OcrEngine
|
||||
:members:
|
||||
|
||||
.. automethod:: __str__
|
||||
|
||||
.. autoclass:: ocrmypdf.pluginspec.OrientationConfidence
|
||||
|
||||
PDF/A production
|
||||
----------------
|
||||
|
||||
.. autofunction:: ocrmypdf.pluginspec.generate_pdfa
|
||||
File diff suppressed because it is too large
Load Diff
-502
@@ -1,502 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
@@ -1,17 +0,0 @@
|
||||
JHOVE - JSTOR/Harvard Object Validation Environment
|
||||
Copyright 2003-2008 by JSTOR and the President and Fellows of Harvard College
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lessor General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA
|
||||
-227
@@ -1,227 +0,0 @@
|
||||
JHOVE - JSTOR/Harvard Object Validation Environment
|
||||
Copyright 2003-2012 by JSTOR and the President and Fellows of Harvard College
|
||||
JHOVE is made available under the GNU Lesser General Public License (LGPL;
|
||||
see the file LICENSE for details)
|
||||
|
||||
Rev. 1.9, 2012-12-17
|
||||
|
||||
JHOVE (the JSTOR/Harvard Object Validation Environment, pronounced "jhove")
|
||||
is an extensible software framework for performing format identification,
|
||||
validation, and characterization of digital objects.
|
||||
|
||||
o Format identification is the process of determining the format to which a
|
||||
digital object conforms: "I have a digital object; what format is it?"
|
||||
o Format validation is the process of determining the level of compliance of a
|
||||
digital object to the specification for its purported format: "I have an
|
||||
object purportedly of format F; is it?"
|
||||
o Format characterization is the process of determing the format-specific
|
||||
significant properties of an object of a given format: "I have an object of
|
||||
format F; what are its salient properties?"
|
||||
|
||||
These actions are frequently necessary during routine operation of digital
|
||||
repositories and for digital preservation activities.
|
||||
|
||||
The output from JHOVE is controlled by output handlers. JHOVE uses an
|
||||
extensible plug-in architecture; it can be configured at the time of its
|
||||
invocation to include whatever specific format modules and output handlers
|
||||
that are desired. The initial release of JHOVE includes modules for
|
||||
arbitrary byte streams, ASCII and UTF-8 encoded text, AIFF and WAVE audio,
|
||||
GIF, JPEG, JPEG 2000, TIFF, and PDF; and text and XML output handlers.
|
||||
|
||||
The JHOVE project is a collaboration of JSTOR and the Harvard University
|
||||
Library. Development of JHOVE was funded in part by the Andrew W. Mellon
|
||||
Foundation. JHOVE is made available under the GNU Lesser General Public
|
||||
License (LGPL; see the file LICENSE for details).
|
||||
|
||||
JHOVE is currently being maintained by indpendent developers.
|
||||
|
||||
REQUIREMENTS
|
||||
|
||||
1. Java J2SE 1.5
|
||||
(JHOVE was originally implemented using the Sun J2SE SDK 1.4.1 and has
|
||||
been tested to work with 1.5)
|
||||
|
||||
2. If you would like to compile the JHOVE source code, then
|
||||
Apache Ant, a Java-based build tool <http://ant.apache.org/> is necessary.
|
||||
Note that the JAVA_HOME environment variable must be set appropriately for
|
||||
Ant to work properly.
|
||||
(JHOVE was implemented and tested using Ant 1.5.1.)
|
||||
|
||||
DISTRIBUTION
|
||||
|
||||
The JHOVE distribution package includes:
|
||||
|
||||
jhove/ # JHOVE home directory
|
||||
COPYING # GNU Lesser General Public License
|
||||
LICENSE # JHOVE license information
|
||||
README
|
||||
RELEASENOTES # JHOVE release notes
|
||||
bin/
|
||||
jhove.jar # JHOVE API package
|
||||
jhove-handler.jar # Standard output handler package
|
||||
jhove-module.jar # Standard module package
|
||||
JhoveApp.jar # JHOVE command line application
|
||||
JhoveView.jar # JHOVE with Swing GUI front-end
|
||||
build.xml # Ant configuration file
|
||||
classes/
|
||||
build.xml # Ant configuration file
|
||||
edu/ ... # JHOVE API packages
|
||||
ADump.* # AIFF dump utility class
|
||||
GDump.* # GIF dump utility class
|
||||
Jhove.* # JHOVE main class
|
||||
JDump.* # JPEG dump utility class
|
||||
J2Dump.* # JPEG 2000 dump utility class
|
||||
PDump.* # PDF dump utility class
|
||||
TDump.* # TIFF dump utility class
|
||||
UserHome.* # user.home property utility class
|
||||
WDump.* # WAVE dump utility class
|
||||
conf/
|
||||
jhove.conf # JHOVE configuration file
|
||||
jhove.xsd # JHOVE output schema
|
||||
jhoveConfig.xsd # JHOVE configuration file schema
|
||||
doc/
|
||||
*.html # API documentation
|
||||
...
|
||||
examples/ # Sample files
|
||||
ascii/ ...
|
||||
gif/ ...
|
||||
jpeg/ ...
|
||||
jpeg2000/ ...
|
||||
pdf/ ...
|
||||
tiff/ ...
|
||||
utf-8/ ...
|
||||
adump* # AIFF dump Bourne shell driver
|
||||
adump.bat* # AIFF dump DOS shell driver script
|
||||
gdump* # GIF dump Bourne shell driver
|
||||
gdump.bat* # GIF dump DOS shell driver script
|
||||
jdump* # JPEG dump Bourne shell driver
|
||||
jdump.bat* # JPEG dump DOS shell driver script
|
||||
j2dump* # JPEG 2000 dump Bourne shell driver
|
||||
j2dump.bat* # JPEG 2000 dump DOS shell driver
|
||||
jhove.tmpl* # Template for JHOVE Bourne shell driver script
|
||||
jhove_bat.tmpl* # Template for JHOVE DOS shell driver script
|
||||
pdump* # PDF dump Bourne shell driver
|
||||
pdump.bat* # PDF dump DOS shell driver script
|
||||
tdump* # TIFF dump Bourne shell driver
|
||||
tdump.bat* # TIFF dump DOS shell driver script
|
||||
userhome* # user.home Bourne shell driver
|
||||
userhome.bat* # user.home DOS shell driver script
|
||||
wdump* # WAVE dump Bourne shell driver
|
||||
wdump.bat* # WAVE dump DOS shell driver script
|
||||
|
||||
INSTALLATION
|
||||
|
||||
Edit the configuration file, jhove/conf/jhove.conf, and set the absolute
|
||||
pathname of the JHOVE home directory and the temporary directory (in which
|
||||
temporary files are created):
|
||||
|
||||
<jhoveHome>jhove-home-directory</jhoveHome>
|
||||
<tempDirectory>temporary-directory</tempDirectory>
|
||||
|
||||
The JHOVE home directory is the top-most directory in the distribution TAR
|
||||
or ZIP file. On Unix systems, "/var/tmp" is an appropriate temporary
|
||||
directory; on Windows, "C:\Temp". For example, if the distribution TAR
|
||||
file is disaggregated on a Unix system in the directory "/users/stephen/
|
||||
projects", then the configuration file should read:
|
||||
|
||||
<jhoveHome>/users/stephen/projects/jhove</jhoveHome>
|
||||
<tempDirectory>/var/tmp</jhoveHome>
|
||||
|
||||
In the JHOVE home directory, copy the JHOVE Bourne shell driver script
|
||||
template, "jhove.tmpl", to "jhove" (or the equivalent Windows shell
|
||||
script, "jhove_bat.tmpl" to "jhove.bat"), and set the
|
||||
JHOVE home directory, Java home directory, and Java interpreter:
|
||||
|
||||
JHOVE_HOME=jhove-home-directory
|
||||
JAVA_HOME=java-home-directory
|
||||
JAVA=java-interpreter
|
||||
|
||||
The JAVA_HOME property should provide the absolute pathname of the Java
|
||||
runtime or SDK installation; JAVA should provide the absolute pathname of the
|
||||
Java interpreter. For example:
|
||||
|
||||
JHOVE_HOME=/users/stephen/projects/jhove
|
||||
JAVA_HOME=/usr/local/j2re1.4.1_02
|
||||
JAVA=$JAVA_HOME/bin/java
|
||||
|
||||
In the DOS shell driver script, jhove.bat, the equivalent three
|
||||
variables are:
|
||||
|
||||
SET JHOVE_HOME=jhove-home-directory
|
||||
SET JAVA_HOME=java-home-directory
|
||||
SET JAVA=%JAVA_HOME%\bin\java
|
||||
|
||||
For example:
|
||||
|
||||
SET JHOVE_HOME="C:\Program Files\jhove"
|
||||
SET JAVA_HOME="C:\Program Files\java\j2re1.4.1_02"
|
||||
SET JAVA=%JAVA_HOME%\bin\java
|
||||
|
||||
The quotation marks are necessary because of the embedded space characters.
|
||||
On Windows platforms it may also be necessary to add the Java bin subdirectory
|
||||
to the System PATH environment variable:
|
||||
|
||||
PATH=C:\Program Files\java\j2re1.4.1_02\bin;...
|
||||
|
||||
(For information on setting a Windows environment variable, consult your local
|
||||
documentation or system administrator.)
|
||||
|
||||
USAGE
|
||||
|
||||
java Jhove [-c config] [-m module] [-h handler] [-e encoding] [-H handler]
|
||||
[-o output] [-x saxclass] [-t tempdir] [-b bufsize]
|
||||
[-l loglevel] [[-krs] dir-file-or-uri [...]]
|
||||
|
||||
where -c config Configuration file pathname
|
||||
-m module Module name
|
||||
-h handler Output handler name (defaults to TEXT)
|
||||
-e encoding Character encoding used by output handler (defaults to UTF-8)
|
||||
-H handler About handler name
|
||||
-o output Output file pathname (defaults to standard output)
|
||||
-x saxclass SAX parser class (defaults to J2SE default)
|
||||
-t tempdir Temporary directory in which to create temporary files
|
||||
-b bufsize Buffer size for buffered I/O (defaults to J2SE 1.4 default)
|
||||
-l loglevel Logging level
|
||||
-k Calculate CRC32, MD5, and SHA-1 checksums
|
||||
-r Display raw data flags, not textual equivalents
|
||||
-s Format identification based on internal signatures only
|
||||
dir-file-or-uri Directory or file pathname or URI of formated content
|
||||
stream
|
||||
|
||||
All named modules and output handlers must be found on the Java CLASSPATH at
|
||||
the time of invocation. The JHOVE driver script, jhove/jhove, automatically
|
||||
sets the CLASSPATH and invokes the Jhove main class:
|
||||
|
||||
jhove [-c config] [-m module] [-h handler] [-e encoding] [-H handler]
|
||||
[-o output] [-x saxclass] [-t tempdir] [-b bufsize] [-l loglevel]
|
||||
[[-krs] dir-file-or-uri [...]]
|
||||
|
||||
The following additional programs are available, primarily for testing
|
||||
and debugging purposes. They display a minimally processed, human-readable
|
||||
version of the contents of AIFF, GIF, JPEG, JPEG 2000, PDF, TIFF, and WAVE
|
||||
files:
|
||||
|
||||
java ADump aiff-file
|
||||
java GDump gif-file
|
||||
java JDump jpeg-file
|
||||
java J2Dump jpeg2000-file
|
||||
java PDump pdf-file
|
||||
java TDump tiff-file
|
||||
java WDump wave-file
|
||||
|
||||
For convenience, the following driver scripts are also available:
|
||||
|
||||
adump aiff-file
|
||||
gdump gif-file
|
||||
jdump jpeg-file
|
||||
j2dump jpeg2000-file
|
||||
pdump pdf-file
|
||||
tdump tiff-file
|
||||
wdump wave-file
|
||||
|
||||
The JHOVE Swing-based GUI interface can be invoked from a command shell from
|
||||
the jhove/bin sub-directory:
|
||||
|
||||
java -jar JhoveView.jar -c <configFile>
|
||||
|
||||
where <configFile> is the pathname of the JHOVE configuration file.
|
||||
-1676
File diff suppressed because it is too large
Load Diff
@@ -1,78 +0,0 @@
|
||||
<project name="Jhove" default="dist" basedir=".">
|
||||
<description>Project build file
|
||||
Jhove - JSTOR/Harvard Object Validation Environment
|
||||
Version 1.0 2004-09-10
|
||||
Copyright 2004 by JSTOR and the President and Fellows of Harvard College
|
||||
</description>
|
||||
|
||||
<!-- ant (or ant dist) Build everything
|
||||
ant debug Build everything with debug enabled
|
||||
ant clean Delete backup files
|
||||
ant cleanclass Delete backup and class files
|
||||
ant cleandist Delete backup, class, and jar files
|
||||
ant javadoc Build javadocs
|
||||
-->
|
||||
|
||||
<!-- set global properties for this build -->
|
||||
<property name="bin" location="bin"/>
|
||||
<property name="classes" location="classes"/>
|
||||
<property name="doc" location="doc"/>
|
||||
|
||||
<target name="dist" description="Create distribution">
|
||||
<ant dir="${classes}" inheritAll="false">
|
||||
<property name="dbg" value="off"/>
|
||||
</ant>
|
||||
<chmod file="jhove" perm="ugo+x"/>
|
||||
<chmod file="${bin}/JhoveView.jar" perm="ugo+x"/>
|
||||
</target>
|
||||
|
||||
<target name="debug" description="Create distribution with debug enabled">
|
||||
<ant dir="${classes}" inheritAll="false">
|
||||
<property name="dbg" value="on"/>
|
||||
</ant>
|
||||
</target>
|
||||
|
||||
<target name="view" description="Create JhoveView application">
|
||||
<ant dir="${classes}" target="view" inheritAll="false">
|
||||
<property name="dbs" value="on"/>
|
||||
</ant>
|
||||
</target>
|
||||
|
||||
<target name="clean" description="Delete backup files">
|
||||
<ant dir="${classes}" target="main-clean" inheritAll="false"/>
|
||||
</target>
|
||||
|
||||
<target name="cleanclass" depends="clean">
|
||||
<ant dir="${classes}" target="main-cleanclass" inheritAll="false"/>
|
||||
</target>
|
||||
|
||||
<target name="cleandist" depends="cleanclass">
|
||||
<delete file="${bin}/jhove.jar"/>
|
||||
<delete file="${bin}/jhove-handler.jar"/>
|
||||
<delete file="${bin}/jhove-module.jar"/>
|
||||
<delete file="${bin}/JhoveApp.jar"/>
|
||||
<delete file="${bin}/JhoveView.jar"/>
|
||||
</target>
|
||||
|
||||
<target name="javadoc">
|
||||
<javadoc sourcepath="${classes}" destdir="${doc}"
|
||||
windowtitle="JHOVE Documentation"
|
||||
Overview="${classes}/overview.html">
|
||||
<package name="edu.harvard.hul.ois.jhove"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.handler"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.handler.audit"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.aiff"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.gif"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.html"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.iff"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.jpeg"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.jpeg2000"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.pdf"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.tiff"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.wave"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.module.xml"/>
|
||||
<package name="edu.harvard.hul.ois.jhove.viewer"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
</project>
|
||||
@@ -1,235 +0,0 @@
|
||||
/**********************************************************************
|
||||
* JDump - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004-2005 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import edu.harvard.hul.ois.jhove.module.aiff.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Dump contents of AIFF file in human-readable format.
|
||||
* @author Gary McGath
|
||||
*/
|
||||
public class ADump extends Dump {
|
||||
|
||||
/* Fixed value for first 4 bytes */
|
||||
private static final int[] sigByte =
|
||||
{ 0X46, 0X4F, 0X52, 0X4D };
|
||||
private static final boolean ENDIAN = true; /* bigEndian */
|
||||
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
* @param args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
if (args.length < 1) {
|
||||
System.err.println ("usage: java ADump file");
|
||||
System.exit (-1);
|
||||
}
|
||||
try {
|
||||
FileInputStream file = new FileInputStream (args[0]);
|
||||
BufferedInputStream buffer = new BufferedInputStream (file);
|
||||
DataInputStream stream = new DataInputStream (buffer);
|
||||
ADump dump = new ADump (); // Just to access contained classes
|
||||
long os = 0;
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch;
|
||||
ch = stream.readUnsignedByte();
|
||||
if (ch != sigByte[i]) {
|
||||
System.out.println ("No AIFF FORM header");
|
||||
System.exit (-2);
|
||||
}
|
||||
}
|
||||
os += 4;
|
||||
long ckSize = ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
|
||||
// Read the file type
|
||||
StringBuffer formType = new StringBuffer (4);
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte(stream);
|
||||
formType.append((char) ch);
|
||||
}
|
||||
System.out.println ("00000000: FORM " + ckSize + ": " + formType);
|
||||
|
||||
boolean aiff_c = false;
|
||||
if (formType.toString ().equals ("AIFC")) {
|
||||
aiff_c = true;
|
||||
}
|
||||
|
||||
StringBuffer sbuf = new StringBuffer ();
|
||||
boolean endOfFile = false;
|
||||
while (!endOfFile) {
|
||||
// Read chunks
|
||||
try {
|
||||
sbuf.setLength(0);
|
||||
// Read chunk name.
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte(stream);
|
||||
sbuf.append((char) ch);
|
||||
}
|
||||
String ckID = sbuf.toString ();
|
||||
// Read size (excluding chunk name and size fields)
|
||||
ckSize = ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
System.out.print (leading (os, 8) + os + ": " + ckID +
|
||||
" " + ckSize);
|
||||
long alreadyRead = 0;
|
||||
if (ckID.equals ("AESD")) {
|
||||
int [] aes = new int[24];
|
||||
for (int i=0; i<24; i++) {
|
||||
aes[i] = ModuleBase.readUnsignedByte (stream);
|
||||
|
||||
}
|
||||
System.out.print (": " + aes[0]);
|
||||
for (int i=1; i<24; i++) {
|
||||
System.out.print ("," + aes[i]);
|
||||
}
|
||||
alreadyRead = 24;
|
||||
}
|
||||
else if (ckID.equals ("ANNO") ||
|
||||
ckID.equals ("AUTH") ||
|
||||
ckID.equals ("(c) ") ||
|
||||
ckID.equals ("NAME")) {
|
||||
sbuf.setLength (0);
|
||||
for (int i=0; i<ckSize; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte (stream);
|
||||
sbuf.append ((char) ch);
|
||||
}
|
||||
System.out.print (": \"" + sbuf.toString () + "\"");
|
||||
alreadyRead = ckSize;
|
||||
}
|
||||
else if (ckID.equals ("APPL")) {
|
||||
sbuf.setLength (0);
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte (stream);
|
||||
sbuf.append ((char) ch);
|
||||
}
|
||||
System.out.print (": " + sbuf.toString ());
|
||||
alreadyRead = 4;
|
||||
}
|
||||
else if (ckID.equals ("COMM")) {
|
||||
int numChannels = ModuleBase.readSignedShort (stream,
|
||||
ENDIAN);
|
||||
long numSampleFrames =
|
||||
ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
int sampleSize = ModuleBase.readSignedShort (stream,
|
||||
ENDIAN);
|
||||
byte [] buf = new byte[10];
|
||||
for (int i=0; i<10; i++) {
|
||||
buf[i] = (byte) ModuleBase.readSignedByte (stream);
|
||||
}
|
||||
ExtDouble xd = new ExtDouble (buf);
|
||||
double sampleRate = xd.toDouble ();
|
||||
|
||||
System.out.print (": " + numChannels + " " +
|
||||
numSampleFrames + " " + sampleSize +
|
||||
" " + sampleRate);
|
||||
alreadyRead = 18;
|
||||
|
||||
if (aiff_c) {
|
||||
sbuf.setLength (0);
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte (stream,
|
||||
null);
|
||||
sbuf.append ((char) ch);
|
||||
}
|
||||
System.out.print (" " + sbuf.toString ());
|
||||
|
||||
int count = ModuleBase.readUnsignedByte (stream,
|
||||
null);
|
||||
alreadyRead = 23;
|
||||
sbuf.setLength (0);
|
||||
for (int i=0; i<count; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte (stream,
|
||||
null);
|
||||
sbuf.append ((char) ch);
|
||||
|
||||
alreadyRead++;
|
||||
}
|
||||
System.out.print (" \"" + sbuf.toString () + "\"");
|
||||
}
|
||||
|
||||
}
|
||||
else if (ckID.equals ("COMT")) {
|
||||
int numComments = ModuleBase.readUnsignedShort (stream,
|
||||
ENDIAN,
|
||||
null);
|
||||
System.out.print (": " + numComments);
|
||||
alreadyRead = 2;
|
||||
}
|
||||
else if (ckID.equals ("FVER")) {
|
||||
long timestamp = ModuleBase.readUnsignedInt (stream,
|
||||
ENDIAN,
|
||||
null);
|
||||
System.out.print (": " + timestamp);
|
||||
alreadyRead = 4;
|
||||
}
|
||||
else if (ckID.equals ("INST")) {
|
||||
int baseNote = ModuleBase.readSignedByte (stream);
|
||||
int detune = ModuleBase.readSignedByte (stream);
|
||||
int lowNote = ModuleBase.readSignedByte (stream);
|
||||
int highNote = ModuleBase.readSignedByte (stream);
|
||||
int lowVelocity = ModuleBase.readSignedByte (stream);
|
||||
int highVelocity = ModuleBase.readSignedByte (stream);
|
||||
int gain = ModuleBase.readSignedShort (stream, ENDIAN);
|
||||
|
||||
System.out.print (": " + baseNote + " " + detune +
|
||||
" " + lowNote + "," + highNote +
|
||||
" " + lowVelocity + "," +
|
||||
highVelocity + " " + gain);
|
||||
alreadyRead = 8;
|
||||
}
|
||||
else if (ckID.equals ("MARK")) {
|
||||
int numMarkers = ModuleBase.readUnsignedShort (stream,
|
||||
ENDIAN);
|
||||
System.out.print (": " + numMarkers);
|
||||
alreadyRead = 2;
|
||||
}
|
||||
else if (ckID.equals ("SSND")) {
|
||||
long offset = ModuleBase.readUnsignedInt (stream,
|
||||
ENDIAN);
|
||||
long blockSize = ModuleBase.readUnsignedInt (stream,
|
||||
ENDIAN);
|
||||
System.out.print (": " + offset + " " + blockSize);
|
||||
alreadyRead = 8;
|
||||
}
|
||||
System.out.println ();
|
||||
|
||||
// Actual number of bytes to skip must be even.
|
||||
long actSize = ckSize;
|
||||
if ((actSize & 1) != 0) {
|
||||
actSize++;
|
||||
}
|
||||
actSize -= alreadyRead;
|
||||
stream.skipBytes ((int) actSize);
|
||||
os += ckSize + 8;
|
||||
}
|
||||
catch (EOFException e) {
|
||||
endOfFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
/**********************************************************************
|
||||
* GDump - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import java.io.*;
|
||||
//import java.util.*;
|
||||
|
||||
/**
|
||||
* Dump contents of GIF file in human-readable format.
|
||||
*/
|
||||
public class GDump
|
||||
extends Dump
|
||||
{
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
* @param args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
if (args.length < 1) {
|
||||
System.err.println ("usage: java GDump file");
|
||||
System.exit (-1);
|
||||
}
|
||||
|
||||
try {
|
||||
FileInputStream file = new FileInputStream (args[0]);
|
||||
BufferedInputStream buffer = new BufferedInputStream (file);
|
||||
DataInputStream stream = new DataInputStream (buffer);
|
||||
boolean bigEndian = false;
|
||||
|
||||
String signature = readChars (stream, 3);
|
||||
String version = readChars (stream, 3);
|
||||
System.out.println ("00000000: \"" + signature + version + "\"");
|
||||
|
||||
int width = ModuleBase.readUnsignedShort(stream, bigEndian, null);
|
||||
int height = ModuleBase.readUnsignedShort(stream, bigEndian, null);
|
||||
int packedFields = stream.readUnsignedByte ();
|
||||
int backgroundColor = stream.readUnsignedByte ();
|
||||
int aspectRatio = stream.readUnsignedByte ();
|
||||
System.out.println ("00000006: LogicalScreenDescriptor: " +
|
||||
width + "x" + height + " 0x" +
|
||||
leading (packedFields, 2) +
|
||||
Integer.toHexString (packedFields) + " " +
|
||||
backgroundColor + " " + aspectRatio);
|
||||
long os = 13;
|
||||
|
||||
boolean globalColorTable = (packedFields & 0x80) != 0;
|
||||
int globalColorTableSize = packedFields & 0x07;
|
||||
|
||||
if (globalColorTable) {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": GlobalColorTable:");
|
||||
os = colorTable (stream, os, globalColorTableSize);
|
||||
}
|
||||
|
||||
for (int op = 0; (op = stream.readUnsignedByte ()) != -1;) {
|
||||
if (op == 0x00) {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": BlockTerminator");
|
||||
os++;
|
||||
}
|
||||
else if (op == 0x2c) {
|
||||
int imageLeft = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int imageTop = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int imageWidth = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int imageHeight = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
packedFields = stream.readUnsignedByte ();
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": ImageDescriptor: " + imageLeft +
|
||||
"," + imageTop + " " + imageWidth +
|
||||
"x" + imageHeight + " 0x" +
|
||||
leading (packedFields, 2) +
|
||||
Integer.toHexString (packedFields));
|
||||
os += 10;
|
||||
|
||||
boolean localColorTable = (packedFields & 0x80) != 0;
|
||||
int localColorTableSize = packedFields & 0x07;
|
||||
|
||||
if (localColorTable) {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": LocalColorTable:");
|
||||
os = colorTable (stream, os, localColorTableSize);
|
||||
}
|
||||
|
||||
int size = stream.readUnsignedByte ();
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": ImageData: " + size);
|
||||
os = subBlocks (stream, ++os);
|
||||
}
|
||||
else if (op == 0x21) {
|
||||
int label = stream.readUnsignedByte ();
|
||||
|
||||
if (label == 0x01) {
|
||||
int blockSize = stream.readUnsignedByte ();
|
||||
int gridLeft = ModuleBase.readUnsignedShort(stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int gridTop = ModuleBase.readUnsignedShort(stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int gridWidth = ModuleBase.readUnsignedShort(stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int gridHeight= ModuleBase.readUnsignedShort(stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int cellWidth = stream.readUnsignedByte ();
|
||||
int cellHeight = stream.readUnsignedByte ();
|
||||
int foreground = stream.readUnsignedByte ();
|
||||
int background = stream.readUnsignedByte ();
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": PlainTextExtension: " +
|
||||
blockSize + " " + gridLeft + "," +
|
||||
gridTop + " " + gridWidth + "x" +
|
||||
gridHeight + " " + cellWidth +
|
||||
"x" + cellHeight + " " +
|
||||
foreground + "," + background);
|
||||
os += 15;
|
||||
os = subBlocks (stream, os);
|
||||
}
|
||||
else if (label == 0xf9) {
|
||||
int blockSize = stream.readUnsignedByte ();
|
||||
packedFields = stream.readUnsignedByte ();
|
||||
int delayTime = ModuleBase.readUnsignedShort(stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int colorIndex= stream.readUnsignedByte ();
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": GraphicControlExtension: " +
|
||||
blockSize + " 0x" +
|
||||
leading (packedFields, 2) +
|
||||
packedFields + " " + delayTime +
|
||||
" " + colorIndex);
|
||||
os += 7;
|
||||
}
|
||||
else if (label == 0xfe) {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": CommentExtension: \"" +
|
||||
"\"");
|
||||
os += 2;
|
||||
os = subBlocks (stream, os);
|
||||
}
|
||||
else if (label == 0xff) {
|
||||
int blockSize = stream.readUnsignedByte ();
|
||||
String appId = readChars (stream, 8);
|
||||
int [] authCode = new int [3];
|
||||
authCode[0] = stream.readUnsignedByte ();
|
||||
authCode[1] = stream.readUnsignedByte ();
|
||||
authCode[2] = stream.readUnsignedByte ();
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": ApplicationExtension: " +
|
||||
blockSize + " \"" + appId +
|
||||
"\" " + authCode[0] + "," +
|
||||
authCode[1] + "," + authCode[2]);
|
||||
os += 14;
|
||||
os = subBlocks (stream, os);
|
||||
}
|
||||
else {
|
||||
String hex = Integer.toHexString (label);
|
||||
System.out.println (leading (os-1, 8) + (os-1) +
|
||||
": Unknown extension block: 0x" +
|
||||
leading (hex, 2) + hex);
|
||||
os += 2;
|
||||
}
|
||||
}
|
||||
else if (op == 0x3b) {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": Trailer: 0x3b");
|
||||
os++;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
String hex = Integer.toHexString (op);
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": Unknown block: 0x" +
|
||||
leading (hex, 2) + hex);
|
||||
os++;
|
||||
}
|
||||
}
|
||||
stream.close ();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace (System.err);
|
||||
System.exit (-2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and display a color table.
|
||||
* @param stream Data input stream
|
||||
* @param os Current byte offset
|
||||
* @param size Color table size
|
||||
* @return Updated byte offset
|
||||
*/
|
||||
private static long colorTable (DataInputStream stream, long os, int size)
|
||||
throws IOException
|
||||
{
|
||||
int n = 2<<size;
|
||||
for (int i=0; i<n; i++) {
|
||||
long r = stream.readUnsignedByte ();
|
||||
long g = stream.readUnsignedByte ();
|
||||
long b = stream.readUnsignedByte ();
|
||||
System.out.println (leading (os, 8) + os + ": " +
|
||||
leading (i, 3, ' ') + i + ": " +
|
||||
leading (r, 3, ' ') + r + "," +
|
||||
leading (g, 3, ' ') + g + "," +
|
||||
leading (b, 3, ' ') + b);
|
||||
os += 3;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and display a sequence of sub-blocks.
|
||||
* @param stream Data input stream
|
||||
* @param os Current byte offset
|
||||
* @return Updated byte offset
|
||||
*/
|
||||
private static long subBlocks (DataInputStream stream, long os)
|
||||
throws IOException
|
||||
{
|
||||
int size;
|
||||
|
||||
while ((size = stream.readUnsignedByte ()) != 0) {
|
||||
System.out.println (leading (os, 8) + os + ": SubBlock: " + size);
|
||||
os += 1;
|
||||
for (int i=0; i<size; i++) {
|
||||
stream.readUnsignedByte ();
|
||||
os += 1;
|
||||
}
|
||||
}
|
||||
System.out.println (leading (os, 8) + os + ": BlockTerminator");
|
||||
return os + 1;
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
/**********************************************************************
|
||||
* JDump - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Dump contents of JPEG2000 file in human-readable format.
|
||||
*/
|
||||
public class J2Dump extends Dump {
|
||||
|
||||
/* Fixed value for first 12 bytes */
|
||||
private static final int[] sigByte =
|
||||
{
|
||||
0X00,
|
||||
0X00,
|
||||
0X00,
|
||||
0X0C,
|
||||
0X6A,
|
||||
0X50,
|
||||
0X20,
|
||||
0X20,
|
||||
0X0D,
|
||||
0X0A,
|
||||
0X87,
|
||||
0X0A };
|
||||
|
||||
private static final boolean ENDIAN = true; /* bigEndian */
|
||||
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
* @param args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
if (args.length < 1) {
|
||||
System.err.println ("usage: java J2Dump file");
|
||||
System.exit (-1);
|
||||
}
|
||||
try {
|
||||
FileInputStream file = new FileInputStream (args[0]);
|
||||
BufferedInputStream buffer = new BufferedInputStream (file);
|
||||
DataInputStream stream = new DataInputStream (buffer);
|
||||
J2Dump dump = new J2Dump (); // Just to access contained classes
|
||||
long os = 0;
|
||||
boolean bigEndian = true;
|
||||
int i;
|
||||
for (i = 0; i < 12; i++) {
|
||||
int ch;
|
||||
ch = stream.readUnsignedByte();
|
||||
if (ch != sigByte[i]) {
|
||||
System.out.println ("No JPEG 2000 header");
|
||||
System.exit (-2);
|
||||
}
|
||||
}
|
||||
os += 12;
|
||||
|
||||
boolean endOfFile = false;
|
||||
Stack boxStack = new Stack ();
|
||||
while (!endOfFile) {
|
||||
//If there are boxes on the stack, see if there's space
|
||||
//left in the top one.
|
||||
Box boxtop;
|
||||
for (;;) {
|
||||
boxtop = null;
|
||||
if (boxStack.isEmpty ()) {
|
||||
break;
|
||||
}
|
||||
boxtop = (Box) boxStack.peek ();
|
||||
if (boxtop.bytesLeft > 0) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
boxStack.pop ();
|
||||
}
|
||||
}
|
||||
|
||||
// Read the header of a JP2 box
|
||||
Box box = dump.new Box (stream);
|
||||
try {
|
||||
box.read ();
|
||||
}
|
||||
catch (EOFException e) {
|
||||
endOfFile = true;
|
||||
break;
|
||||
}
|
||||
os += box.length - box.bytesLeft;
|
||||
|
||||
// If it's contained in a superbox, subtract
|
||||
// this box from its remaining length
|
||||
if (boxtop != null) {
|
||||
boxtop.bytesLeft -= box.length;
|
||||
}
|
||||
System.out.println (leading (os, 8) + os + ": " +
|
||||
stackPrefix (boxStack) + box.type + " " + box.length);
|
||||
if (box.isSuperbox ()) {
|
||||
boxStack.push (box);
|
||||
}
|
||||
else {
|
||||
os += box.bytesLeft;
|
||||
stream.skipBytes((int) box.bytesLeft);
|
||||
}
|
||||
|
||||
// A "length" of 0 means the box occupies the rest of the file.
|
||||
if (box.length == 0) {
|
||||
endOfFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace (System.err);
|
||||
System.exit (-2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Constructs a qualifying prefix to indicate nested boxes. */
|
||||
private static String stackPrefix (Stack boxStack)
|
||||
{
|
||||
StringBuffer retval = new StringBuffer ();
|
||||
// In defiance of gravity, we rummage through the stack
|
||||
// of boxes starting at the bottom.
|
||||
for (int i = 0; i < boxStack.size(); i++) {
|
||||
Box box = (Box) boxStack.elementAt (i);
|
||||
// Remove trailing spaces from types for better readability
|
||||
retval.append (box.type.trim() + "/");
|
||||
}
|
||||
return retval.toString ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Local class for defining JPEG2000 boxes. */
|
||||
class Box {
|
||||
public String type;
|
||||
public long length;
|
||||
public long bytesLeft;
|
||||
public boolean hasBoxes;
|
||||
DataInputStream dstream;
|
||||
|
||||
public Box (DataInputStream stream)
|
||||
{
|
||||
this.dstream = stream;
|
||||
}
|
||||
|
||||
|
||||
/** Reads a box header and sets up for reading contents. */
|
||||
public void read () throws IOException
|
||||
{
|
||||
length = ModuleBase.readUnsignedInt (dstream, ENDIAN, null);
|
||||
long headerLength = 8;
|
||||
type = read4Chars ();
|
||||
// If the length field is 1, there is an 8-byte extended
|
||||
// length field.
|
||||
if (length == 1) {
|
||||
length = ModuleBase.readSignedLong(dstream, true, null);
|
||||
headerLength = 16;
|
||||
}
|
||||
bytesLeft = length - headerLength;
|
||||
}
|
||||
|
||||
|
||||
/* Reads a 4-character name */
|
||||
private String read4Chars() throws IOException {
|
||||
StringBuffer sbuf = new StringBuffer(4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte(dstream, null);
|
||||
sbuf.append((char) ch);
|
||||
}
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
/** Returns true if this box contains other boxes.
|
||||
* At present, we don't deal with the insides of boxes
|
||||
* that contain both data and boxes (e.g., cref). */
|
||||
public boolean isSuperbox ()
|
||||
{
|
||||
// If it's a known superbox type, we return true.
|
||||
// If we've left any out, that will merely make us
|
||||
// lose the subboxes of that type.
|
||||
String [] supertypes = { "asoc", "cgrp", "comp", "drep",
|
||||
"ftbl", "jp2h", "jpch",
|
||||
"jplh", "res ", "uuid" };
|
||||
for (int i = 0; i < supertypes.length; i++) {
|
||||
if (supertypes[i].equals (type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,404 +0,0 @@
|
||||
/**********************************************************************
|
||||
* JDump - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import java.io.*;
|
||||
//import java.util.*;
|
||||
|
||||
/**
|
||||
* Dump contents of JPEG file in human-readable format.
|
||||
*/
|
||||
public class JDump
|
||||
extends Dump
|
||||
{
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
* @param args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
if (args.length < 1) {
|
||||
System.err.println ("usage: java JDump file");
|
||||
System.exit (-1);
|
||||
}
|
||||
|
||||
try {
|
||||
FileInputStream file = new FileInputStream (args[0]);
|
||||
BufferedInputStream buffer = new BufferedInputStream (file);
|
||||
DataInputStream stream = new DataInputStream (buffer);
|
||||
boolean bigEndian = true;
|
||||
|
||||
long os = 0;
|
||||
|
||||
boolean endOfImage = false;
|
||||
boolean readingECS = false;
|
||||
boolean haveCode = false;;
|
||||
int nECS = 0;
|
||||
int code = 0;
|
||||
while (!endOfImage) {
|
||||
if (!readingECS) {
|
||||
if (!haveCode) {
|
||||
code = stream.readUnsignedByte ();
|
||||
for (int i=0;
|
||||
(code = stream.readUnsignedByte ()) == 0xff;
|
||||
i++) {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": fill 0xff");
|
||||
os++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
boolean ff = false;
|
||||
int length = 0;
|
||||
while (true) {
|
||||
code = stream.readUnsignedByte ();
|
||||
length++;
|
||||
if (code == 0xff) {
|
||||
ff = true;
|
||||
}
|
||||
else if (ff) {
|
||||
if (code != 0x00) {
|
||||
length -= 2;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ff = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println (leading (os, 8) + os + ": ECS" +
|
||||
nECS + " " + length + " ...");
|
||||
os += length;
|
||||
nECS++;
|
||||
readingECS = false;
|
||||
haveCode = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code == 0x01) {
|
||||
System.out.println (leading (os, 8) + os + ": TEM");
|
||||
}
|
||||
else if ((code >= 0xc0 && code <= 0xc3) ||
|
||||
(code >= 0xc5 && code <= 0xc7) ||
|
||||
(code >= 0xc9 && code <= 0xcb) ||
|
||||
(code >= 0xcd && code <= 0xcf)) {
|
||||
int n = code - 0xc0;
|
||||
/****************** int length = markerSegment (stream, bigEndian); */
|
||||
int length = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int P = stream.readUnsignedByte ();
|
||||
int Y = ModuleBase.readUnsignedShort (stream, bigEndian,
|
||||
null);
|
||||
int X = ModuleBase.readUnsignedShort (stream, bigEndian,
|
||||
null);
|
||||
int Nf = stream.readUnsignedByte ();
|
||||
int [] Ci = new int [Nf];
|
||||
int [] Hi = new int [Nf];
|
||||
int [] Vi = new int [Nf];
|
||||
int [] Tqi = new int [Nf];
|
||||
for (int i=0; i<Nf; i++) {
|
||||
Ci[i] = stream.readUnsignedByte ();
|
||||
Hi[i] = stream.readUnsignedByte ();
|
||||
Tqi[i] = stream.readUnsignedByte ();
|
||||
}
|
||||
System.out.print (leading (os, 8) + os + ": SOF" + n +
|
||||
" " + length + ": " + P + " " + X +
|
||||
"x" + Y + " " + Nf + ":");
|
||||
for (int i=0; i<Nf; i++) {
|
||||
System.out.print (" " + Ci[i] + "," + Hi[i] + "," +
|
||||
Tqi[i]);
|
||||
}
|
||||
System.out.println ();
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xc4) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DHT" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xc8) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": JPG" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xcc) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DAC" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code >= 0xd0 && code <= 0xd7) {
|
||||
int m = code - 0xd0;
|
||||
System.out.println (leading (os, 8) + os + ": RST" + m);
|
||||
|
||||
readingECS = true;
|
||||
}
|
||||
else if (code == 0xd8) {
|
||||
System.out.println (leading (os, 8) + os + ": SOI");
|
||||
}
|
||||
else if (code == 0xd9) {
|
||||
System.out.println (leading (os, 8) + os + ": EOI");
|
||||
endOfImage = true;
|
||||
break;
|
||||
}
|
||||
else if (code == 0xda) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": SOS" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
|
||||
readingECS = true;
|
||||
}
|
||||
else if (code == 0xdb) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DQT" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xdc) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DNL" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xdd) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DRI" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xde) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DHP" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xdf) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": EXP" + " " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xe0) {
|
||||
int length = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
String id = readChars (stream, 5);
|
||||
if (id.equals ("JFIF\0")) {
|
||||
int major = stream.readUnsignedByte ();
|
||||
int minor = stream.readUnsignedByte ();
|
||||
int units = stream.readUnsignedByte ();
|
||||
int xDensity = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int yDensity = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int xThumbnail = stream.readUnsignedByte ();
|
||||
int yThumbnail = stream.readUnsignedByte ();
|
||||
System.out.print (leading (os, 8) + os + ": APP0 " +
|
||||
"\"" + id + "\" " + major + "." +
|
||||
minor + " " + units + " " +
|
||||
xDensity + "x" + yDensity + " "
|
||||
+ xThumbnail + "x" + yThumbnail);
|
||||
int n = length - 16;
|
||||
if (n > 0) {
|
||||
for (int i=0; i<n; i++) {
|
||||
stream.readUnsignedByte ();
|
||||
}
|
||||
System.out.print (" " + n + " ...");
|
||||
}
|
||||
System.out.println ();
|
||||
}
|
||||
else if (id.equals ("JFXX\0")) {
|
||||
int ext = stream.readUnsignedByte ();
|
||||
String hex = Integer.toHexString (ext);
|
||||
System.out.print (leading (os, 8) + os + ": APP0 " +
|
||||
"0x" + leading (hex, 2) + hex);
|
||||
int n = length-3;
|
||||
if (n > 0) {
|
||||
for (int i=0; i<n; i++) {
|
||||
stream.readUnsignedByte ();
|
||||
}
|
||||
System.out.print (" " + n + " ...");
|
||||
}
|
||||
System.out.println ();
|
||||
}
|
||||
else {
|
||||
System.out.println (leading (os, 8) + os + ": APP0 " +
|
||||
length + " ...");
|
||||
for (int i=2; i<length; i++) {
|
||||
stream.readUnsignedByte ();
|
||||
}
|
||||
}
|
||||
os += length;
|
||||
}
|
||||
else if (code >= 0xe1 && code <= 0xef) {
|
||||
int n = code - 0xe0;
|
||||
/*
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
*/
|
||||
int length = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
if ((n == 1 || n == 2) && length >= 8) {
|
||||
String id = readChars (stream, 4);
|
||||
int NULL = stream.readUnsignedByte ();
|
||||
int padding = stream.readUnsignedByte ();
|
||||
if (id.equals ("Exif") || id.equals ("FPXR")) {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": APP" + n + " \"" + id +
|
||||
"\" " + NULL + " " + padding +
|
||||
" " + (length-8) + ": ...");
|
||||
}
|
||||
else {
|
||||
System.out.println (leading (os, 8) + os +
|
||||
": APP" + n + " " + length +
|
||||
" ...");
|
||||
}
|
||||
for (int i=8; i<length; i++) {
|
||||
stream.readUnsignedByte ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.out.println (leading (os, 8) + os + ": APP" +
|
||||
n + " " + length + " ...");
|
||||
for (int i=2; i<length; i++) {
|
||||
stream.readUnsignedByte ();
|
||||
}
|
||||
}
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xf0) {
|
||||
int length = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
int v = stream.readUnsignedByte ();
|
||||
int rev = stream.readUnsignedByte ();
|
||||
System.out.print (leading (os, 8) + os + ": VER " +
|
||||
v + "." + rev);
|
||||
int n = length - 4;
|
||||
if (n > 0) {
|
||||
int [] cap = new int [n];
|
||||
for (int i=0; i<n; i++) {
|
||||
cap[i] = stream.readUnsignedByte ();
|
||||
System.out.print (((i==0) ? " " : ",") + cap[i]);
|
||||
}
|
||||
}
|
||||
System.out.println ();
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xf1) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DTI " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xf2) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DTT " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xf3) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": SRF " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xf4) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": SRS " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xf5) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DCR " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xf6) {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": DQS " +
|
||||
length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code >= 0xf7 && code <= 0xfd) {
|
||||
int n = code - 0xf0;
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
System.out.println (leading (os, 8) + os + ": JPG" + n +
|
||||
" " + length + " ...");
|
||||
os += length;
|
||||
}
|
||||
else if (code == 0xfe) {
|
||||
int length = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
String comment = readChars (stream, length-2);
|
||||
System.out.println (leading (os, 8) + os + ": COM \"" +
|
||||
comment + "\"");
|
||||
os += length;
|
||||
}
|
||||
else {
|
||||
int length = markerSegment (stream, bigEndian);
|
||||
String hex = Integer.toHexString (code);
|
||||
System.out.println (leading (os, 8) + os + ": RES (0x" +
|
||||
leading (hex, 2) + hex + ") " +
|
||||
length + " ...");
|
||||
}
|
||||
os += 2;
|
||||
}
|
||||
|
||||
stream.close ();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace (System.err);
|
||||
System.exit (-2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read marker segment data
|
||||
* @param stream Data input stream
|
||||
* @param bigEndian True if big-endian
|
||||
* @return Length of marker segment
|
||||
*/
|
||||
private static int markerSegment (DataInputStream stream,
|
||||
boolean bigEndian)
|
||||
throws IOException
|
||||
{
|
||||
int length = ModuleBase.readUnsignedShort (stream,
|
||||
bigEndian,
|
||||
null);
|
||||
for (int i=2; i<length; i++) {
|
||||
stream.readUnsignedByte ();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
@@ -1,313 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004-2007 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
//import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class Jhove
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE CLASS FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Application name. */
|
||||
private static final String NAME = "Jhove";
|
||||
|
||||
/** Application build date, YYYY, MM, DD. */
|
||||
private static int [] DATE;
|
||||
|
||||
/** Application release number. */
|
||||
private static String RELEASE;
|
||||
|
||||
/** Application invocation syntax. */
|
||||
private static final String USAGE = "java " + NAME + " [-c config] " +
|
||||
"[-m module] [-h handler] [-e encoding] [-H handler] [-o output] " +
|
||||
"[-x saxclass] [-t tempdir] [-b bufsize] [-l loglevel] [[-krs] " +
|
||||
"dir-file-or-uri [...]]";
|
||||
|
||||
/** Copyright information. */
|
||||
private static final String RIGHTS =
|
||||
"Derived from software Copyright 2004-2011 " +
|
||||
"by the President and Fellows of Harvard College. " +
|
||||
"Version 1.7 and higher independently released. " +
|
||||
"Released under the GNU Lesser General Public License.";
|
||||
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
public static void main (String [] args)
|
||||
{
|
||||
RELEASE = JhoveBase._release; // possibly safer than final static init
|
||||
DATE = JhoveBase.DATE;
|
||||
/* Make sure we have a satisfactory version of Java. */
|
||||
String version = System.getProperty ("java.vm.version");
|
||||
if (version.compareTo ("1.5.0") < 0) {
|
||||
//System.err.println (NAME + ": Java 1.4 or higher is required");
|
||||
System.out.println ("Java 1.5 or higher is required");
|
||||
System.exit (-1);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
/**********************************************************
|
||||
* Initialize the application state object.
|
||||
**********************************************************/
|
||||
|
||||
App app = new App (NAME, RELEASE, DATE, USAGE, RIGHTS);
|
||||
|
||||
/**********************************************************
|
||||
* Retrieve the configuration file.
|
||||
**********************************************************/
|
||||
|
||||
String configFile = JhoveBase.getConfigFileFromProperties ();
|
||||
String saxClass = JhoveBase.getSaxClassFromProperties ();
|
||||
|
||||
/* Pre-parse the command line for -c and -x config options.
|
||||
* With Windows, we have to deal with quote marks on our own. With Unix,
|
||||
* the shell takes care of quotes for us. */
|
||||
boolean quoted = false;
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (quoted) {
|
||||
int len = args[i].length ();
|
||||
if (args[i].charAt (len-1) == '"') {
|
||||
quoted = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (args[i].equals ("-c")) {
|
||||
if (i < args.length-1) {
|
||||
configFile = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-x")) {
|
||||
if (i <args.length-1) {
|
||||
saxClass = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].charAt (0) == '"') {
|
||||
quoted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* Initialize the JHOVE engine.
|
||||
**********************************************************/
|
||||
|
||||
String encoding = null;
|
||||
String tempDir = null;
|
||||
int bufferSize = -1;
|
||||
|
||||
String moduleName = null;
|
||||
String handlerName = null;
|
||||
String aboutHandler = null;
|
||||
String logLevel = "SEVERE";
|
||||
String outputFile = null;
|
||||
boolean checksum = false;
|
||||
boolean showRaw = false;
|
||||
boolean signature = false;
|
||||
List<String> list = new ArrayList<String> ();
|
||||
|
||||
|
||||
/**********************************************************
|
||||
* Parse command line arguments:
|
||||
* -m module Module name
|
||||
* -h handler Output handler
|
||||
* -e encoding Output encoding
|
||||
* -H handler About handler
|
||||
* -o output Output file pathname
|
||||
* -t tempdir Directory for temp files
|
||||
* -b bufsize Buffer size for buffered I/O
|
||||
* -k Calculate checksums
|
||||
* -r Display raw numeric flags
|
||||
* -s Check internal signatures only
|
||||
* dirFileOrUri Directories, file pathnames, or URIs
|
||||
*
|
||||
* The following arguments were defined in previous
|
||||
* versions, but are now obsolete
|
||||
* -p param OBSOLETE
|
||||
* -P param OBSOLETE
|
||||
**********************************************************/
|
||||
|
||||
quoted = false;
|
||||
StringBuffer filename = null;
|
||||
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (quoted) {
|
||||
int len = args[i].length ();
|
||||
if (args[i].charAt (len-1) == '"') {
|
||||
filename.append (" " + args[i].substring (0, len-1));
|
||||
list.add (filename.toString ());
|
||||
quoted = false;
|
||||
}
|
||||
else {
|
||||
filename.append (" " + args[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (args[i].equals ("-c")) {
|
||||
i++;
|
||||
}
|
||||
else if (args[i].equals ("-m")) {
|
||||
if (i < args.length-1) {
|
||||
moduleName = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-p")) {
|
||||
// Obsolete -- but eat the next arg for compatibility
|
||||
if (i <args.length-1) {
|
||||
@SuppressWarnings("unused")
|
||||
String moduleParam = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-h")) {
|
||||
if (i < args.length-1) {
|
||||
handlerName = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-P")) {
|
||||
// Obsolete -- but eat the next arg for compatibility
|
||||
if (i <args.length-1) {
|
||||
@SuppressWarnings("unused")
|
||||
String handlerParam = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-e")) {
|
||||
if (i < args.length-1) {
|
||||
encoding = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-H")) {
|
||||
if (i < args.length-1) {
|
||||
aboutHandler = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-l")) {
|
||||
if (i < args.length-1) {
|
||||
logLevel = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-o")) {
|
||||
if (i < args.length-1) {
|
||||
outputFile = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-x")) {
|
||||
i++;
|
||||
}
|
||||
else if (args[i].equals ("-t")) {
|
||||
if (i <args.length-1) {
|
||||
tempDir = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-b")) {
|
||||
if (i <args.length-1) {
|
||||
try {
|
||||
bufferSize = Integer.parseInt (args[++i]);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.err.println ("Invalid buffer size, using default.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-k")) {
|
||||
checksum = true;
|
||||
}
|
||||
else if (args[i].equals ("-r")) {
|
||||
showRaw = true;
|
||||
}
|
||||
else if (args[i].equals ("-s")) {
|
||||
signature = true;
|
||||
}
|
||||
else if (args[i].charAt (0) != '-') {
|
||||
if (args[i].charAt (0) == '"') {
|
||||
filename = new StringBuffer ();
|
||||
filename.append (args[i].substring (1));
|
||||
quoted = true;
|
||||
}
|
||||
else {
|
||||
list.add (args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (quoted) {
|
||||
list.add (filename.toString ());
|
||||
}
|
||||
|
||||
JhoveBase je = new JhoveBase ();
|
||||
je.setLogLevel (logLevel);
|
||||
je.init (configFile, saxClass);
|
||||
if (encoding == null) {
|
||||
encoding = je.getEncoding ();
|
||||
}
|
||||
if (tempDir == null) {
|
||||
tempDir = je.getTempDirectory ();
|
||||
}
|
||||
if (bufferSize < 0) {
|
||||
bufferSize = je.getBufferSize ();
|
||||
}
|
||||
Module module = je.getModule (moduleName);
|
||||
if (module == null && moduleName != null) {
|
||||
System.out.println ("Module '" + moduleName + "' not found");
|
||||
System.exit (-1);
|
||||
}
|
||||
OutputHandler about = je.getHandler (aboutHandler);
|
||||
if (about == null && aboutHandler != null) {
|
||||
System.out.println ("Handler '" + aboutHandler + "' not found");
|
||||
System.exit (-1);
|
||||
}
|
||||
OutputHandler handler = je.getHandler (handlerName);
|
||||
if (handler == null && handlerName != null) {
|
||||
System.out.println ("Handler '" + handlerName + "' not found");
|
||||
System.exit (-1);
|
||||
}
|
||||
String [] dirFileOrUri = null;
|
||||
int len = list.size ();
|
||||
if (len > 0) {
|
||||
dirFileOrUri = new String [len];
|
||||
for (int i=0; i<len; i++) {
|
||||
dirFileOrUri[i] = (String) list.get (i);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************
|
||||
* Invoke the JHOVE engine.
|
||||
**********************************************************/
|
||||
|
||||
je.setEncoding (encoding);
|
||||
je.setTempDirectory (tempDir);
|
||||
je.setBufferSize (bufferSize);
|
||||
je.setChecksumFlag (checksum);
|
||||
je.setShowRawFlag (showRaw);
|
||||
je.setSignatureFlag (signature);
|
||||
je.dispatch (app, module, about, handler, outputFile,
|
||||
dirFileOrUri);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace (System.err);
|
||||
System.exit (-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004-2008 by JSTOR and the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import edu.harvard.hul.ois.jhove.viewer.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* JhoveView - JSTOR/Harvard Object Validation Environment.
|
||||
*/
|
||||
public class JhoveView
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE CLASS FIELDS.
|
||||
*
|
||||
* Application constants.
|
||||
******************************************************************/
|
||||
|
||||
/** Application name. */
|
||||
private static final String NAME = "JhoveView";
|
||||
|
||||
/** Application build date, YYYY, MM, DD. */
|
||||
private static int [] _date;
|
||||
|
||||
/** Usage string is meaningless here. */
|
||||
private static final String USAGE = null;
|
||||
|
||||
/** Application release number. */
|
||||
private static String _release;
|
||||
|
||||
/** Default character encoding */
|
||||
//private static final String DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
/** Copyright information. */
|
||||
private static final String RIGHTS =
|
||||
"Derived from software Copyright 2004-2011 " +
|
||||
"by the President and Fellows of Harvard College. " +
|
||||
"Version 1.7 and higher independently released. " +
|
||||
"Released under the GNU Lesser General Public License.";
|
||||
|
||||
/******************************************************************
|
||||
* Configuration constants.
|
||||
******************************************************************/
|
||||
|
||||
/** Configuration file property. */
|
||||
// private static final String CONFIG_PROPERTY = "edu.harvard.hul.ois." +
|
||||
// "jhove.config";
|
||||
/** Jhove directory */
|
||||
// private static final String JHOVE_DIR = "jhove";
|
||||
|
||||
/** Config directory */
|
||||
// private static final String CONFIG_DIR = "conf";
|
||||
|
||||
/** SAX parser class property. */
|
||||
// private static final String SAX_PROPERTY = "edu.harvard.hul.ois.jhove." +
|
||||
// "saxClass";
|
||||
|
||||
/******************************************************************
|
||||
* Action constants.
|
||||
******************************************************************/
|
||||
|
||||
/******************************************************************
|
||||
* Exit code constants.
|
||||
******************************************************************/
|
||||
|
||||
/** General error. */
|
||||
private static final int ERROR = -1;
|
||||
|
||||
/** Incompatible Java VM. */
|
||||
private static final int INCOMPATIBLE_VM = -2;
|
||||
|
||||
/** File not writable. */
|
||||
//private static final int FILE_NOT_WRITABLE = -11;
|
||||
|
||||
/** No module specified. */
|
||||
//private static final int NO_MODULE = -21;
|
||||
|
||||
/** Module not found. */
|
||||
//private static final int MODULE_NOT_FOUND = -22;
|
||||
|
||||
/** Output handler not found. */
|
||||
//private static final int HANDLER_NOT_FOUND = -31;
|
||||
|
||||
/** No object specified. */
|
||||
//private static final int NO_OBJECT = -41;
|
||||
|
||||
/** URL not accessible. */
|
||||
//private static final int URL_NOT_ACCESSIBLE = -42;
|
||||
|
||||
/** File not found. */
|
||||
//private static final int FILE_NOT_FOUND = -43;
|
||||
|
||||
/** File not readable. */
|
||||
//private static final int FILE_NOT_READABLE = -44;
|
||||
|
||||
/** SAX parser not found. */
|
||||
//private static final int PARSER_NOT_FOUND = -51;
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC CLASS METHODS.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Stub constructor.
|
||||
*/
|
||||
|
||||
private JhoveView ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Application main entry point.
|
||||
* @parm args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
_release = JhoveBase._release; // Seems safer than final init
|
||||
_date = JhoveBase.DATE;
|
||||
/* Make sure we have a satisfactory version of Java. */
|
||||
String version = System.getProperty ("java.vm.version");
|
||||
if (version.compareTo ("1.4.0") < 0) {
|
||||
//System.err.println (NAME + ": Java 1.4 or higher is required");
|
||||
errorAlert ("Java 1.4 or higher is required");
|
||||
System.exit (INCOMPATIBLE_VM);
|
||||
}
|
||||
|
||||
// If we're running on a Macintosh, put the menubar at the top
|
||||
// of the screen where it belongs.
|
||||
System.setProperty ("apple.laf.useScreenMenuBar", "true");
|
||||
|
||||
App app = new App (NAME, _release, _date, USAGE, RIGHTS);
|
||||
try {
|
||||
|
||||
/**********************************************************
|
||||
* Retrieve the configuration file.
|
||||
**********************************************************/
|
||||
|
||||
String configFile = JhoveBase.getConfigFileFromProperties ();
|
||||
String saxClass = JhoveBase.getSaxClassFromProperties ();
|
||||
|
||||
/**********************************************************
|
||||
* Initialization:
|
||||
* configFile Configuration file pathname
|
||||
* saxClass SAX parser class
|
||||
**********************************************************/
|
||||
|
||||
/* Pre-parse the command line for -c and -x config options. */
|
||||
boolean quoted = false;
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (quoted) {
|
||||
int len = args[i].length ();
|
||||
if (args[i].charAt (len-1) == '"') {
|
||||
quoted = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (args[i].equals ("-c")) {
|
||||
if (i < args.length-1) {
|
||||
configFile = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].equals ("-x")) {
|
||||
if (i <args.length-1) {
|
||||
saxClass = args[++i];
|
||||
}
|
||||
}
|
||||
else if (args[i].charAt (0) == '"') {
|
||||
quoted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************
|
||||
* Initialize the JHOVE engine.
|
||||
**********************************************************/
|
||||
|
||||
JhoveBase je = new JhoveBase ();
|
||||
try {
|
||||
je.init (configFile, saxClass);
|
||||
}
|
||||
catch (JhoveException e) {
|
||||
errorAlert (e.getMessage ());
|
||||
// Keep going, so user can correct in editor
|
||||
}
|
||||
|
||||
// Create the main window to select a file.
|
||||
|
||||
JhoveWindow jwin = new JhoveWindow (app, je);
|
||||
jwin.setVisible (true);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace (System.err);
|
||||
System.exit (ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Displays an error alert. */
|
||||
private static void errorAlert (String msg)
|
||||
{
|
||||
JFrame hiddenFrame = new JFrame ();
|
||||
// Truncate long messages so the alert isn't wider
|
||||
// than the screen
|
||||
if (msg.length() > 80) {
|
||||
msg = msg.substring (0, 79) + "...";
|
||||
}
|
||||
JOptionPane.showMessageDialog (hiddenFrame,
|
||||
msg, "Jhove Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/**********************************************************************
|
||||
* PDump - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import edu.harvard.hul.ois.jhove.module.pdf.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Dump contents of PDF file in human-readable format.
|
||||
*/
|
||||
public class PDump
|
||||
extends Dump
|
||||
{
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
* @param args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
if (args.length < 1) {
|
||||
System.err.println ("usage: java PDump file");
|
||||
System.exit (-1);
|
||||
}
|
||||
|
||||
try {
|
||||
RandomAccessFile file = new RandomAccessFile (args[0], "r");
|
||||
Tokenizer tokenizer = new FileTokenizer (file);
|
||||
Token token = null;
|
||||
long offset = 0;
|
||||
while ((token = tokenizer.getNext ()) != null) {
|
||||
System.out.print (leading (offset, 8) + offset + ": ");
|
||||
if (token instanceof ArrayEnd) {
|
||||
System.out.println ("ArrayEnd");
|
||||
}
|
||||
else if (token instanceof ArrayStart) {
|
||||
System.out.println ("ArrayStart");
|
||||
}
|
||||
else if (token instanceof Comment) {
|
||||
System.out.println ("Comment \"" +
|
||||
((Comment) token).getValue () + "\"");
|
||||
}
|
||||
else if (token instanceof DictionaryEnd) {
|
||||
System.out.println ("DictionaryEnd");
|
||||
}
|
||||
else if (token instanceof DictionaryStart) {
|
||||
System.out.println ("DictionaryStart");
|
||||
}
|
||||
// else if (token instanceof Hexadecimal) {
|
||||
// System.out.println ("Hexadecimal[" +
|
||||
// (((Hexadecimal) token).isPDFDocEncoding () ?
|
||||
// "PDF" : "UTF-16") + "] \"" +
|
||||
// ((Hexadecimal) token).getValue () +
|
||||
// "\"");
|
||||
// }
|
||||
else if (token instanceof Keyword) {
|
||||
System.out.println ("Keyword \"" +
|
||||
((Keyword) token).getValue () + "\"");
|
||||
}
|
||||
else if (token instanceof Literal) {
|
||||
System.out.println ("Literal[" +
|
||||
(((Literal)token).isPDFDocEncoding () ?
|
||||
"PDF" : "UTF-16") + "] \"" +
|
||||
((Literal) token).getValue () + "\"");
|
||||
}
|
||||
else if (token instanceof Name) {
|
||||
System.out.println ("Name \"" +
|
||||
((Name) token).getValue () + "\"");
|
||||
}
|
||||
else if (token instanceof Numeric) {
|
||||
Numeric numeric = (Numeric) token;
|
||||
if (numeric.isReal ()) {
|
||||
System.out.println ("Numeric " + numeric.getValue ());
|
||||
}
|
||||
else {
|
||||
System.out.println ("Numeric " +
|
||||
numeric.getIntegerValue ());
|
||||
}
|
||||
}
|
||||
else if (token instanceof Stream) {
|
||||
System.out.println ("Stream " +
|
||||
((Stream) token).getLength ());
|
||||
}
|
||||
else {
|
||||
System.out.println (token);
|
||||
}
|
||||
offset = tokenizer.getOffset ();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace (System.err);
|
||||
System.exit (-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
/**********************************************************************
|
||||
* TDump - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003-2004 by JSTOR and the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import edu.harvard.hul.ois.jhove.module.tiff.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Dump contents of TIFF file in human-readable format.
|
||||
*/
|
||||
public class TDump
|
||||
extends Dump
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE CLASS FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Count of IFDs. */
|
||||
private static int _nIFDs;
|
||||
/** Sorted associative map of tags. */
|
||||
private static Map _tags;
|
||||
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
* @param args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
if (args.length < 1) {
|
||||
System.err.println ("usage: java TDump [-bs] file");
|
||||
System.exit (-1);
|
||||
}
|
||||
|
||||
String tiff = null;
|
||||
boolean nobyte = false;
|
||||
boolean nosub = false;
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i].equals ("-b")) {
|
||||
nobyte = true;
|
||||
}
|
||||
else if (args[i].equals ("-s")) {
|
||||
nosub = true;
|
||||
}
|
||||
else if (tiff == null) {
|
||||
tiff = args[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Accumlate all tag definitions in a sorted map. */
|
||||
|
||||
_tags = new TreeMap ();
|
||||
|
||||
int err = 0;
|
||||
try {
|
||||
|
||||
/* Read TIFF header. */
|
||||
|
||||
RandomAccessFile file = new RandomAccessFile (tiff, "r");
|
||||
boolean bigEndian = true;
|
||||
int b1 = ModuleBase.readUnsignedByte (file);
|
||||
int b2 = ModuleBase.readUnsignedByte (file);
|
||||
if (b1 == 0x49 && b2 == b1) {
|
||||
bigEndian = false;
|
||||
}
|
||||
int magic = ModuleBase.readUnsignedShort (file, bigEndian);
|
||||
long offset = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
_tags.put ("00000000", "\"" + ((char) b1) + ((char) b2) + "\" (" +
|
||||
(bigEndian ? "big" : "little") + " endian) " + magic +
|
||||
" LONG @" + offset);
|
||||
|
||||
/* Read IFDs. */
|
||||
|
||||
_nIFDs = 0;
|
||||
while ((offset = readIFD (file, bigEndian, offset, nobyte,
|
||||
nosub)) > 0) {
|
||||
}
|
||||
file.close ();
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace (System.out);
|
||||
err = -2;
|
||||
}
|
||||
finally {
|
||||
|
||||
/* Display all tags in offset-sorted order. */
|
||||
|
||||
Iterator iter = _tags.keySet ().iterator ();
|
||||
while (iter.hasNext ()) {
|
||||
String os = (String) iter.next ();
|
||||
System.out.println (os + ": " + (String) _tags.get (os));
|
||||
}
|
||||
if (err != 0) {
|
||||
System.exit (err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read IFDs.
|
||||
* @param file Open TIFF file
|
||||
* @param bigEndian True if big-endian
|
||||
* @param offset Byte offset of IFD
|
||||
* @param nobyte If true, only display the first 8 bytes of data of
|
||||
* type BYTE
|
||||
* @param nosub If true, do not parse subIFDs
|
||||
*/
|
||||
private static long readIFD (RandomAccessFile file, boolean bigEndian,
|
||||
long offset, boolean nobyte, boolean nosub)
|
||||
throws Exception
|
||||
{
|
||||
int nIFD = ++_nIFDs;
|
||||
List subIFDs = new ArrayList ();
|
||||
List stripByteCounts = new ArrayList ();
|
||||
List stripOffsets = new ArrayList ();
|
||||
|
||||
file.seek (offset);
|
||||
int nEntries = ModuleBase.readUnsignedShort (file, bigEndian);
|
||||
_tags.put (leading (offset, 8) + offset, "IFD " + nIFD + " with " +
|
||||
nEntries + " entries");
|
||||
|
||||
String name = null;
|
||||
for (int i=0; i<nEntries; i++) {
|
||||
long os = offset + 2 + i*12;
|
||||
file.seek (os);
|
||||
int tag = ModuleBase.readUnsignedShort (file, bigEndian);
|
||||
int type = ModuleBase.readUnsignedShort (file, bigEndian);
|
||||
long count = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
|
||||
StringBuffer buffer = new StringBuffer (tag + " (" +
|
||||
TiffTags.tagName(tag) +
|
||||
") " + IFD.TYPE[type] +
|
||||
" " + count);
|
||||
if (type == IFD.ASCII) {
|
||||
if (count > 4) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo);
|
||||
}
|
||||
StringBuffer ascii = new StringBuffer ();
|
||||
for (int j=0; j<count-1; j++) {
|
||||
ascii.append ((char) ModuleBase.readUnsignedByte (file));
|
||||
}
|
||||
buffer.append (" = \"" + ascii.toString () + "\"");
|
||||
}
|
||||
else if (type == IFD.BYTE ||
|
||||
type == IFD.UNDEFINED) {
|
||||
if (count > 4) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo);
|
||||
}
|
||||
buffer.append (" =");
|
||||
long ct = count;
|
||||
if (nobyte && count > 8) {
|
||||
ct = 8;
|
||||
}
|
||||
for (int j=0; j<ct; j++) {
|
||||
long by = ModuleBase.readUnsignedByte (file);
|
||||
buffer.append (" " + by);
|
||||
}
|
||||
if (nobyte && count > 8) {
|
||||
buffer.append (" ...");
|
||||
}
|
||||
}
|
||||
else if (type == IFD.DOUBLE) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo + " =");
|
||||
for (int j=0; j<count; j++) {
|
||||
double db = ModuleBase.readDouble (file, bigEndian);
|
||||
buffer.append (" " + db);
|
||||
}
|
||||
}
|
||||
else if (type == IFD.FLOAT) {
|
||||
if (count > 1) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo);
|
||||
}
|
||||
buffer.append (" =");
|
||||
for (int j=0; j<count; j++) {
|
||||
float fl = ModuleBase.readFloat (file, bigEndian);
|
||||
buffer.append (" " + fl);
|
||||
}
|
||||
}
|
||||
else if (type == IFD.LONG || type == IFD.IFD) {
|
||||
if (count > 1) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo + " = ");
|
||||
}
|
||||
else if (tag == 330 || /* Sub IFD */
|
||||
tag == 34665 || /* EXIF IFD */
|
||||
tag == 34853 || /* EXIF GPS IFD */
|
||||
tag == 40965) { /* EXIF Interoperability IFD */
|
||||
buffer.append (" @");
|
||||
}
|
||||
else {
|
||||
buffer.append (" = ");
|
||||
}
|
||||
for (int j=0; j<count; j++) {
|
||||
long in = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
if (j > 0) {
|
||||
buffer.append (" ");
|
||||
}
|
||||
buffer.append (in);
|
||||
|
||||
if (tag == 330 || /* Sub IFD */
|
||||
tag == 34665 || /* EXIF IFD */
|
||||
tag == 34853 || /* EXIF GPS IFD */
|
||||
tag == 40965) { /* EXIF Interoperability IFD */
|
||||
subIFDs.add (new Long (in));
|
||||
}
|
||||
else if (tag == 273) {
|
||||
stripOffsets.add (new Long (in));
|
||||
}
|
||||
else if (tag == 279) {
|
||||
stripByteCounts.add (new Long (in));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == IFD.RATIONAL) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo + " =");
|
||||
for (int j=0; j<count; j++) {
|
||||
long numer = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
long denom = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
buffer.append (" " + numer + "/" + denom);
|
||||
}
|
||||
}
|
||||
else if (type == IFD.SBYTE) {
|
||||
if (count > 4) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo);
|
||||
}
|
||||
buffer.append (" =");
|
||||
for (int j=0; j<count; j++) {
|
||||
long by = ModuleBase.readSignedByte (file);
|
||||
buffer.append (" " + by);
|
||||
}
|
||||
}
|
||||
else if (type == IFD.SHORT) {
|
||||
if (count > 2) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo);
|
||||
}
|
||||
buffer.append (" =");
|
||||
for (int j=0; j<count; j++) {
|
||||
int sh = ModuleBase.readUnsignedShort (file, bigEndian);
|
||||
buffer.append (" " + sh);
|
||||
|
||||
if (tag == 273) {
|
||||
stripOffsets.add (new Long ((long) sh));
|
||||
}
|
||||
else if (tag == 279) {
|
||||
stripByteCounts.add (new Long ((long) sh));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (type == IFD.SLONG) {
|
||||
if (count > 1) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo);
|
||||
}
|
||||
buffer.append (" =");
|
||||
for (int j=0; j<count; j++) {
|
||||
int in = ModuleBase.readSignedInt (file, bigEndian);
|
||||
buffer.append (" " + in);
|
||||
}
|
||||
}
|
||||
else if (type == IFD.SRATIONAL) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo + " =");
|
||||
for (int j=0; j<count; j++) {
|
||||
long numer = ModuleBase.readSignedInt (file, bigEndian);
|
||||
long denom = ModuleBase.readSignedInt (file, bigEndian);
|
||||
buffer.append (" " + numer + "/" + denom);
|
||||
}
|
||||
}
|
||||
else if (type == IFD.SSHORT) {
|
||||
if (count > 2) {
|
||||
long vo = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
file.seek (vo);
|
||||
|
||||
buffer.append (" @" + vo);
|
||||
}
|
||||
buffer.append (" =");
|
||||
for (int j=0; j<count; j++) {
|
||||
int sh = ModuleBase.readSignedShort (file, bigEndian);
|
||||
buffer.append (" " + sh);
|
||||
}
|
||||
}
|
||||
_tags.put (leading (os, 8) + os, buffer.toString ());
|
||||
}
|
||||
|
||||
if (!nosub) {
|
||||
for (int i=0; i<subIFDs.size (); i++) {
|
||||
long os = ((Long) subIFDs.get (i)).longValue ();
|
||||
while ((os = readIFD (file, bigEndian, os, nobyte, nosub)) > 0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long os = offset + 2 + nEntries*12;
|
||||
file.seek (os);
|
||||
long next = ModuleBase.readUnsignedInt (file, bigEndian);
|
||||
_tags.put (leading (os, 8) + os, "NextIFDOffset LONG @" + next);
|
||||
|
||||
int len = stripOffsets.size ();
|
||||
if (len > 0) {
|
||||
for (int j=0; j<len; j++) {
|
||||
long start = ((Long) stripOffsets.get (j)).longValue ();
|
||||
long count = ((Long) stripByteCounts.get (j)).longValue ();
|
||||
long finish= start + count - 1;
|
||||
_tags.put (leading (start, 8) + start, "(Image " + nIFD +
|
||||
",strip " + (j+1) + ") IMAGEDATA " + count +
|
||||
": ... " + leading (finish, 8) + finish);
|
||||
}
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/**********************************************************************
|
||||
* UserHome - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2006 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Determine the default value of the Java user.home property.
|
||||
*/
|
||||
public class UserHome
|
||||
{
|
||||
public static void main (String [] args)
|
||||
{
|
||||
System.out.println ("Default user.home is \"" +
|
||||
System.getProperty ("user.home") + "\"");
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/**********************************************************************
|
||||
* JDump - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004-2005 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
import edu.harvard.hul.ois.jhove.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Dump contents of WAVE file in human-readable format.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class WDump extends Dump {
|
||||
|
||||
/* Fixed value for first 4 bytes */
|
||||
private static final int[] sigByte =
|
||||
{ 0X52, 0X49, 0X46, 0X46 };
|
||||
|
||||
private static final boolean ENDIAN = false; /* little endian */
|
||||
|
||||
/******************************************************************
|
||||
* MAIN ENTRY POINT.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
* @param args Command line arguments
|
||||
*/
|
||||
public static void main (String [] args)
|
||||
{
|
||||
if (args.length < 1) {
|
||||
System.err.println ("usage: java WDump file");
|
||||
System.exit (-1);
|
||||
}
|
||||
try {
|
||||
FileInputStream file = new FileInputStream (args[0]);
|
||||
BufferedInputStream buffer = new BufferedInputStream (file);
|
||||
DataInputStream stream = new DataInputStream (buffer);
|
||||
ADump dump = new ADump (); // Just to access contained classes
|
||||
long os = 0;
|
||||
for (int i=0; i<4; i++) {
|
||||
int ch;
|
||||
ch = stream.readUnsignedByte();
|
||||
if (ch != sigByte[i]) {
|
||||
System.out.println ("No AIFF FORM header");
|
||||
System.exit (-2);
|
||||
}
|
||||
os++;
|
||||
}
|
||||
long ckSize = ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
os += 4;
|
||||
|
||||
// Read the file type
|
||||
String formType = read4Chars (stream);
|
||||
os += 4;
|
||||
|
||||
System.out.println ("00000000: RIFF " + ckSize + ": " + formType);
|
||||
|
||||
boolean endOfFile = false;
|
||||
while (!endOfFile) {
|
||||
// Read chunks
|
||||
try {
|
||||
// Read chunk name.
|
||||
String ckID = read4Chars (stream);
|
||||
// Read size (excluding chunk name and size fields)
|
||||
ckSize = ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
System.out.print (leading (os, 8) + os + ": " + ckID +
|
||||
" " + ckSize);
|
||||
long alreadyRead = 0;
|
||||
if (ckID.equals ("fact")) {
|
||||
long sampleLength =
|
||||
ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
System.out.print (": " + sampleLength);
|
||||
alreadyRead = 4;
|
||||
}
|
||||
else if (ckID.equals ("fmt ")) {
|
||||
int formatTag = ModuleBase.readUnsignedShort (stream,
|
||||
ENDIAN);
|
||||
int channels = ModuleBase.readUnsignedShort (stream,
|
||||
ENDIAN);
|
||||
long samplesPerSec =
|
||||
ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
long avgBytesPerSec =
|
||||
ModuleBase.readUnsignedInt (stream, ENDIAN);
|
||||
int blockAlign = ModuleBase.readUnsignedShort (stream,
|
||||
ENDIAN);
|
||||
String hex = Integer.toHexString (formatTag);
|
||||
System.out.print (": 0x" + leading (hex, 4) + hex +
|
||||
" " + channels + " " +
|
||||
samplesPerSec + " " +
|
||||
avgBytesPerSec + " " + blockAlign);
|
||||
alreadyRead = 14;
|
||||
if (ckSize > 14) {
|
||||
int bitsPerSample =
|
||||
ModuleBase.readUnsignedShort (stream, ENDIAN);
|
||||
System.out.print (" " + bitsPerSample);
|
||||
alreadyRead = 16;
|
||||
if (ckSize > 16) {
|
||||
int size =
|
||||
ModuleBase.readUnsignedShort (stream,
|
||||
ENDIAN);
|
||||
System.out.print (" " + size);
|
||||
alreadyRead = 18;
|
||||
if (size == 22) {
|
||||
int validBitsPerSample =
|
||||
ModuleBase.readUnsignedShort (stream,
|
||||
ENDIAN);
|
||||
long channelMask =
|
||||
ModuleBase.readUnsignedInt (stream,
|
||||
ENDIAN);
|
||||
hex = Long.toHexString (channelMask);
|
||||
System.out.print (" " +
|
||||
validBitsPerSample +
|
||||
" 0x" +
|
||||
leading (hex, 8) + hex +
|
||||
" 0x");
|
||||
for (int i=0; i<4; i++) {
|
||||
long guid =
|
||||
ModuleBase.readUnsignedInt (
|
||||
stream,
|
||||
ENDIAN);
|
||||
hex = Long.toHexString (guid);
|
||||
System.out.print (leading (hex, 8) +
|
||||
hex);
|
||||
}
|
||||
alreadyRead = 40;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println ();
|
||||
|
||||
if (ckID.equals ("list") || ckID.equals ("LIST")) {
|
||||
readNestedChunks (ckID, stream, ckSize, os + 8);
|
||||
}
|
||||
else {
|
||||
stream.skipBytes ((int) (ckSize - alreadyRead));
|
||||
}
|
||||
os += ckSize + 8;
|
||||
}
|
||||
catch (EOFException e) {
|
||||
endOfFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
/* The "list" and "LIST" chunks (which are two distinct chunk types)
|
||||
hold nested chunks. */
|
||||
private static void readNestedChunks
|
||||
(String ckID, DataInputStream stream, long ckSize, long os)
|
||||
throws IOException
|
||||
{
|
||||
String listType = read4Chars (stream);
|
||||
System.out.println ("List type = " + listType);
|
||||
while (ckSize > 0) {
|
||||
String subCkID = read4Chars (stream);
|
||||
long subCkSize = ModuleBase.readUnsignedInt (stream, ENDIAN, null);
|
||||
System.out.println (leading (os, 8) + os + ": " +
|
||||
ckID + "/" + subCkID + " " + subCkSize);
|
||||
stream.skipBytes ((int) subCkSize);
|
||||
os += subCkSize + 8;
|
||||
ckSize -= subCkSize + 8;
|
||||
}
|
||||
}
|
||||
|
||||
private static String read4Chars (DataInputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
StringBuffer sbuf = new StringBuffer(4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int ch = ModuleBase.readUnsignedByte(stream, null);
|
||||
sbuf.append((char) ch);
|
||||
}
|
||||
return sbuf.toString ();
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
<project name="Jhove" default="main-dist" basedir=".">
|
||||
<description>Main build file
|
||||
Jhove - JSTOR/Harvard Object Validation Environment
|
||||
Version 1.1 2006-02-13
|
||||
Copyright 2004-2006 by JSTOR and the President and Fellows of Harvard College
|
||||
</description>
|
||||
|
||||
<!-- set global properties for this build -->
|
||||
<property name="classpath" value=".:../bin/jhove.jar"/>
|
||||
<property name="api" location="edu/harvard/hul/ois/jhove"/>
|
||||
<property name="viewer" location="edu/harvard/hul/ois/jhove/viewer"/>
|
||||
<property name="root" location=".."/>
|
||||
<property name="manifest" location="${viewer}/META-INF"/>
|
||||
|
||||
<target name="main-init" description="Create the time stamp">
|
||||
<tstamp>
|
||||
<format property="timestamp.isoformat" pattern="yyyy-MM-dd'T'HH:mm:ss"/>
|
||||
</tstamp>
|
||||
</target>
|
||||
|
||||
<target name="main-dist" depends="api,main,view"/>
|
||||
|
||||
<target name="api" description="Compile the API">
|
||||
<ant dir="${api}" inheritAll="false">
|
||||
<property name="dbg" value="${dbg}"/>
|
||||
</ant>
|
||||
</target>
|
||||
|
||||
<target name="main-compile" depends="main-init"
|
||||
description="Compile the main file">
|
||||
<javac compiler="javac1.5" target="1.5" srcdir="." debug="${dbg}" classpath="${classpath}"/>
|
||||
</target>
|
||||
|
||||
<target name="main" depends="main-compile, app-manifest"
|
||||
description="Build the app jar">
|
||||
<jar destfile="${root}/bin/JhoveApp.jar" basedir="." index="true"
|
||||
manifest="./META-INF/MANIFEST.MF"
|
||||
includes="Jhove.class,
|
||||
GDump.class, JDump.class, PDump.class, TDump.class,
|
||||
J2Dump.class,J2Dump$Box.class,
|
||||
ADump.class,
|
||||
WDump.class, UserHome.class,
|
||||
edu/harvard/hul/ois/jhove/*.class,
|
||||
edu/harvard/hul/ois/jhove/*.xsd,
|
||||
edu/harvard/hul/ois/jhove/handler/*.class,
|
||||
edu/harvard/hul/ois/jhove/handler/audit/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/aiff/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/gif/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/html/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/html/*.dtd,
|
||||
edu/harvard/hul/ois/jhove/module/html/*.ent,
|
||||
edu/harvard/hul/ois/jhove/module/iff/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/jpeg/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/jpeg2000/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/pdf/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/tiff/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/wave/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/xml/*.class"/>
|
||||
</target>
|
||||
|
||||
<target name="app-manifest" depends="main-init">
|
||||
<mkdir dir="${manifest}"/>
|
||||
<manifest file="./META-INF/MANIFEST.MF">
|
||||
<attribute name="Built-By" value="${user.name}"/>
|
||||
<attribute name="Built-On" value="${timestamp.isoformat}"/>
|
||||
<attribute name="Main-Class" value="Jhove"/>
|
||||
<section name="JHOVE">
|
||||
<attribute name="Version" value="1.0"/>
|
||||
<attribute name="Package" value="Jhove app"/>
|
||||
<attribute name="Rights" value="Copyright 2004-2006 by JSTOR and the President and Fellows of Harvard College"/>
|
||||
</section>
|
||||
</manifest>
|
||||
</target>
|
||||
|
||||
<target name="view-manifest" depends="main-init">
|
||||
<mkdir dir="${manifest}"/>
|
||||
<manifest file="${manifest}/MANIFEST.MF">
|
||||
<attribute name="Built-By" value="${user.name}"/>
|
||||
<attribute name="Built-On" value="${timestamp.isoformat}"/>
|
||||
<attribute name="Main-Class" value="JhoveView"/>
|
||||
<section name="JHOVE">
|
||||
<attribute name="Version" value="1.0"/>
|
||||
<attribute name="Package" value="Swing Viewer"/>
|
||||
<attribute name="Rights" value="Copyright 2004-2006 by JSTOR and the President and Fellows of Harvard College"/>
|
||||
</section>
|
||||
</manifest>
|
||||
</target>
|
||||
|
||||
<target name="view" description="Compile the viewer application"
|
||||
depends="api,main,view-manifest">
|
||||
<jar destfile="${root}/bin/JhoveView.jar" basedir="." index="true"
|
||||
manifest="${manifest}/MANIFEST.MF"
|
||||
includes="JhoveView.class,
|
||||
edu/harvard/hul/ois/jhove/*.class,
|
||||
edu/harvard/hul/ois/jhove/handler/*.class,
|
||||
edu/harvard/hul/ois/jhove/handler/audit/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/aiff/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/gif/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/html/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/html/*.dtd,
|
||||
edu/harvard/hul/ois/jhove/module/html/*.ent,
|
||||
edu/harvard/hul/ois/jhove/module/iff/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/jpeg/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/jpeg2000/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/pdf/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/tiff/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/wave/*.class,
|
||||
edu/harvard/hul/ois/jhove/module/xml/*.class,
|
||||
edu/harvard/hul/ois/jhove/viewer/*.gif,
|
||||
edu/harvard/hul/ois/jhove/viewer/*.class"/>
|
||||
</target>
|
||||
|
||||
<target name="main-clean">
|
||||
<delete>
|
||||
<fileset dir="." includes="*~ \#*"/>
|
||||
</delete>
|
||||
<ant dir="${api}" target="api-clean" inheritAll="false"/>
|
||||
</target>
|
||||
|
||||
<target name="main-cleanclass">
|
||||
<delete>
|
||||
<fileset dir="." includes="*.class*"/>
|
||||
</delete>
|
||||
<ant dir="${api}" target="api-cleanclass" inheritAll="false"/>
|
||||
</target>
|
||||
</project>
|
||||
@@ -1,940 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004-2005 by JSTOR and the President and Fellows of Harvard College
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Encapsulation of the AES Metadata for Audio documents
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class AESAudioMetadata
|
||||
{
|
||||
/******************************************************************
|
||||
* PUBLIC CLASS FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Big-endian constant. */
|
||||
public static final int BIG_ENDIAN = 0;
|
||||
|
||||
/** Little-endian constant. */
|
||||
public static final int LITTLE_ENDIAN = 1;
|
||||
|
||||
/** Analog / digital labels. */
|
||||
public static final String [] A_D = {
|
||||
"ANALOG", "PHYS_DIGITAL", "FILE_DIGITAL"
|
||||
};
|
||||
|
||||
/** Values for primary identifier type */
|
||||
public static final String
|
||||
FILE_NAME = "FILE_NAME",
|
||||
OTHER = "OTHER";
|
||||
|
||||
/** Constant for an undefined integer value. */
|
||||
public static final int NULL = -1;
|
||||
/** Constant for an undefined floating-point value. */
|
||||
public static final double NILL = -1.0;
|
||||
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
/** Constant value for the SchemaVersion field */
|
||||
public static final String SCHEMA_VERSION = "1.02b";
|
||||
|
||||
/** Constant value for the disposition field */
|
||||
private static final String DEFAULT_DISPOSITION = "validation";
|
||||
|
||||
private String _analogDigitalFlag;
|
||||
private String _appSpecificData;
|
||||
private String _audioDataEncoding;
|
||||
private int _byteOrder;
|
||||
private String _disposition;
|
||||
private List _faceList;
|
||||
private long _firstSampleOffset;
|
||||
private String _format;
|
||||
private List _formatList;
|
||||
private int _numChannels;
|
||||
private String _primaryIdentifier;
|
||||
private String _primaryIdentifierType;
|
||||
private String _primaryIdentifierOtherType;
|
||||
private String _schemaVersion;
|
||||
private String _specificationVersion;
|
||||
private String[] _use;
|
||||
|
||||
/* Most recently added FormatRegion */
|
||||
private FormatRegion _curFormatRegion;
|
||||
/* Most recently added Face */
|
||||
private Face _curFace;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/** Instantiate a <code>NisoImageMetadata</code> object.
|
||||
*/
|
||||
public AESAudioMetadata ()
|
||||
{
|
||||
_schemaVersion = SCHEMA_VERSION;
|
||||
_disposition = DEFAULT_DISPOSITION;
|
||||
_analogDigitalFlag = null;
|
||||
_format = null;
|
||||
_specificationVersion = null;
|
||||
_audioDataEncoding = null;
|
||||
_primaryIdentifier = null;
|
||||
_primaryIdentifierType = null;
|
||||
_use = null;
|
||||
|
||||
// We add one format region to get started. In practice,
|
||||
// that one is all we're likely to need. but more can be
|
||||
// added if necessary.
|
||||
_formatList = new LinkedList ();
|
||||
_faceList = new LinkedList ();
|
||||
addFormatRegion ();
|
||||
addFace ();
|
||||
_numChannels = NULL;
|
||||
_byteOrder = NULL;
|
||||
_firstSampleOffset = NULL;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC STATIC INTERFACES.
|
||||
*
|
||||
******************************************************************/
|
||||
/**
|
||||
* Public interface to the nested FormatRegion object. Instances
|
||||
* of this should be created only by addFormatRegion, but can be
|
||||
* accessed through the public methods of this interface.
|
||||
*/
|
||||
public static interface FormatRegion {
|
||||
/** Returns the bit depth. */
|
||||
public int getBitDepth ();
|
||||
/** Returns the bitrate reduction (compression information).
|
||||
* This will be an array of seven strings (which may be
|
||||
* empty, but should never be null) interpreted as follows:
|
||||
* <ul>
|
||||
* <li>0: codecName
|
||||
* <li>1: codecNameVersion
|
||||
* <li>2: codecCreatorApplication
|
||||
* <li>3: codecCreatorApplicationVersion
|
||||
* <li>4: codecQuality
|
||||
* <li>5: dataRate
|
||||
* <li>6: dataRateMode
|
||||
* </ul>
|
||||
*/
|
||||
public String[] getBitrateReduction ();
|
||||
/** Returns the sample rate. */
|
||||
public double getSampleRate ();
|
||||
/** Returns the word size. */
|
||||
int getWordSize ();
|
||||
/** Returns <code>true</code> if the region is empty. */
|
||||
public boolean isEmpty ();
|
||||
/** Sets the bit depth value. */
|
||||
public void setBitDepth (int bitDepth);
|
||||
/** Sets the bitrate reduction information to null (no compression). */
|
||||
public void clearBitrateReduction ();
|
||||
/** Sets the bitrate reduction (aka compression type). */
|
||||
public void setBitrateReduction (String codecName,
|
||||
String codecNameVersion,
|
||||
String codecCreatorApplication,
|
||||
String codecCreatorApplicationVersion,
|
||||
String codecQuality,
|
||||
String dataRate,
|
||||
String dataRateMode);
|
||||
/** Sets the sample rate. */
|
||||
public void setSampleRate (double sampleRate);
|
||||
/** Sets the word size. */
|
||||
public void setWordSize (int wordSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public interface to the nested TimeDesc object. Instances
|
||||
* of this should be created only by appropriate methods, but can be
|
||||
* accessed through the public methods of this interface.
|
||||
*/
|
||||
public static interface TimeDesc {
|
||||
/** Returns the hours component. */
|
||||
public int getHours ();
|
||||
/** Returns the minutes component. */
|
||||
public int getMinutes ();
|
||||
/** Returns the seconds component. */
|
||||
public int getSeconds ();
|
||||
/** Returns the frames component of the fraction of a second.
|
||||
* We always consider frames to be thirtieths of a second. */
|
||||
public int getFrames ();
|
||||
/** Returns the samples remaining after the frames part of
|
||||
* the fractional second. */
|
||||
public int getSamples ();
|
||||
/** Returns the sample rate on which the samples remainder
|
||||
* is based. */
|
||||
public double getSampleRate ();
|
||||
}
|
||||
|
||||
/** Public interface to the nested Face object. Instances
|
||||
* of this should be created only by appropriate methods, but can be
|
||||
* accessed through the public methods of this interface. */
|
||||
public static interface Face {
|
||||
/** Returns an indexed FaceRegion. */
|
||||
public FaceRegion getFaceRegion (int i);
|
||||
|
||||
/** Adds a FaceRegion. This may be called repeatedly to
|
||||
* add multiple FaceRegions. */
|
||||
public void addFaceRegion ();
|
||||
|
||||
/** Returns the starting time. */
|
||||
public TimeDesc getStartTime ();
|
||||
|
||||
/** Returns the duration. */
|
||||
public TimeDesc getDuration ();
|
||||
|
||||
/** Returns the direction. */
|
||||
public String getDirection ();
|
||||
|
||||
/** Sets the starting time. This will be converted
|
||||
* into a TimeDesc. */
|
||||
public void setStartTime (long samples);
|
||||
|
||||
/** Sets the duration. This will be converted
|
||||
* into a TimeDesc. */
|
||||
public void setDuration (long samples);
|
||||
|
||||
/** Sets the direction. This must be one of the
|
||||
* directionTypes. FORWARD is recommended for most
|
||||
* or all cases.
|
||||
*/
|
||||
public void setDirection (String direction);
|
||||
|
||||
/* End of interface Face */
|
||||
}
|
||||
|
||||
/** Public interface to the nested FaceRegion object. Instances
|
||||
* of this should be created only by appropriate methods, but can be
|
||||
* accessed through the public methods of this interface. */
|
||||
public static interface FaceRegion {
|
||||
/** Returns the starting time. */
|
||||
public TimeDesc getStartTime ();
|
||||
|
||||
/** Returns the duration. */
|
||||
public TimeDesc getDuration ();
|
||||
|
||||
/** Returns the channel map locations. The array length must
|
||||
* equal the number of channels. */
|
||||
public String[] getMapLocations ();
|
||||
|
||||
/** Sets the starting time. */
|
||||
public void setStartTime (long samples);
|
||||
|
||||
/** Sets the duration. */
|
||||
public void setDuration (long samples);
|
||||
|
||||
/** Sets the channel map locations. The array length must
|
||||
* equal the number of channels. */
|
||||
public void setMapLocations (String[] locations);
|
||||
|
||||
/* End of interface FaceRegion */
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* STATIC MEMBER CLASSES.
|
||||
*
|
||||
******************************************************************/
|
||||
/** The implementation of the FormatRegion interface. The combination
|
||||
* of a public interface and a private implementation is suggested
|
||||
* in _Java in a Nutshell_.
|
||||
*/
|
||||
class FormatRegionImpl implements FormatRegion {
|
||||
|
||||
private int _bitDepth;
|
||||
private double _sampleRate;
|
||||
private int _wordSize;
|
||||
private String[] _bitrateReduction;
|
||||
|
||||
public FormatRegionImpl () {
|
||||
_bitDepth = NULL;
|
||||
_sampleRate = NILL;
|
||||
_wordSize = NULL;
|
||||
_bitrateReduction = null;
|
||||
}
|
||||
|
||||
/** Returns bit depth. */
|
||||
public int getBitDepth ()
|
||||
{
|
||||
return _bitDepth;
|
||||
}
|
||||
|
||||
/** Returns the bitrate reduction (compression information).
|
||||
* This will be an array of seven strings (which may be
|
||||
* empty but not null) interpreted respectively as follows:
|
||||
* <ul>
|
||||
* <li>0: codecName
|
||||
* <li>1: codecNameVersion
|
||||
* <li>2: codecCreatorApplication
|
||||
* <li>3: codecCreatorApplicationVersion
|
||||
* <li>4: codecQuality
|
||||
* <li>5: dataRate
|
||||
* <li>6: dataRateMode
|
||||
* </ul>
|
||||
*/
|
||||
public String[] getBitrateReduction ()
|
||||
{
|
||||
return _bitrateReduction;
|
||||
}
|
||||
|
||||
/** Returns sample rate. */
|
||||
public double getSampleRate ()
|
||||
{
|
||||
return _sampleRate;
|
||||
}
|
||||
|
||||
/** Returns word size. */
|
||||
public int getWordSize ()
|
||||
{
|
||||
return _wordSize;
|
||||
}
|
||||
|
||||
/** Returns true if the FormatRegion contains only
|
||||
* default values. */
|
||||
public boolean isEmpty ()
|
||||
{
|
||||
return _bitDepth == NULL &&
|
||||
_sampleRate == NILL &&
|
||||
_wordSize == NULL;
|
||||
}
|
||||
|
||||
/** Sets bit depth. */
|
||||
public void setBitDepth (int bitDepth)
|
||||
{
|
||||
_bitDepth = bitDepth;
|
||||
}
|
||||
|
||||
/** Sets the bitrate reduction information to null (no compression). */
|
||||
public void clearBitrateReduction ()
|
||||
{
|
||||
_bitrateReduction = null;
|
||||
}
|
||||
|
||||
/** Sets the bitrate reduction (compression type). */
|
||||
public void setBitrateReduction (String codecName,
|
||||
String codecNameVersion,
|
||||
String codecCreatorApplication,
|
||||
String codecCreatorApplicationVersion,
|
||||
String codecQuality,
|
||||
String dataRate,
|
||||
String dataRateMode)
|
||||
{
|
||||
_bitrateReduction = new String[7];
|
||||
_bitrateReduction[0] = codecName;
|
||||
_bitrateReduction[1] = codecNameVersion;
|
||||
_bitrateReduction[2] = codecCreatorApplication;
|
||||
_bitrateReduction[3] = codecCreatorApplicationVersion;
|
||||
_bitrateReduction[4] = codecQuality;
|
||||
_bitrateReduction[5] = dataRate;
|
||||
_bitrateReduction[6] = dataRateMode;
|
||||
}
|
||||
|
||||
/** Sets sample rate. */
|
||||
public void setSampleRate (double sampleRate)
|
||||
{
|
||||
_sampleRate = sampleRate;
|
||||
}
|
||||
|
||||
|
||||
/** Sets word size. */
|
||||
public void setWordSize (int wordSize)
|
||||
{
|
||||
_wordSize = wordSize;
|
||||
}
|
||||
|
||||
/* End of FormatRegionImpl */
|
||||
}
|
||||
|
||||
/** The implementation of the TimeDesc interface. The combination
|
||||
* of a public interface and a private implementation is suggested
|
||||
* in _Java in a Nutshell_.
|
||||
*/
|
||||
class TimeDescImpl implements TimeDesc
|
||||
{
|
||||
private int _hours;
|
||||
private int _minutes;
|
||||
private int _seconds;
|
||||
private int _frames;
|
||||
private int _samples;
|
||||
private double _sampleRate;
|
||||
private int _frameCount;
|
||||
|
||||
/* Constructor rewritten to avoid rounding errors when converting to
|
||||
* TCF. Now uses integer remainder math instead of floating point.
|
||||
* Changed the base unit from a double representing seconds to a long
|
||||
* representing samples. Changed all existing calls (that I could find)
|
||||
* to this method to accomodate this change.
|
||||
*
|
||||
* @author David Ackerman
|
||||
*/
|
||||
public TimeDescImpl (long samples)
|
||||
{
|
||||
long _sample_count = samples;
|
||||
_frameCount = 30;
|
||||
_sampleRate = _curFormatRegion.getSampleRate ();
|
||||
|
||||
/* It seems that this method is initially called before a valid
|
||||
* sample rate has been established, causing a divide by zero
|
||||
* error.
|
||||
*/
|
||||
if (_sampleRate < 0) {
|
||||
_sampleRate = 44100.0; //reasonable default value
|
||||
}
|
||||
|
||||
long sample_in_1_frame = (long)(_sampleRate/_frameCount);
|
||||
long sample_in_1_second = sample_in_1_frame * _frameCount;
|
||||
long sample_in_1_minute = sample_in_1_frame * _frameCount * 60;
|
||||
long sample_in_1_hour = sample_in_1_frame * _frameCount * 60 * 60;
|
||||
long sample_in_1_day = sample_in_1_frame * _frameCount * 60 * 60 * 24;
|
||||
|
||||
// BWF allows for a negative timestamp but tcf does not, so adjust
|
||||
// time accordingly
|
||||
// this might be a good place to report a warning during validation
|
||||
if (_sample_count < 0) {
|
||||
_sample_count += sample_in_1_day;
|
||||
_sample_count = (_sample_count % sample_in_1_day);
|
||||
}
|
||||
|
||||
_hours = (int)(_sample_count / sample_in_1_hour);
|
||||
_sample_count -= (_hours * sample_in_1_hour);
|
||||
_minutes = (int)(_sample_count / sample_in_1_minute);
|
||||
_sample_count -= (_minutes * sample_in_1_minute);
|
||||
_seconds = (int)(_sample_count / sample_in_1_second);
|
||||
_sample_count -= (_seconds * sample_in_1_second);
|
||||
_frames = (int)(_sample_count / sample_in_1_frame);
|
||||
_sample_count -= (_frames * sample_in_1_frame);
|
||||
_samples = (int)_sample_count;
|
||||
|
||||
/* At present TCF does not have the ability to handle time stamps
|
||||
* > midnight. Industry practice is to roll the clock forward to
|
||||
* zero or back to 23:59:59:29... when crossing this boundary
|
||||
* condition.
|
||||
*/
|
||||
_hours = _hours % 24;
|
||||
}
|
||||
|
||||
/** Returns the hours component. */
|
||||
public int getHours () {
|
||||
return _hours;
|
||||
}
|
||||
|
||||
/** Returns the minutes component. */
|
||||
public int getMinutes () {
|
||||
return _minutes;
|
||||
}
|
||||
|
||||
/** Returns the seconds component. */
|
||||
public int getSeconds () {
|
||||
return _seconds;
|
||||
}
|
||||
|
||||
/** Returns the frames component of the fraction of a second.
|
||||
* We always consider frames to be thirtieths of a second. */
|
||||
public int getFrames () {
|
||||
return _frames;
|
||||
}
|
||||
|
||||
/** Returns the samples remaining after the frames part of
|
||||
* the fractional second. */
|
||||
public int getSamples () {
|
||||
return _samples;
|
||||
}
|
||||
|
||||
/** Returns the sample rate on which the samples remainder
|
||||
* is based. */
|
||||
public double getSampleRate () {
|
||||
return _sampleRate;
|
||||
}
|
||||
} /* End of TimeDescImpl */
|
||||
|
||||
/** The implementation of the Face interface. The combination
|
||||
* of a public interface and a private implementation is suggested
|
||||
* in _Java in a Nutshell_.
|
||||
*/
|
||||
class FaceImpl implements Face {
|
||||
List _regionList;
|
||||
TimeDesc _startTime;
|
||||
TimeDesc _duration;
|
||||
String _direction;
|
||||
|
||||
|
||||
/** Constructor. Initially the duration is set
|
||||
* to null, indicating unknown value. */
|
||||
public FaceImpl ()
|
||||
{
|
||||
_regionList = new ArrayList ();
|
||||
_startTime = new TimeDescImpl (0);
|
||||
_duration = null;
|
||||
}
|
||||
|
||||
|
||||
/** Returns an indexed FaceRegion. */
|
||||
public FaceRegion getFaceRegion (int i) {
|
||||
return (FaceRegion) _regionList.get (i);
|
||||
}
|
||||
|
||||
/** Adds a FaceRegion. This may be called repeatedly to
|
||||
* add multiple FaceRegions. */
|
||||
public void addFaceRegion () {
|
||||
_regionList.add (new FaceRegionImpl ());
|
||||
}
|
||||
|
||||
/** Returns the starting time. Will be zero if not
|
||||
* explicitly specified. */
|
||||
public TimeDesc getStartTime () {
|
||||
return _startTime;
|
||||
}
|
||||
|
||||
/** Returns the duration. May be null if the duration
|
||||
* is unspecified. */
|
||||
public TimeDesc getDuration () {
|
||||
return _duration;
|
||||
}
|
||||
|
||||
/** Returns the direction. */
|
||||
public String getDirection ()
|
||||
{
|
||||
return _direction;
|
||||
}
|
||||
|
||||
/** Sets the starting time. This will be converted
|
||||
* into a TimeDesc. */
|
||||
public void setStartTime (long samples)
|
||||
{
|
||||
_startTime = new TimeDescImpl (samples);
|
||||
}
|
||||
|
||||
/** Sets the duration. This will be converted
|
||||
* into a TimeDesc. */
|
||||
public void setDuration (long samples)
|
||||
{
|
||||
_duration = new TimeDescImpl (samples);
|
||||
}
|
||||
|
||||
/** Sets the direction. This must be one of the
|
||||
* directionTypes. FORWARD is recommended for most
|
||||
* or all cases.
|
||||
*/
|
||||
public void setDirection (String direction)
|
||||
{
|
||||
_direction = direction;
|
||||
}
|
||||
|
||||
/* End of FaceImpl */
|
||||
}
|
||||
|
||||
|
||||
/** The implementation of the Face interface. The combination
|
||||
* of a public interface and a private implementation is suggested
|
||||
* in _Java in a Nutshell_.
|
||||
*/
|
||||
class FaceRegionImpl implements FaceRegion {
|
||||
private TimeDesc _startTime;
|
||||
private TimeDesc _duration;
|
||||
private String[] _mapLocations;
|
||||
|
||||
public FaceRegionImpl ()
|
||||
{
|
||||
_startTime = new TimeDescImpl (0);
|
||||
_duration = null;
|
||||
}
|
||||
|
||||
/** Returns the starting time. */
|
||||
public TimeDesc getStartTime () {
|
||||
return _startTime;
|
||||
}
|
||||
|
||||
/** Returns the duration. */
|
||||
public TimeDesc getDuration () {
|
||||
return _duration;
|
||||
}
|
||||
|
||||
/** Returns the channel map locations. The array length
|
||||
* will equal the number of channels. */
|
||||
public String[] getMapLocations ()
|
||||
{
|
||||
return _mapLocations;
|
||||
}
|
||||
|
||||
/** Sets the duration. This will be converted
|
||||
* into a TimeDesc. */
|
||||
public void setStartTime (long samples) {
|
||||
_startTime = new TimeDescImpl (samples);
|
||||
}
|
||||
|
||||
/** Sets the duration. This will be converted
|
||||
* into a TimeDesc. */
|
||||
public void setDuration (long samples)
|
||||
{
|
||||
_duration = new TimeDescImpl (samples);
|
||||
}
|
||||
|
||||
/** Sets the channel map locations. The array length must
|
||||
* equal the number of channels. */
|
||||
public void setMapLocations (String[] locations)
|
||||
{
|
||||
_mapLocations = locations;
|
||||
}
|
||||
/* End of FaceRegionImpl */
|
||||
}
|
||||
|
||||
/* End of inner classes */
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Accessor methods.
|
||||
******************************************************************/
|
||||
|
||||
/** Returns analog/digital flag. Value will always be
|
||||
* "FILE_DIGITAL" in practice. */
|
||||
public String getAnalogDigitalFlag ()
|
||||
{
|
||||
return _analogDigitalFlag;
|
||||
}
|
||||
|
||||
/** Returns application-specific data. We assume this is
|
||||
* representable in String format.
|
||||
*/
|
||||
public String getAppSpecificData ()
|
||||
{
|
||||
return _appSpecificData;
|
||||
}
|
||||
|
||||
/** Returns audio data encoding. */
|
||||
public String getAudioDataEncoding ()
|
||||
{
|
||||
return _audioDataEncoding;
|
||||
}
|
||||
|
||||
/** Returns the bitrate reduction (compression information).
|
||||
* This will be an array of seven strings (which may be
|
||||
* empty, but should never be null) interpreted as follows:
|
||||
* <ul>
|
||||
* <li>0: codecName
|
||||
* <li>1: codecNameVersion
|
||||
* <li>2: codecCreatorApplication
|
||||
* <li>3: codecCreatorApplicationVersion
|
||||
* <li>4: codecQuality
|
||||
* <li>5: dataRate
|
||||
* <li>6: dataRateMode
|
||||
* </ul>
|
||||
*/
|
||||
public String[] getBitrateReduction ()
|
||||
{
|
||||
return _curFormatRegion.getBitrateReduction();
|
||||
}
|
||||
|
||||
/* Returns the sample rate. */
|
||||
public double getSampleRate ()
|
||||
{
|
||||
return _curFormatRegion.getSampleRate ();
|
||||
}
|
||||
|
||||
/** Return the byte order: 0 = big-endian; 1 = little-endian. */
|
||||
public int getByteOrder ()
|
||||
{
|
||||
return _byteOrder;
|
||||
}
|
||||
|
||||
/** Returns disposition. */
|
||||
public String getDisposition ()
|
||||
{
|
||||
return _disposition;
|
||||
}
|
||||
|
||||
/** Gets the list of Faces. Normally there will be only one face
|
||||
* in a digital file. */
|
||||
public List getFaceList ()
|
||||
{
|
||||
return _faceList;
|
||||
}
|
||||
|
||||
/** Return the offset of the first byte of sample data. */
|
||||
public long getFirstSampleOffset ()
|
||||
{
|
||||
return _firstSampleOffset;
|
||||
}
|
||||
|
||||
/** Returns format name. */
|
||||
public String getFormat ()
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
|
||||
/** Gets the list of Format Regions. Since one is created
|
||||
* automatically on initialization, it's possible that the
|
||||
* list will contain a Format Region with only default values.
|
||||
* This should be checked with isEmpty ().
|
||||
*/
|
||||
public List getFormatList ()
|
||||
{
|
||||
return _formatList;
|
||||
}
|
||||
|
||||
/** Returns the names of the map locations.
|
||||
* The returned
|
||||
* value is an array whose length equals the number of
|
||||
* channels and whose elements correspond to channels 0, 1,
|
||||
* etc.
|
||||
*/
|
||||
public String[] getMapLocations() {
|
||||
return _curFace.getFaceRegion(0).getMapLocations();
|
||||
}
|
||||
|
||||
/** Returns number of channels. */
|
||||
public int getNumChannels ()
|
||||
{
|
||||
return _numChannels;
|
||||
}
|
||||
|
||||
/** Returns primary identifier. */
|
||||
public String getPrimaryIdentifier ()
|
||||
{
|
||||
return _primaryIdentifier;
|
||||
}
|
||||
|
||||
/** Returns primary identifier type. */
|
||||
public String getPrimaryIdentifierType ()
|
||||
{
|
||||
return _primaryIdentifierType;
|
||||
}
|
||||
|
||||
/** Returns schema version. */
|
||||
public String getSchemaVersion ()
|
||||
{
|
||||
return _schemaVersion;
|
||||
}
|
||||
|
||||
/** Returns specification version of the document format. */
|
||||
public String getSpecificationVersion ()
|
||||
{
|
||||
return _specificationVersion;
|
||||
}
|
||||
|
||||
/** Returns the use (role of the document).
|
||||
* The value returned is an array of two strings,
|
||||
* the useType and the otherType. */
|
||||
public String[] getUse ()
|
||||
{
|
||||
return _use;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Mutator methods.
|
||||
******************************************************************/
|
||||
|
||||
/** Sets the analog/digital flag. The value set should always
|
||||
* be "FILE_DIGITAL". */
|
||||
public void setAnalogDigitalFlag (String flagType)
|
||||
{
|
||||
_analogDigitalFlag = flagType;
|
||||
}
|
||||
|
||||
/** Sets the bitrate reduction (compression type). */
|
||||
public void setBitrateReduction (String codecName,
|
||||
String codecNameVersion,
|
||||
String codecCreatorApplication,
|
||||
String codecCreatorApplicationVersion,
|
||||
String codecQuality,
|
||||
String dataRate,
|
||||
String dataRateMode)
|
||||
{
|
||||
_curFormatRegion.setBitrateReduction (codecName,
|
||||
codecNameVersion, codecCreatorApplication,
|
||||
codecCreatorApplicationVersion,
|
||||
codecQuality, dataRate, dataRateMode);
|
||||
}
|
||||
|
||||
/** Set the bitrate reduction information to null (no compression). */
|
||||
public void clearBitrateReduction ()
|
||||
{
|
||||
_curFormatRegion.clearBitrateReduction ();
|
||||
}
|
||||
|
||||
/** Sets the byte order.
|
||||
* @param order Byte order: 0 = big-endian, 1 = little-endian
|
||||
*/
|
||||
public void setByteOrder (int order)
|
||||
{
|
||||
_byteOrder = order;
|
||||
}
|
||||
|
||||
/** Sets the byte order.
|
||||
*/
|
||||
public void setByteOrder (String order)
|
||||
{
|
||||
if (order.substring (0, 3).toLowerCase ().equals ("big")) {
|
||||
_byteOrder = BIG_ENDIAN;
|
||||
}
|
||||
else if (order.substring (0, 6).toLowerCase ().equals ("little")) {
|
||||
_byteOrder = LITTLE_ENDIAN;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the audio data encoding. */
|
||||
public void setAudioDataEncoding (String audioDataEncoding)
|
||||
{
|
||||
_audioDataEncoding = audioDataEncoding;
|
||||
}
|
||||
|
||||
/** Set the application-specific data. For present purposes,
|
||||
* we assume this is representable as a text string. */
|
||||
public void setAppSpecificData (String data)
|
||||
{
|
||||
_appSpecificData = data;
|
||||
}
|
||||
|
||||
/** Sets the bit depth. */
|
||||
public void setBitDepth (int bitDepth)
|
||||
{
|
||||
_curFormatRegion.setBitDepth (bitDepth);
|
||||
}
|
||||
|
||||
/** Sets the disposition. */
|
||||
public void setDisposition (String disposition)
|
||||
{
|
||||
_disposition = disposition;
|
||||
}
|
||||
|
||||
/** Sets the direction.
|
||||
* This must be one of the values
|
||||
* FORWARD, REVERSE, A_WIND, B_WIND, C_WIND, D_WIND,
|
||||
* FRONT, BACK. FORWARD may be the only one that
|
||||
* makes sense for digital formats.
|
||||
*/
|
||||
public void setDirection (String direction)
|
||||
{
|
||||
_curFace.setDirection (direction);
|
||||
}
|
||||
|
||||
/** Sets the duration in samples.
|
||||
* This affects the current face and its first FaceRegion.
|
||||
*/
|
||||
public void setDuration (long duration)
|
||||
{
|
||||
_curFace.setDuration (duration);
|
||||
_curFace.getFaceRegion(0).setDuration (duration);
|
||||
}
|
||||
|
||||
/** Sets the offset of the first byte of sample data. */
|
||||
public void setFirstSampleOffset (long offset)
|
||||
{
|
||||
_firstSampleOffset = offset;
|
||||
}
|
||||
|
||||
/** Sets the format name. */
|
||||
public void setFormat (String format)
|
||||
{
|
||||
_format = format;
|
||||
}
|
||||
|
||||
/** Sets the array of channel map locations. The length
|
||||
* of the array must equal the number of channels. */
|
||||
public void setMapLocations (String[] locations) {
|
||||
_curFace.getFaceRegion(0).setMapLocations (locations);
|
||||
}
|
||||
|
||||
/** Sets the number of channels. */
|
||||
public void setNumChannels (int numChannels)
|
||||
{
|
||||
_numChannels = numChannels;
|
||||
}
|
||||
|
||||
/** Sets the primary identifier. */
|
||||
public void setPrimaryIdentifier (String primaryIdentifier)
|
||||
{
|
||||
_primaryIdentifier = primaryIdentifier;
|
||||
}
|
||||
|
||||
/** Sets the primary identifier type. If the primary identifier
|
||||
* type is OTHER, use setOtherPrimaryIdentifierType instead.
|
||||
*/
|
||||
public void setPrimaryIdentifierType (String primaryIdentifierType)
|
||||
{
|
||||
_primaryIdentifierType = primaryIdentifierType;
|
||||
}
|
||||
|
||||
/** Sets the primary identifier type as "OTHER", and
|
||||
* set the otherType.
|
||||
*/
|
||||
public void setOtherPrimaryIdentifierType (String otherType)
|
||||
{
|
||||
_primaryIdentifierType = "OTHER";
|
||||
_primaryIdentifierOtherType = otherType;
|
||||
}
|
||||
|
||||
/** Sets the sample rate. */
|
||||
public void setSampleRate (double sampleRate)
|
||||
{
|
||||
_curFormatRegion.setSampleRate (sampleRate);
|
||||
}
|
||||
|
||||
/** Sets the specification version of the document format.*/
|
||||
public void setSpecificationVersion (String specificationVersion)
|
||||
{
|
||||
_specificationVersion = specificationVersion;
|
||||
}
|
||||
|
||||
/** Sets the start time in samples.
|
||||
* This affects the current face and its first FaceRegion.
|
||||
*/
|
||||
public void setStartTime (long samples)
|
||||
{
|
||||
_curFace.setStartTime (samples);
|
||||
_curFace.getFaceRegion(0).setStartTime (samples);
|
||||
}
|
||||
|
||||
/** Sets the role of the document. Permitted values are
|
||||
* ORIGINAL_MASTER, PRESERVATION_MASTER, PRODUCTION_MASTER,
|
||||
* SERVICE, PREVIEW, or OTHER.
|
||||
* If useType is "OTHER", then otherType
|
||||
* is significant. Since OTHER is the only meaningful
|
||||
* value for a digital document, the code assumes this will always
|
||||
* be the case and uses otherType. */
|
||||
public void setUse (String useType, String otherType)
|
||||
{
|
||||
_use = new String[] {useType, otherType};
|
||||
}
|
||||
|
||||
/** Sets the word size. */
|
||||
public void setWordSize (int wordSize)
|
||||
{
|
||||
_curFormatRegion.setWordSize (wordSize);
|
||||
}
|
||||
|
||||
/** Adds a FormatRegion object to a FormatSize list.
|
||||
* The most recently added FormatRegion object will
|
||||
* be filled in by setBitDepth, setSampleRate, and
|
||||
* setWordSize.
|
||||
*/
|
||||
public void addFormatRegion ()
|
||||
{
|
||||
_curFormatRegion = new FormatRegionImpl ();
|
||||
_formatList.add (_curFormatRegion);
|
||||
}
|
||||
|
||||
/** Adds a Face.
|
||||
*/
|
||||
public void addFace ()
|
||||
{
|
||||
_curFace = new FaceImpl ();
|
||||
_faceList.add (_curFace);
|
||||
_curFace.addFaceRegion();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* Encapsulates information about agents, either individual
|
||||
* persons or corporate bodies.
|
||||
*/
|
||||
public class Agent
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
private String _name;
|
||||
private AgentType _type;
|
||||
private String _address;
|
||||
private String _telephone;
|
||||
private String _fax;
|
||||
private String _email;
|
||||
private String _web;
|
||||
private String _note;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Creates an Agent given a name and an AgentType.
|
||||
*/
|
||||
public Agent (String name, AgentType type)
|
||||
{
|
||||
_name = name;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the value of the address property.
|
||||
*/
|
||||
public String getAddress ()
|
||||
{
|
||||
return _address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the email property.
|
||||
*/
|
||||
public String getEmail ()
|
||||
{
|
||||
return _email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the fax property.
|
||||
*/
|
||||
public String getFax ()
|
||||
{
|
||||
return _fax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the name property.
|
||||
*/
|
||||
public String getName ()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the note property.
|
||||
*/
|
||||
public String getNote ()
|
||||
{
|
||||
return _note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the telephone property.
|
||||
*/
|
||||
public String getTelephone ()
|
||||
{
|
||||
return _telephone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the type property.
|
||||
*/
|
||||
public AgentType getType ()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the web property.
|
||||
*/
|
||||
public String getWeb ()
|
||||
{
|
||||
return _web;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Mutator methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Sets the value of the address property.
|
||||
*/
|
||||
public void setAddress (String address)
|
||||
{
|
||||
_address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the email property.
|
||||
*/
|
||||
public void setEmail (String email)
|
||||
{
|
||||
_email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the fax property.
|
||||
*/
|
||||
public void setFax (String fax)
|
||||
{
|
||||
_fax = fax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the name property.
|
||||
*/
|
||||
public void setName (String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the note property.
|
||||
*/
|
||||
public void setNote (String note)
|
||||
{
|
||||
_note = note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the telephone property.
|
||||
*/
|
||||
public void setTelephone (String telephone)
|
||||
{
|
||||
_telephone = telephone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the web property.
|
||||
*/
|
||||
public void setWeb (String web)
|
||||
{
|
||||
_web = web;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines enumerated types for an Agent.
|
||||
* Applications will not create or modify AgentTypes, but will
|
||||
* use one of the predefined AgentType instances COMMERCIAL, GOVERNMENT,
|
||||
* EDUCATIONAL, NONPROFIT, STANDARD, or OTHER.
|
||||
*
|
||||
* @see Agent
|
||||
*/
|
||||
public final class AgentType
|
||||
extends EnumerationType
|
||||
{
|
||||
/******************************************************************
|
||||
* PUBLIC STATIC INSTANCES.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Agent type for a commercial entity.
|
||||
*/
|
||||
public static final AgentType COMMERCIAL = new AgentType ("Commercial");
|
||||
/**
|
||||
* Agent type for a governmental body.
|
||||
*/
|
||||
public static final AgentType GOVERNMENT = new AgentType ("Government");
|
||||
/**
|
||||
* Agent type for an educational institution.
|
||||
*/
|
||||
public static final AgentType EDUCATIONAL = new AgentType ("Educational");
|
||||
/**
|
||||
* Agent type for a non-profit organization.
|
||||
*/
|
||||
public static final AgentType NONPROFIT = new AgentType ("Non-profit");
|
||||
/**
|
||||
* Agent type for a standards body.
|
||||
*/
|
||||
public static final AgentType STANDARD = new AgentType ("Standards body");
|
||||
/**
|
||||
* Agent type that doesn't fit the other categories.
|
||||
*/
|
||||
public static final AgentType OTHER = new AgentType ("Other");
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Applications will never create AgentTypes directly.
|
||||
**/
|
||||
private AgentType (String value)
|
||||
{
|
||||
super (value);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by JSTOR and the President and Fellows of Harvard College
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* This class defines enumerated types for the analog/digital
|
||||
* flag of AESAudioMetadata.
|
||||
* Applications will not create or modify instances of this class, but will
|
||||
* use one of the predefined AnalogDigitalFlagType instances.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class AnalogDigitalFlagType extends EnumerationType {
|
||||
|
||||
/** Enumeration instance for analog data */
|
||||
public static final AnalogDigitalFlagType ANALOG =
|
||||
new AnalogDigitalFlagType ("ANALOG");
|
||||
|
||||
/** Enumeration instance for physical digital data */
|
||||
public static final AnalogDigitalFlagType PHYS_DIGITAL =
|
||||
new AnalogDigitalFlagType ("PHYS_DIGITAL");
|
||||
|
||||
/** Enumeration instance for FILE digital data */
|
||||
public static final AnalogDigitalFlagType FILE_DIGITAL =
|
||||
new AnalogDigitalFlagType ("FILE_DIGITAL");
|
||||
|
||||
/**
|
||||
* Applications will never create PropertyTypes directly.
|
||||
**/
|
||||
private AnalogDigitalFlagType (String value)
|
||||
{
|
||||
super (value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
//import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The application class for JHOVE. One instance of this class is
|
||||
* generated by the application. Various utility and informational
|
||||
* methods are contained here.
|
||||
*/
|
||||
public class App
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Application build date. */
|
||||
private Date _date;
|
||||
|
||||
/** Application name. */
|
||||
private String _name;
|
||||
|
||||
/** Application release identifier. */
|
||||
private String _release;
|
||||
|
||||
/** Application rights statement. */
|
||||
private String _rights;
|
||||
|
||||
/** Application invocation syntax. */
|
||||
private String _usage;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Creates an App object.
|
||||
* @param name Name of the application.
|
||||
* @param release Release identifier.
|
||||
* @param date Last modification date of the application code,
|
||||
* in the form of an array of three numbers.
|
||||
* <code>date[0]</code> is the year,
|
||||
* <code>date[1]</code> the month, and
|
||||
* <code>date[2]</code> the day.
|
||||
* @param usage String summarizing command line usage, to
|
||||
* output when app name is typed with no
|
||||
* arguments or flags.
|
||||
* @param rights Copyright or other rights statement.
|
||||
*/
|
||||
public App (String name, String release, int [] date, String usage,
|
||||
String rights)
|
||||
{
|
||||
Calendar calendar = new GregorianCalendar ();
|
||||
calendar.set (date[0], date[1]-1, date[2]);
|
||||
|
||||
_name = name;
|
||||
_release = release;
|
||||
_date = calendar.getTime ();
|
||||
_usage = usage;
|
||||
_rights = rights;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Accessor methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Returns application code creation date
|
||||
*/
|
||||
public Date getDate ()
|
||||
{
|
||||
return _date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this application
|
||||
*/
|
||||
public String getName ()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the release identifier for this application.
|
||||
*/
|
||||
public String getRelease ()
|
||||
{
|
||||
return _release;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rights string.
|
||||
*/
|
||||
public String getRights ()
|
||||
{
|
||||
return _rights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the usage string, which should be output when the user
|
||||
* enters a command line with only the application name.
|
||||
*/
|
||||
public String getUsage ()
|
||||
{
|
||||
return _usage;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Serialization methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the application,
|
||||
* including configuration, available modules and handlers,
|
||||
* etc.
|
||||
*/
|
||||
public void show (OutputHandler handler)
|
||||
{
|
||||
handler.show (this);
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Class for providing an InputSource to XMPHandler,
|
||||
* with a ByteArrayInputStream as the basis of the
|
||||
* InputSource. This is suitable for a number of modules.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class ByteArrayXMPSource extends XMPSource {
|
||||
|
||||
/* The underlying ByteArrayInputStream. */
|
||||
ByteArrayInputStream _instrm;
|
||||
|
||||
/**
|
||||
* Constructor based on ByteArrayInputStream.
|
||||
*
|
||||
* @param instrm ByteArrayInputStream containing the XMP
|
||||
*/
|
||||
public ByteArrayXMPSource (ByteArrayInputStream instrm)
|
||||
throws IOException
|
||||
{
|
||||
super (new InputStreamReader
|
||||
(new XMLWrapperStream (instrm)));
|
||||
_instrm = instrm;
|
||||
// Prepare for resetting.
|
||||
instrm.mark (instrm.available ());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor based on ByteArrayInputStream with encoding.
|
||||
*
|
||||
* @param instrm ByteArrayInputStream containing the XMP
|
||||
*/
|
||||
public ByteArrayXMPSource (ByteArrayInputStream instrm,
|
||||
String encoding)
|
||||
throws IOException
|
||||
{
|
||||
super (new InputStreamReader
|
||||
(new XMLWrapperStream (instrm), encoding));
|
||||
_instrm = instrm;
|
||||
// Prepare for resetting.
|
||||
instrm.mark (instrm.available ());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see edu.harvard.hul.ois.jhove.XMPSource#resetReader()
|
||||
*/
|
||||
protected void resetReader() {
|
||||
_instrm.reset ();
|
||||
_reader = new InputStreamReader (_instrm);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* An interface for supporting a general, simple callback function.
|
||||
*/
|
||||
public interface Callback
|
||||
{
|
||||
/**
|
||||
* A generic callback function. Any class which needs to support
|
||||
* callback can implement callback and pass a reference to itself
|
||||
* to the function that does the callback.
|
||||
*
|
||||
* @param selector An indicator of the function to be performed.
|
||||
* Interpretation is determined by the implementing class.
|
||||
* @param parm Whatever data may be appropriate to the callback.
|
||||
*
|
||||
* @return As specified by the implementing class.
|
||||
*/
|
||||
public int callback (int selector, Object parm);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* This class encapsulates the result of calculations which provide a greater
|
||||
* or lesser degree of confirmation of the integrity of a digital
|
||||
* object's content, including checksums, CRC's, message digests,
|
||||
* etc.
|
||||
*
|
||||
* @see ChecksumType
|
||||
* @see Checksummer
|
||||
*/
|
||||
public class Checksum
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
private ChecksumType _type;
|
||||
private String _value;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Creates a Checksum with a given value and type
|
||||
*/
|
||||
public Checksum (String value, ChecksumType type)
|
||||
{
|
||||
_value = value;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Accessor methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Returns this Checksum's type
|
||||
*/
|
||||
public ChecksumType getType ()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this Checksum's value
|
||||
*/
|
||||
public String getValue ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Mutator methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Sets the type of this Checksum
|
||||
*/
|
||||
public void setType (ChecksumType type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this Checksum
|
||||
*/
|
||||
public void setValue (String value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Put here as a convenience for checksum calculators
|
||||
*****************************************************************/
|
||||
/**
|
||||
* Maps unsigned byte value (0 to 256) to signed byte value (-128 to 127).
|
||||
*/
|
||||
public static byte unsignedByteToByte (int value)
|
||||
{
|
||||
return (byte) ((value < 127) ? value : value - 256);
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003-2006 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A ChecksumInputStream is a FilterInputStream with the added
|
||||
* functionality of calculating checksums as it goes.
|
||||
*
|
||||
* The idea of replacing this with java.util.zip.CheckedInputStream
|
||||
* looks very tempting, but we need the byte count, which
|
||||
* CheckedInputStream doesn't provide.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class ChecksumInputStream extends FilterInputStream {
|
||||
|
||||
private InputStream subsumedStream;
|
||||
private Checksummer _cksummer;
|
||||
private long _nBytes;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stream Stream to be filtered
|
||||
* @param cksummer Object to calculate checksum on the bytes
|
||||
* as they are read
|
||||
*/
|
||||
public ChecksumInputStream(InputStream stream, Checksummer cksummer) {
|
||||
super (stream);
|
||||
subsumedStream = stream;
|
||||
_cksummer = cksummer;
|
||||
_nBytes = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte from the subsumed stream, updating
|
||||
* the byte count and the checksums.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
int ch = subsumedStream.read ();
|
||||
if (ch >= 0) {
|
||||
_nBytes++;
|
||||
if (_cksummer != null) {
|
||||
_cksummer.update (ch);
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads some number of bytes from the input stream and
|
||||
* stores them into the buffer array b. The number of
|
||||
* bytes actually read is returned as an integer.
|
||||
*
|
||||
* All bytes read are fed through the checksummer.
|
||||
*/
|
||||
public int read(byte[] b) throws IOException
|
||||
{
|
||||
int len = subsumedStream.read (b);
|
||||
// Careful here -- don't want to add -1 bytes at EOF
|
||||
if (len > 0) {
|
||||
if (_cksummer != null) {
|
||||
_cksummer.update (b);
|
||||
}
|
||||
_nBytes += len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to len bytes of data from the input stream
|
||||
* into an array of bytes. An attempt is made to read as
|
||||
* many as len bytes, but a smaller number may be read,
|
||||
* possibly zero. The number of bytes actually read is
|
||||
* returned as an integer.
|
||||
*
|
||||
* All bytes read are fed through the checksummer.
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
len = subsumedStream.read (b, off, len);
|
||||
// Careful here -- don't want to add -1 bytes at EOF
|
||||
if (len > 0) {
|
||||
if (_cksummer != null) {
|
||||
_cksummer.update (b, off, len);
|
||||
}
|
||||
_nBytes += len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips n bytes.
|
||||
* Reads them and feeds them through the checksummer.
|
||||
*/
|
||||
public long skip (long n) throws IOException {
|
||||
long nret = 0;
|
||||
while (n > 0) {
|
||||
// grab the data in reasonable buffer-sized chunks.
|
||||
int bufsize = (int) (n > 8192 ? 8192 : n);
|
||||
byte[] buf = new byte[bufsize];
|
||||
int nread = read (buf);
|
||||
if (nread <= 0) {
|
||||
break;
|
||||
}
|
||||
nret += nread;
|
||||
n -= nread;
|
||||
}
|
||||
return nret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the subsumed stream.
|
||||
*/
|
||||
public void close () throws IOException
|
||||
{
|
||||
subsumedStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte count to date on the stream.
|
||||
* This returns the number of bytes read.
|
||||
* Because of buffering, this is not a reliable
|
||||
* indicator of how many bytes have actually been processed.
|
||||
*/
|
||||
public long getNBytes ()
|
||||
{
|
||||
return _nBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Checksummer object.
|
||||
*/
|
||||
public Checksummer getChecksummer ()
|
||||
{
|
||||
return _cksummer;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines enumerated types for a Checksum on a content
|
||||
* stream or file.
|
||||
* Applications will not create or modify ChecksumTypes, but will
|
||||
* use one of the predefined ChecksumType instances
|
||||
* CRC32, MD5, or SHA1.
|
||||
*
|
||||
* @see Checksum
|
||||
*/
|
||||
public final class ChecksumType
|
||||
extends EnumerationType
|
||||
{
|
||||
/** 32-bit Cyclical Redundancy Checksum. */
|
||||
public static final ChecksumType CRC32 = new ChecksumType ("CRC32");
|
||||
|
||||
/** 128-bit Message Digest 5. */
|
||||
public static final ChecksumType MD5 = new ChecksumType ("MD5");
|
||||
|
||||
/** 160-bit Secure Hash Algorithm. */
|
||||
public static final ChecksumType SHA1 = new ChecksumType ("SHA-1");
|
||||
|
||||
/**
|
||||
* Applications will never create ChecksumTypes directly.
|
||||
**/
|
||||
private ChecksumType (String value)
|
||||
{
|
||||
super (value);
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003-2006 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
import java.security.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
* The Checksummer class encapsulates the calculation of the
|
||||
* CRC32, MD5, and SHA-1 checksums.
|
||||
*/
|
||||
public class Checksummer implements java.util.zip.Checksum
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Byte count. */
|
||||
protected long _nByte;
|
||||
/** CRC32 object. */
|
||||
private CRC32 _crc32;
|
||||
/** MD5 message digest. */
|
||||
private MessageDigest _md5;
|
||||
/** SHA-1 message digest. */
|
||||
private MessageDigest _sha1;
|
||||
|
||||
/**
|
||||
* Creates a Checksummer, with instances of each of
|
||||
* CRC32, MD5 MessageDigest, and SHA-1 MessageDigest.
|
||||
* If one or both of the MessageDigests aren't supported
|
||||
* on the current platform, they are left as null.
|
||||
*
|
||||
* @see CRC32
|
||||
* @see MessageDigest
|
||||
*/
|
||||
public Checksummer ()
|
||||
{
|
||||
reset ();
|
||||
}
|
||||
|
||||
/** Resets all checksums and the byte count to their
|
||||
* initial values.
|
||||
*/
|
||||
public void reset ()
|
||||
{
|
||||
_nByte = 0;
|
||||
_crc32 = new CRC32 ();
|
||||
try {
|
||||
_md5 = MessageDigest.getInstance ("MD5");
|
||||
_sha1 = MessageDigest.getInstance ("SHA-1");
|
||||
}
|
||||
catch (NoSuchAlgorithmException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/** getValue is required by the Checksum interface, but
|
||||
* we can return only one of the three values. We
|
||||
* return the CRC32 value, since that's the one which
|
||||
* is guaranteed to be available.
|
||||
*/
|
||||
public long getValue ()
|
||||
{
|
||||
return _crc32.getValue ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum with the argument.
|
||||
* Called when a signed byte is available.
|
||||
*/
|
||||
public void update (byte b)
|
||||
{
|
||||
_crc32.update (b);
|
||||
if (_md5 != null) {
|
||||
_md5.update (b);
|
||||
}
|
||||
if (_sha1 != null) {
|
||||
_sha1.update (b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum with the argument.
|
||||
* Called when an unsigned byte is available.
|
||||
*/
|
||||
public void update (int b)
|
||||
{
|
||||
byte sb;
|
||||
if (b > 127) {
|
||||
sb = (byte) (b - 256);
|
||||
}
|
||||
else {
|
||||
sb = (byte) b;
|
||||
}
|
||||
update (sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum with the argument.
|
||||
* Called when a byte array is available.
|
||||
*/
|
||||
public void update (byte[] b)
|
||||
{
|
||||
_crc32.update (b);
|
||||
if (_md5 != null) {
|
||||
_md5.update (b);
|
||||
}
|
||||
if (_sha1 != null) {
|
||||
_sha1.update (b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the checksum with the argument.
|
||||
* Called when a byte array is available.
|
||||
*/
|
||||
public void update (byte[] b, int off, int len)
|
||||
{
|
||||
_crc32.update (b, off, len);
|
||||
if (_md5 != null) {
|
||||
_md5.update (b, off, len);
|
||||
}
|
||||
if (_sha1 != null) {
|
||||
_sha1.update (b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the CRC32 as a hex string.
|
||||
*/
|
||||
public String getCRC32 ()
|
||||
{
|
||||
return padLeadingZeroes
|
||||
(Long.toHexString (_crc32.getValue ()), 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the MD5 digest as a hex string.
|
||||
* Returns null if the digest is not available.
|
||||
*/
|
||||
public String getMD5 ()
|
||||
{
|
||||
String value = null;
|
||||
|
||||
if (_md5 != null) {
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
byte [] digest = _md5.digest ();
|
||||
for (int i=0; i<digest.length; i++) {
|
||||
int un = (digest[i] >= 0) ? digest[i] : 256+digest[i];
|
||||
buffer.append (padLeadingZeroes
|
||||
(Integer.toHexString (un), 2));
|
||||
}
|
||||
value = buffer.toString ();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the SHA-1 digest as a hex string.
|
||||
* Returns null if the digest is not available.
|
||||
*/
|
||||
public String getSHA1 ()
|
||||
{
|
||||
String value = null;
|
||||
|
||||
if (_sha1 != null) {
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
byte [] digest = _sha1.digest ();
|
||||
for (int i=0; i<digest.length; i++) {
|
||||
int un = (digest[i] >= 0) ? digest[i] : 256+digest[i];
|
||||
buffer.append (padLeadingZeroes
|
||||
(Integer.toHexString (un), 2));
|
||||
}
|
||||
value = buffer.toString ();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Pad a hexadecimal (or other numeric) string out to
|
||||
* the specified length with leading zeroes. */
|
||||
private String padLeadingZeroes (String str, int len)
|
||||
{
|
||||
// This is optimized for adding just one leading zero
|
||||
// or none, which will be the usual case.
|
||||
while (str.length () < len) {
|
||||
str = "0" + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -1,395 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import org.xml.sax.*;
|
||||
|
||||
/**
|
||||
* SAX Parser for the configuration file.
|
||||
*/
|
||||
public class ConfigHandler
|
||||
extends org.xml.sax.helpers.DefaultHandler
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
private String _class;
|
||||
protected StringBuffer _content;
|
||||
private Map<String, String> _extension;
|
||||
|
||||
/** The schema name */
|
||||
private final static String configSchemaName =
|
||||
"jhoveConfig.xsd";
|
||||
|
||||
/** The list of handlers. Each element in the List is an
|
||||
* array of two Strings representing the class and the initialization
|
||||
* string. */
|
||||
private List<String[]> _handler;
|
||||
|
||||
/** The list of handler parameters. Each element in the List is
|
||||
* a List of Strings (which may be empty but not null) representing
|
||||
* parameters to be passed to the module. List elements are in
|
||||
* one-to-one correspondence with _handler.
|
||||
*/
|
||||
protected List<List<String>> _handlerParams;
|
||||
private String _init;
|
||||
private List<String> _param;
|
||||
private String _tempDir;
|
||||
private String _mixVsn;
|
||||
private String _encoding;
|
||||
private String _logLevel;
|
||||
private int _bufferSize;
|
||||
private String _jhoveHome;
|
||||
private int _sigBytes;
|
||||
|
||||
protected boolean _isHandler;
|
||||
|
||||
/* _isModule is protected rather than private so that subclasses
|
||||
* can add elements to the module element. */
|
||||
protected boolean _isModule;
|
||||
|
||||
private boolean _isTempDir;
|
||||
private boolean _isMixVsn;
|
||||
private boolean _isEncoding;
|
||||
private boolean _isBufferSize;
|
||||
private boolean _isJhoveHome;
|
||||
private boolean _isLogLevel;
|
||||
private boolean _isSigBytes;
|
||||
|
||||
/** The list of modules. Each element in the List is an
|
||||
* array of two Strings representing the class and the initialization
|
||||
* string. */
|
||||
protected List<ModuleInfo> _module;
|
||||
|
||||
/** The list of module parameters. Each element in the List is
|
||||
* a List of Strings (which may be empty but not null) representing
|
||||
* parameters to be passed to the module. List elements are in
|
||||
* one-to-one correspondence with _module.
|
||||
*/
|
||||
protected List<List<String>> _modParams;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Creates a ConfigHandler.
|
||||
*/
|
||||
public ConfigHandler ()
|
||||
{
|
||||
_module = new ArrayList<ModuleInfo> ();
|
||||
_handler = new ArrayList<String[]> ();
|
||||
_modParams = new ArrayList<List<String>> ();
|
||||
_handlerParams = new ArrayList<List<String>> ();
|
||||
|
||||
_isModule = false;
|
||||
_isHandler = false;
|
||||
_isTempDir = false;
|
||||
_isEncoding = false;
|
||||
_isBufferSize = false;
|
||||
_isJhoveHome = false;
|
||||
_isLogLevel = false;
|
||||
|
||||
_bufferSize = -1;
|
||||
_encoding = null;
|
||||
_extension = new Hashtable<String, String> ();
|
||||
_tempDir = null;
|
||||
_mixVsn = null;
|
||||
_sigBytes = 1024;
|
||||
_logLevel = null;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Accessor methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the List of Modules specified by the config file.
|
||||
* Each element of the List is a String[2] whose elements are
|
||||
* the module class name and initialization value.
|
||||
*
|
||||
* @see Module
|
||||
*/
|
||||
public List<ModuleInfo> getModule ()
|
||||
{
|
||||
return _module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the List of module parameters specified by the config file.
|
||||
* Each element of the List is a List (possibly empty) of Strings
|
||||
* whose elements are parameters to pass to the module. The
|
||||
* values returned by <code>getModuleParams()</code> are in
|
||||
* one-to-one correspondence with those return by <code>getModule()</code>.
|
||||
*/
|
||||
public List<List<String>> getModuleParams ()
|
||||
{
|
||||
return _modParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the List of handler parameters specified by the config file.
|
||||
* Each element of the List is a List (possibly empty) of Strings
|
||||
* whose elements are parameters to pass to the output handler. The
|
||||
* values returned by <code>getHandlerParams()</code> are in
|
||||
* one-to-one correspondence with those return by <code>getHandler()</code>.
|
||||
*/
|
||||
public List<List<String>> getHandlerParams ()
|
||||
{
|
||||
return _handlerParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the List of OutputHandlers specified by the config file.
|
||||
*
|
||||
* @see OutputHandler
|
||||
*/
|
||||
public List<String[]> getHandler ()
|
||||
{
|
||||
return _handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the temporary directory path specified by the config file,
|
||||
* with final path separator.
|
||||
*/
|
||||
public String getTempDir ()
|
||||
{
|
||||
return _tempDir;
|
||||
}
|
||||
|
||||
/** Returns the MIX schema version specified by the config file.
|
||||
* Acceptable values are "0.2" and "1.0" and "2.0".
|
||||
*/
|
||||
public String getMixVsn ()
|
||||
{
|
||||
return _mixVsn;
|
||||
}
|
||||
|
||||
/** Returns the number of bytes to examine when looking for an
|
||||
* indefinitely positioned signature, or checking the first
|
||||
* sigBytes bytes of a file in lieu of a signature.
|
||||
*/
|
||||
public int getSigBytes ()
|
||||
{
|
||||
return _sigBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character encoding specified by the config file.
|
||||
*/
|
||||
public String getEncoding ()
|
||||
{
|
||||
return _encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the buffer size specified in the config file.
|
||||
*
|
||||
* @return the buffer size, or -1 if none specified
|
||||
*/
|
||||
public int getBufferSize ()
|
||||
{
|
||||
return _bufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an associative map of configuration extensions.
|
||||
*/
|
||||
public Map<String, String> getExtensions ()
|
||||
{
|
||||
return _extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the application's home directory,
|
||||
* with final path separator.
|
||||
*/
|
||||
public String getJhoveHome ()
|
||||
{
|
||||
return _jhoveHome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the desired log level. This should be the
|
||||
* name of one of the predefined values of java.util.logging.Level,
|
||||
* e.g., "WARNING", "INFO", "ALL". The default level is SEVERE.
|
||||
*/
|
||||
public String getLogLevel ()
|
||||
{
|
||||
return _logLevel;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* SAX parser methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* SAX parser callback method.
|
||||
*/
|
||||
public void startElement (String namespaceURI, String localName,
|
||||
String rawName, Attributes atts)
|
||||
throws SAXException
|
||||
{
|
||||
_content = new StringBuffer ();
|
||||
|
||||
if (rawName.equals ("module")) {
|
||||
_isModule = true;
|
||||
_init = null;
|
||||
_param = new ArrayList<String> (1);
|
||||
_class = null;
|
||||
}
|
||||
else if (rawName.equals ("outputHandler")) {
|
||||
_isHandler = true;
|
||||
_init = null;
|
||||
_param = new ArrayList<String> (1);
|
||||
_class = null;
|
||||
}
|
||||
else if (rawName.equals ("tempDirectory")) {
|
||||
_isTempDir = true;
|
||||
}
|
||||
else if (rawName.equals ("mixVersion")) {
|
||||
_isMixVsn = true;
|
||||
}
|
||||
else if (rawName.equals ("defaultEncoding")) {
|
||||
_isEncoding = true;
|
||||
}
|
||||
else if (rawName.equals ("bufferSize")) {
|
||||
_isBufferSize = true;
|
||||
}
|
||||
else if (rawName.equals ("jhoveHome")) {
|
||||
_isJhoveHome = true;
|
||||
}
|
||||
else if (rawName.equals ("logLevel")) {
|
||||
_isLogLevel = true;
|
||||
}
|
||||
else if (rawName.equals ("sigBytes")) {
|
||||
_isSigBytes = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SAX parser callback method.
|
||||
*/
|
||||
public void characters (char [] ch, int start, int length)
|
||||
throws SAXException
|
||||
{
|
||||
_content.append (ch, start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* SAX parser callback method.
|
||||
*/
|
||||
public void endElement (String namespaceURI, String localName,
|
||||
String rawName)
|
||||
throws SAXException
|
||||
{
|
||||
if (_isModule) {
|
||||
if (rawName.equals ("class")) {
|
||||
_class = _content.toString ();
|
||||
}
|
||||
else if (rawName.equals ("init")) {
|
||||
_init = _content.toString ();
|
||||
}
|
||||
else if (rawName.equals ("param")) {
|
||||
_param.add (_content.toString ());
|
||||
}
|
||||
else if (rawName.equals ("module")) {
|
||||
ModuleInfo modInfo = new ModuleInfo( _class, _init);
|
||||
_module.add (modInfo);
|
||||
_modParams.add (_param);
|
||||
_isModule = false;
|
||||
}
|
||||
}
|
||||
else if (_isHandler) {
|
||||
if (rawName.equals ("class")) {
|
||||
_class = _content.toString ();
|
||||
}
|
||||
else if (rawName.equals ("init")) {
|
||||
_init = _content.toString ();
|
||||
}
|
||||
else if (rawName.equals ("param")) {
|
||||
_param.add (_content.toString ());
|
||||
}
|
||||
else if (rawName.equals ("outputHandler")) {
|
||||
String [] tuple = { _class, _init };
|
||||
_handler.add (tuple);
|
||||
_handlerParams.add (_param);
|
||||
_isHandler = false;
|
||||
}
|
||||
}
|
||||
else if (_isTempDir) {
|
||||
_tempDir = _content.toString ().trim ();
|
||||
_isTempDir = false;
|
||||
}
|
||||
else if (_isMixVsn) {
|
||||
_mixVsn = _content.toString ().trim ();
|
||||
_isMixVsn = false;
|
||||
}
|
||||
else if (_isSigBytes) {
|
||||
try {
|
||||
_sigBytes = Integer.parseInt (_content.toString ().trim ());
|
||||
}
|
||||
catch (NumberFormatException e) {}
|
||||
_isSigBytes = false;
|
||||
}
|
||||
else if (_isEncoding) {
|
||||
_encoding = _content.toString ().trim ();
|
||||
_isEncoding = false;
|
||||
}
|
||||
else if (_isJhoveHome) {
|
||||
_jhoveHome = _content.toString ().trim ();
|
||||
_isJhoveHome = false;
|
||||
}
|
||||
else if (_isLogLevel) {
|
||||
_logLevel = _content.toString ().trim ();
|
||||
_isLogLevel = false;
|
||||
}
|
||||
else if (_isBufferSize) {
|
||||
try {
|
||||
_bufferSize = Integer.parseInt (_content.toString ().trim ());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
/* Just ignore a malformed number */
|
||||
}
|
||||
_isBufferSize = false;
|
||||
}
|
||||
else if (!rawName.equals ("jhoveConfig")) {
|
||||
_extension.put (rawName, _content.toString ().trim ());
|
||||
}
|
||||
}
|
||||
|
||||
/** EntityResolver designed to locate the config schema. It tries to find it
|
||||
* as a local resource.
|
||||
*
|
||||
* It appears that not all SAX implementations will actually call this
|
||||
* function for schema resolution, so this isn't a guarantee that the
|
||||
* schema in the config file won't be called directly. But hopefully
|
||||
* it will cut down on the burden on the server with the official
|
||||
* schema copy.
|
||||
*/
|
||||
public InputSource resolveEntity (String publicId, String systemId)
|
||||
throws SAXException, IOException {
|
||||
if (systemId.endsWith (configSchemaName)) {
|
||||
try {
|
||||
URL resURL = this.getClass().getResource("jhoveConfig.xsd");
|
||||
InputStream strm = resURL.openStream ();
|
||||
return new InputSource (strm);
|
||||
}
|
||||
catch (Exception e) {}
|
||||
}
|
||||
// If we couldn't get the local resource, use default location methods
|
||||
return super.resolveEntity (publicId, systemId);
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import edu.harvard.hul.ois.jhove.viewer.ConfigWindow;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class to write out configuration information to the configuration file.
|
||||
* To minimize the chance of getting into a bad state, it writes to a
|
||||
* temporary file, then replaces the old config file with that file,
|
||||
* rather than directly overwriting the existing file.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class ConfigWriter {
|
||||
|
||||
|
||||
private PrintWriter _confOut;
|
||||
private File _tempFile;
|
||||
private File _confFile;
|
||||
ConfigWindow _parent;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates a temporary file for writing and creates an OutputStreamWriter
|
||||
* to write to it. If there is already a file located by
|
||||
* <code>file</code>, it will not be replaced or overwritten
|
||||
* until <code>writeFile</code> has successfully written out
|
||||
* the temporary file.
|
||||
*
|
||||
* @param file Location of the configuration file
|
||||
*
|
||||
* @param parent The ConfigWindow which invoked this instance.
|
||||
* May be null if invoked to write a default config file.
|
||||
*/
|
||||
public ConfigWriter (File file, ConfigWindow parent) throws IOException
|
||||
{
|
||||
_confFile = file;
|
||||
_parent = parent;
|
||||
// Set up a temporary file to write to.
|
||||
String path = file.getParent();
|
||||
file.getParentFile().mkdirs(); // Make sure the directory exists
|
||||
_tempFile = File.createTempFile ("jho", ".conf", new File (path));
|
||||
//_tempFile.createNewFile();
|
||||
FileOutputStream ostrm = new FileOutputStream (_tempFile);
|
||||
OutputStreamWriter osw = new OutputStreamWriter (ostrm, "UTF-8");
|
||||
_confOut = new PrintWriter (osw);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out the content of the file to the temporary file,
|
||||
* then deletes the existing configuration file (as specified
|
||||
* by the constructor parameter) and renames the temporary file
|
||||
* to the configuration file.
|
||||
*
|
||||
* If the temporary file can't be written, or the configuration
|
||||
* file can't be replaced, a warning dialog is put up and the
|
||||
* configuration file remains unchanged.
|
||||
*/
|
||||
public void writeFile (List<ModuleInfo> modules,
|
||||
List<String[]> handlers,
|
||||
File homeDir,
|
||||
File tempDir,
|
||||
String encoding,
|
||||
int bufferSize) throws IOException
|
||||
{
|
||||
writeHead ();
|
||||
|
||||
// Write the home and temp directories. Home must always be valid.
|
||||
_confOut.println (" <jhoveHome>" +
|
||||
encodeContent (homeDir.getPath ()) +
|
||||
"</jhoveHome>");
|
||||
|
||||
// Write out the encoding
|
||||
if (encoding != null && encoding.length() > 0) {
|
||||
_confOut.println (" <defaultEncoding>" +
|
||||
encodeContent (encoding) + "</defaultEncoding>");
|
||||
}
|
||||
|
||||
|
||||
if (tempDir != null) {
|
||||
_confOut.println (" <tempDirectory>" +
|
||||
encodeContent (tempDir.getPath ()) +
|
||||
"</tempDirectory>");
|
||||
}
|
||||
|
||||
// Write the buffer size if not default
|
||||
if (bufferSize > 0) {
|
||||
_confOut.println (" <bufferSize>" + bufferSize +
|
||||
"</bufferSize>");
|
||||
}
|
||||
|
||||
// Write out the modules
|
||||
ListIterator<ModuleInfo> iter = modules.listIterator ();
|
||||
while (iter.hasNext ()) {
|
||||
ModuleInfo minfo = iter.next ();
|
||||
// The class must be non-null, but init may be null.
|
||||
// If the class is empty, it's a user error (probably
|
||||
// clicked "Add" and then lost track of it). Don't
|
||||
// write it out.
|
||||
if (!"".equals (minfo.clas)) {
|
||||
_confOut.println (" <module>");
|
||||
_confOut.println (" <class>" + encodeContent (minfo.clas) +
|
||||
"</class>");
|
||||
if (minfo.init != null && minfo.init.length () > 0) {
|
||||
_confOut.println (" <init>" + encodeContent (minfo.init) +
|
||||
"</init>");
|
||||
}
|
||||
/** tuple[2] and beyond are parameters */
|
||||
if (minfo.params != null) {
|
||||
for (int i = 0; i < minfo.params.length; i++) {
|
||||
_confOut.println (" <param>" + encodeContent(minfo.params[i]) +
|
||||
"</param>");
|
||||
}
|
||||
}
|
||||
_confOut.println (" </module>");
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the handlers
|
||||
ListIterator<String[]> hiter = handlers.listIterator ();
|
||||
while (hiter.hasNext ()) {
|
||||
String handler = hiter.next ()[0];
|
||||
if (handler.length() > 0) { // Don't write out blank handler names
|
||||
_confOut.println (" <outputHandler>");
|
||||
_confOut.println (" <class>" + encodeContent (handler) +
|
||||
"</class>");
|
||||
_confOut.println (" </outputHandler>");
|
||||
}
|
||||
}
|
||||
|
||||
writeTail ();
|
||||
_confOut.close ();
|
||||
|
||||
// Replace the old file with the new.
|
||||
if (_confFile.exists () && !_confFile.delete ()) {
|
||||
if (_parent != null) {
|
||||
JOptionPane.showMessageDialog(_parent,
|
||||
"Can't replace old config file",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
_tempFile.delete ();
|
||||
}
|
||||
else {
|
||||
_tempFile.renameTo (_confFile);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the fixed lines which begin the config file */
|
||||
private void writeHead () throws IOException
|
||||
{
|
||||
_confOut.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
_confOut.println("<jhoveConfig version=\"1.0\"");
|
||||
_confOut.println(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
|
||||
_confOut.println(" xmlns=\"http://hul.harvard.edu/ois/xml/ns/jhove/jhoveConfig\"");
|
||||
|
||||
// Note that the open quote of this line isn't closed till the next line; that's intentional.
|
||||
_confOut.println("xsi:schemaLocation=\"http://hul.harvard.edu/ois/xml/ns/jhove/jhoveConfig");
|
||||
|
||||
_confOut.println(" http://hul.harvard.edu/ois/xml/xsd/jhove/jhoveConfig.xsd\">");
|
||||
}
|
||||
|
||||
/* Write out the fixed end of the config file */
|
||||
private void writeTail () throws IOException
|
||||
{
|
||||
_confOut.println("</jhoveConfig>");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a content String in XML-clean form, converting characters
|
||||
* to entities as necessary. The null string will be
|
||||
* converted to an empty string.
|
||||
*/
|
||||
private static String encodeContent (String content)
|
||||
{
|
||||
if (content == null) {
|
||||
content = "";
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer (content);
|
||||
|
||||
int n = 0;
|
||||
while ((n = buffer.indexOf ("&", n)) > -1) {
|
||||
buffer.insert (n+1, "amp;");
|
||||
n +=5;
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf ("<", n)) > -1) {
|
||||
buffer.replace (n, n+1, "<");
|
||||
n += 4;
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf (">", n)) > -1) {
|
||||
buffer.replace (n, n+1, ">");
|
||||
n += 4;
|
||||
}
|
||||
|
||||
return buffer.toString ();
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A FilterInputStream which passes only a specified
|
||||
* number of bytes, then returns an EOF condition.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class CountedInputStream extends FilterInputStream {
|
||||
|
||||
private int bytesLeft;
|
||||
|
||||
/**
|
||||
* @param instrm The InputStream being counted
|
||||
* @param count The number of bytes to be allowed
|
||||
*/
|
||||
public CountedInputStream(InputStream instrm, int count) {
|
||||
super(instrm);
|
||||
bytesLeft = count;
|
||||
}
|
||||
|
||||
|
||||
/** Reads a single byte from the stream and decrements
|
||||
* the count of remaining bytes. If the count
|
||||
* is exhausted, returns -1 to signify end of file. */
|
||||
public int read() throws IOException {
|
||||
if (bytesLeft <= 0) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
int ch = super.read ();
|
||||
if (ch != -1) {
|
||||
--bytesLeft;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads some number of bytes from the input stream and
|
||||
* stores them into the buffer array b. The number of
|
||||
* bytes actually read is returned as an integer.
|
||||
*
|
||||
* The number of bytes read will not exceed the number
|
||||
* of bytes remaining in the count. The count is
|
||||
* decremented by the number of bytes actually read.
|
||||
*/
|
||||
public int read(byte[] b) throws IOException
|
||||
{
|
||||
int len = b.length;
|
||||
int bytesRead;
|
||||
if (len <= bytesLeft) {
|
||||
// Limit doesn't affect us, do normal read
|
||||
bytesRead = super.read (b);
|
||||
}
|
||||
else {
|
||||
// Limit the read to bytesLeft
|
||||
bytesRead = super.read (b, 0, bytesLeft);
|
||||
}
|
||||
bytesLeft -= bytesRead;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads up to len bytes of data from the input stream
|
||||
* into an array of bytes. An attempt is made to read as
|
||||
* many as len bytes, but a smaller number may be read,
|
||||
* possibly zero. The number of bytes actually read is
|
||||
* returned as an integer.
|
||||
*
|
||||
* The number of bytes read will not exceed the number
|
||||
* of bytes remaining in the count. The count is
|
||||
* decremented by the number of bytes actually read.
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
int bytesRead;
|
||||
if (len <= bytesLeft) {
|
||||
// Limit doesn't affect us, do normal read
|
||||
bytesRead = super.read (b, off, len);
|
||||
}
|
||||
else {
|
||||
bytesRead = super.read (b, off, bytesLeft);
|
||||
}
|
||||
bytesLeft -= bytesRead;
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips n bytes.
|
||||
* Decrements the count by the number of bytes
|
||||
* actually skipped.
|
||||
*/
|
||||
public long skip (long n) throws IOException {
|
||||
long bytesRead = super.skip (n);
|
||||
if (bytesLeft < bytesRead) {
|
||||
bytesLeft = 0;
|
||||
}
|
||||
else {
|
||||
bytesLeft -= bytesRead;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import edu.harvard.hul.ois.jhove.module.*;
|
||||
|
||||
/** This class creates a default configuration if no valid configuration file
|
||||
* is found. */
|
||||
public class DefaultConfigurationBuilder {
|
||||
|
||||
private final static String FILE_SEP = System.getProperty ("file.separator");
|
||||
private final static String HOME_DIR = System.getProperty ("user.home");
|
||||
private final static String JHOVE_DIR = HOME_DIR + FILE_SEP + "jhove";
|
||||
private final static String TEMP_DIR = System.getProperty("java.io.tmpdir");
|
||||
private final static String DEFAULT_ENCODING = "utf-8";
|
||||
private final static int DEFAULT_BUFFER_SIZE = 131072;
|
||||
|
||||
private File configFile;
|
||||
|
||||
|
||||
/** Constructor. A location for the file may be specified or
|
||||
* left null, */
|
||||
public DefaultConfigurationBuilder (File location) {
|
||||
if (location != null) {
|
||||
configFile = location;
|
||||
}
|
||||
else {
|
||||
configFile = new File (JHOVE_DIR +
|
||||
FILE_SEP + "conf" +
|
||||
FILE_SEP + "jhove.conf");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void writeDefaultConfigFile () throws IOException {
|
||||
// if (TEMP_DEBUG) {
|
||||
// String configFileName = "null";
|
||||
// if (configFile != null)
|
||||
// configFileName = configFile.getAbsolutePath();
|
||||
// System.out.println ("writeDefaultConfigFile: path is " + configFileName);
|
||||
// }
|
||||
ConfigWriter cw = new ConfigWriter (configFile, null);
|
||||
List<ModuleInfo> modules = getModules();
|
||||
// TextHandler, XmlHandler, and AuditHandler are loaded by
|
||||
// default, so there are no handlers to put in the config file.
|
||||
List<String[]> handlers = new ArrayList<String[]> ();
|
||||
File homeDir = new File (JHOVE_DIR);
|
||||
File tempDir = new File (TEMP_DIR);
|
||||
try {
|
||||
cw.writeFile(modules, handlers, homeDir, tempDir,
|
||||
DEFAULT_ENCODING, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
catch (IOException e) {
|
||||
// if (TEMP_DEBUG)
|
||||
// e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// public void writeDefaultConfigFile () throws IOException {
|
||||
// ConfigWriter cw = new ConfigWriter (configFile, null);
|
||||
// List<ConfigWriter.ModuleInfo> modules = getModules();
|
||||
// // TextHandler, XmlHandler, and AuditHandler are loaded by
|
||||
// // default, so there are no handlers to put in the config file.
|
||||
// List<String> handlers = new ArrayList<String> ();
|
||||
// File homeDir = new File (JHOVE_DIR);
|
||||
// File tempDir = new File (TEMP_DIR);
|
||||
// cw.writeFile(modules, handlers, homeDir, tempDir,
|
||||
// DEFAULT_ENCODING, DEFAULT_BUFFER_SIZE);
|
||||
// }
|
||||
|
||||
public File getConfigFile () {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
|
||||
protected List<ModuleInfo> getModules () {
|
||||
int nModules = builtInModules.length;
|
||||
ArrayList<ModuleInfo> mods = new ArrayList<ModuleInfo> (nModules);
|
||||
try {
|
||||
for (int i = 0; i < nModules; i++) {
|
||||
Class<?> cls = builtInModules[i];
|
||||
ModuleInfo minfo = new ModuleInfo(cls.getName());
|
||||
minfo.init = null; // Never used at present
|
||||
minfo.params = getDefaultConfigParameters (cls);
|
||||
mods.add(minfo);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {}
|
||||
return mods;
|
||||
}
|
||||
|
||||
|
||||
/** We can't have a static method in an Interface and override it, so we
|
||||
* have to get a bit ugly to fake static inheritance. The advantage of
|
||||
* this is that only the Modules with non-null default config file
|
||||
* parameters have to implement the defaultConfigParams static field. */
|
||||
protected String[] getDefaultConfigParameters (Class<?> c) {
|
||||
try {
|
||||
Field dcpField = c.getField("defaultConfigParams");
|
||||
return (String[]) dcpField.get(null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return new String [] {};
|
||||
}
|
||||
}
|
||||
|
||||
/** The array of build-in modules. If a module is added to or removed from
|
||||
* the build, this array must be changed. The Bytestream module is
|
||||
* loaded by default and so is not listed here. */
|
||||
private Class<?>[] builtInModules = {
|
||||
AiffModule.class,
|
||||
AsciiModule.class,
|
||||
GifModule.class,
|
||||
HtmlModule.class,
|
||||
Jpeg2000Module.class,
|
||||
JpegModule.class,
|
||||
PdfModule.class,
|
||||
TiffModule.class,
|
||||
Utf8Module.class,
|
||||
WaveModule.class,
|
||||
XmlModule.class
|
||||
};
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class encapsulates information about format specification documents.
|
||||
*
|
||||
* @see DocumentType
|
||||
*/
|
||||
public class Document
|
||||
{
|
||||
private List _author;
|
||||
private String _date;
|
||||
private String _edition;
|
||||
private String _enum;
|
||||
private List _identifier;
|
||||
private String _note;
|
||||
private String _pages;
|
||||
private List _publisher;
|
||||
private String _title;
|
||||
private DocumentType _type;
|
||||
|
||||
/**
|
||||
* Creates a Document with a given title and one of the predefined
|
||||
* DocumentTypes.
|
||||
*/
|
||||
public Document (String title, DocumentType type)
|
||||
{
|
||||
_title = title;
|
||||
_type = type;
|
||||
|
||||
_author = new ArrayList ();
|
||||
_identifier = new ArrayList ();
|
||||
_publisher = new ArrayList ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List of Agents, each representing an author of this
|
||||
* Document.
|
||||
* Returns an empty list if no authors have been listed.
|
||||
*
|
||||
* @see Agent
|
||||
*/
|
||||
public List getAuthor ()
|
||||
{
|
||||
return _author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date of this Document
|
||||
*/
|
||||
public String getDate ()
|
||||
{
|
||||
return _date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns informaton on the edition of this Document
|
||||
*/
|
||||
public String getEdition ()
|
||||
{
|
||||
return _edition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enumeration (e.g., serial volume and number)
|
||||
* of this Document
|
||||
*/
|
||||
public String getEnumeration ()
|
||||
{
|
||||
return _enum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of formal Identifiers for this Document.
|
||||
* If no Identifiers are given, returns an empty list.
|
||||
*/
|
||||
public List getIdentifier ()
|
||||
{
|
||||
return _identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the note associated with this Document
|
||||
*/
|
||||
public String getNote ()
|
||||
{
|
||||
return _note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pagination information for this Document
|
||||
*/
|
||||
public String getPages ()
|
||||
{
|
||||
return _pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List of Agents, each representing a publisher of this
|
||||
* Document. If no publishers are listed, returns an empty list.
|
||||
*/
|
||||
public List getPublisher ()
|
||||
{
|
||||
return _publisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of this Document
|
||||
*/
|
||||
public String getTitle ()
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of the predefined DocumentTypes as the type of
|
||||
* this Document
|
||||
*/
|
||||
public DocumentType getType ()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an author to the list of authors
|
||||
*/
|
||||
public void setAuthor (Agent author)
|
||||
{
|
||||
_author.add (author);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date of this Document
|
||||
*/
|
||||
public void setDate (String date)
|
||||
{
|
||||
_date = date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets edition information for this Document
|
||||
*/
|
||||
public void setEdition (String edition)
|
||||
{
|
||||
_edition = edition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets enumeration information (e.g., serial volume and number)
|
||||
* for this Document
|
||||
*/
|
||||
public void setEnumeration (String enm)
|
||||
{
|
||||
_enum = enm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Identifier to the list of identifiers
|
||||
*/
|
||||
public void setIdentifier (Identifier identifier)
|
||||
{
|
||||
_identifier.add (identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a note giving additional information about this Document
|
||||
*/
|
||||
public void setNote (String note)
|
||||
{
|
||||
_note = note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets pagination information for this Document
|
||||
*/
|
||||
public void setPages (String pages)
|
||||
{
|
||||
_pages = pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a publisher to the list of publishers
|
||||
*/
|
||||
public void setPublisher (Agent publisher)
|
||||
{
|
||||
_publisher.add (publisher);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines enumerated types for a Document.
|
||||
* Applications will not create or modify DocumentTypes, but will
|
||||
* use one of the predefined DocumentType instances
|
||||
* ARTICLE, BOOK, REPORT, RFC, STANDARD, WEB, or OTHER.
|
||||
*
|
||||
* @see Document
|
||||
*
|
||||
*/
|
||||
public final class DocumentType
|
||||
extends EnumerationType
|
||||
{
|
||||
/**
|
||||
* Document type for a printed article.
|
||||
*/
|
||||
public static final DocumentType ARTICLE = new DocumentType ("Article");
|
||||
/**
|
||||
* Document type for an book.
|
||||
*/
|
||||
public static final DocumentType BOOK = new DocumentType ("Book");
|
||||
/**
|
||||
* Document type for a report.
|
||||
*/
|
||||
public static final DocumentType REPORT = new DocumentType ("Report");
|
||||
/**
|
||||
* Document type for an IETF Request for Comment.
|
||||
*/
|
||||
public static final DocumentType RFC = new DocumentType ("RFC");
|
||||
/**
|
||||
* Document type for a standards body publication.
|
||||
*/
|
||||
public static final DocumentType STANDARD = new DocumentType ("Standard");
|
||||
/**
|
||||
* Document type for a Web page.
|
||||
*/
|
||||
public static final DocumentType WEB = new DocumentType ("Web");
|
||||
/**
|
||||
* Document type that doesn't fit the other categories.
|
||||
*/
|
||||
public static final DocumentType OTHER = new DocumentType ("Other");
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Applications will never create DocumentTypes directly.
|
||||
**/
|
||||
private DocumentType (String value)
|
||||
{
|
||||
super (value);
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/**********************************************************************
|
||||
* JHOVE - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by the President and Fellows of Harvard College
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Common methods for dump utilities.
|
||||
*/
|
||||
public class Dump
|
||||
{
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
public Dump ()
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC CLASS METHODS.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Return leading characters to pad out the byte offset to field width.
|
||||
* @param os Byte offset
|
||||
* @param width Field width
|
||||
* @return String of leading zeros
|
||||
*/
|
||||
protected static String leading (int os, int width)
|
||||
{
|
||||
return leading (os, width, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return leading characters to pad out the byte offset to field width.
|
||||
* @param os Byte offset
|
||||
* @param width Field width
|
||||
* @return String of leading zeros
|
||||
*/
|
||||
protected static String leading (long os, int width)
|
||||
{
|
||||
return leading (os, width, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return leading characters to pad out the byte offset to field width.
|
||||
* @param os Byte offset
|
||||
* @param width Field width
|
||||
* @param pad Padding character
|
||||
* @return String of leading characters
|
||||
*/
|
||||
protected static String leading (int os, int width, char pad)
|
||||
{
|
||||
return leading ((long) os, width, pad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return leading characters to pad out the byte offset to field width.
|
||||
* @param os Byte offset
|
||||
* @param width Field width
|
||||
* @param pad Padding character
|
||||
* @return String of leading characters
|
||||
*/
|
||||
protected static String leading (long os, int width, char pad)
|
||||
{
|
||||
String ss = Long.toString (os);
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
for (int j=0; j<width-ss.length (); j++) {
|
||||
buffer.append (pad);
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return leading characters to pad out the string to field width.
|
||||
* @param s String
|
||||
* @param width Field width
|
||||
* @return String of leading characters
|
||||
*/
|
||||
protected static String leading (String s, int width)
|
||||
{
|
||||
return leading (s, width, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return leading characters to pad out the string to field width.
|
||||
* @param s String
|
||||
* @param width Field width
|
||||
* @param pad Padding character
|
||||
* @return String of leading characters
|
||||
*/
|
||||
protected static String leading (String s, int width, char pad)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
for (int j=0; j<width-s.length (); j++) {
|
||||
buffer.append (pad);
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and display a sequence of characters.
|
||||
* @param stream Data input stream
|
||||
* @param length Number of characters
|
||||
* @return Character string
|
||||
*/
|
||||
protected static String readChars (DataInputStream stream, int length)
|
||||
throws IOException
|
||||
{
|
||||
byte [] buffer = new byte [length];
|
||||
for (int i=0; i<length; i++) {
|
||||
buffer[i] = stream.readByte ();
|
||||
}
|
||||
return new String (buffer);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* Enumerated data type. To create an emumeration, define a subclass
|
||||
* of EnumerationType with a private constructor, and define as
|
||||
* many <code>public final static</code> instances of the subclass,
|
||||
* within the subclass definition, as there are enumeration cases.
|
||||
* No other instances of an EnumerationType should ever be created,
|
||||
* and the only operations which should ever be performed on an
|
||||
* EnumerationType are assignment and equality testing.
|
||||
*
|
||||
*/
|
||||
public abstract class EnumerationType
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Enumeration value. */
|
||||
private String _value;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Instantiate an <tt>EnumerationType</tt> object.
|
||||
* @param value Enumeration value
|
||||
*/
|
||||
protected EnumerationType (String value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private no-argument constructor to close off the default
|
||||
* constructor.
|
||||
*/
|
||||
private EnumerationType ()
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Type equality test.
|
||||
* @param enm Enumerated type
|
||||
* @return True, if equal
|
||||
*/
|
||||
public boolean equals (EnumerationType enm)
|
||||
{
|
||||
return this == enm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return enumeration value.
|
||||
* @return Value
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* This class encapsulates an error message from a Module, representing
|
||||
* a problem in the content being analyzed.
|
||||
*/
|
||||
public class ErrorMessage
|
||||
extends Message
|
||||
{
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Create an ErrorMessage.
|
||||
* @param message Human-readable string describing the problem.
|
||||
*/
|
||||
public ErrorMessage (String message)
|
||||
{
|
||||
super (message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ErrorMessage.
|
||||
* @param message Human-readable string describing the problem.
|
||||
* @param offset The offset in the file at which the problem
|
||||
* was detected.
|
||||
*/
|
||||
public ErrorMessage (String message, long offset)
|
||||
{
|
||||
super (message, offset);
|
||||
}
|
||||
/**
|
||||
* Create an ErrorMessage.
|
||||
* @param message Human-readable string describing the problem.
|
||||
*/
|
||||
public ErrorMessage (String message, String subMessage)
|
||||
{
|
||||
super (message, subMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ErrorMessage.
|
||||
* @param message Human-readable string describing the problem.
|
||||
* @param subMessage Human-readable additional information.
|
||||
* @param offset The offset in the file at which the problem
|
||||
* was detected.
|
||||
*/
|
||||
public ErrorMessage (String message, String subMessage, long offset)
|
||||
{
|
||||
super (message, subMessage, offset);
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003-4 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* This class encapsulates information about external format signatures.
|
||||
* The value of a Signature may be either a String or a byte array
|
||||
* (stored as an int array to avoid signed byte problems).
|
||||
*/
|
||||
public class ExternalSignature
|
||||
extends Signature
|
||||
{
|
||||
/**
|
||||
* Creates an ExternalSignature given a string value, a type,
|
||||
* and a use requirement.
|
||||
*/
|
||||
public ExternalSignature (String value, SignatureType type,
|
||||
SignatureUseType use)
|
||||
{
|
||||
super (value, type, use);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExternalSignature given a byte array, a type,
|
||||
* and a use requirement.
|
||||
*/
|
||||
public ExternalSignature (int[] value, SignatureType type,
|
||||
SignatureUseType use)
|
||||
{
|
||||
super (value, type, use);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ExternalSignature given a string value, a type,
|
||||
* a use requirement, and a note.
|
||||
*/
|
||||
public ExternalSignature (String value, SignatureType type,
|
||||
SignatureUseType use,
|
||||
String note)
|
||||
{
|
||||
super (value, type, use, note);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates an ExternalSignature given a byte array, a type,
|
||||
* a use requirement, and a note.
|
||||
*/
|
||||
public ExternalSignature (int[] value, SignatureType type,
|
||||
SignatureUseType use,
|
||||
String note)
|
||||
{
|
||||
super (value, type, use, note);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,812 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.*;
|
||||
|
||||
/**
|
||||
* Abstract base class for Jhove output handlers.
|
||||
* Output handlers should normally subclass HandlerBase.
|
||||
*/
|
||||
public abstract class HandlerBase
|
||||
implements OutputHandler
|
||||
{
|
||||
/******************************************************************
|
||||
* PUBLIC CLASS FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* A DateFormat for representing a Date in yyyy-MM-dd
|
||||
* (e.g., 2003-07-31) format.
|
||||
*/
|
||||
public static SynchronizedDateFormat date =
|
||||
new SynchronizedDateFormat ("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* A DateFormat for representing a Date in yyyy-MM-dd HH:mm:ss z
|
||||
* (e.g., 2003-07-31 15:31:12 EDT) format.
|
||||
*/
|
||||
public static SynchronizedDateFormat dateTime =
|
||||
new SynchronizedDateFormat ("yyyy-MM-dd HH:mm:ss z");
|
||||
|
||||
/**
|
||||
* A DateFormat for representing a Date in ISO 8601
|
||||
* (e.g., 2003-07-31T15:31:12-0400) format.
|
||||
* We subclass SimpleDateFormat to make it thread-safe.
|
||||
*/
|
||||
public static SynchronizedDateFormat iso8601 =
|
||||
new SynchronizedDateFormat ("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** The application object */
|
||||
protected App _app;
|
||||
/** The Jhove engine */
|
||||
protected JhoveBase _base;
|
||||
/** Handler last modification date */
|
||||
protected Date _date;
|
||||
/** Character encoding for writer */
|
||||
protected String _encoding;
|
||||
/** Initialization value. */
|
||||
protected String _init;
|
||||
/** List of default parameters. */
|
||||
protected List<String> _defaultParams;
|
||||
/** JHOVE engine. */
|
||||
protected JhoveBase _je;
|
||||
/** Indentation level */
|
||||
protected int _level;
|
||||
/** Handler name */
|
||||
protected String _name;
|
||||
/** Handler note */
|
||||
protected String _note;
|
||||
/** Handler release description. */
|
||||
protected String _release;
|
||||
/** Handler-specific parameter. */
|
||||
protected String _param;
|
||||
/** Copyright notice */
|
||||
protected String _rights;
|
||||
/** Handler specification document list */
|
||||
protected List<Document> _specification;
|
||||
/** Handler vendor */
|
||||
protected Agent _vendor;
|
||||
/** Writer for doing output */
|
||||
protected PrintWriter _writer;
|
||||
/** Logger for a handler class. */
|
||||
protected Logger _logger;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Constructors of all subclasses of HandlerBase should call
|
||||
* this as a <code>super</code> constructor.
|
||||
*
|
||||
* @param name Name of the handler
|
||||
* @param release Release identifier
|
||||
* @param date Last modification date of the handler code,
|
||||
* in the form of an array of three numbers.
|
||||
* <code>date[0]</code> is the year,
|
||||
* <code>date[1]</code> the month, and
|
||||
* <code>date[2]</code> the day.
|
||||
* @param note Additional information about the handler
|
||||
* (may be null)
|
||||
* @param rights Copyright notice for the handler
|
||||
*/
|
||||
protected HandlerBase (String name, String release, int [] date,
|
||||
String note, String rights)
|
||||
{
|
||||
// Though we're actually in the jhove package, all the related
|
||||
// action logically belongs in the handler package, so we name
|
||||
// this logger accordingly.
|
||||
_logger = Logger.getLogger ("edu.harvard.hul.ois.jhove.handler");
|
||||
_logger.info ("Initializing " + name);
|
||||
_name = name;
|
||||
_release = release;
|
||||
_encoding = "UTF-8";
|
||||
|
||||
Calendar calendar = new GregorianCalendar ();
|
||||
calendar.set (date[0], date[1]-1, date[2]);
|
||||
_date = calendar.getTime ();
|
||||
|
||||
_note = note;
|
||||
_rights = rights;
|
||||
_specification = new ArrayList<Document> ();
|
||||
|
||||
_level = -1;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Initialization methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Reset the handler. This needs to be called before each invocation.
|
||||
*/
|
||||
public void reset () {
|
||||
_level = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a a List of default parameters for the module.
|
||||
*
|
||||
* @param params A List whose elements are Strings.
|
||||
* May be empty.
|
||||
*/
|
||||
public void setDefaultParams (List<String> params)
|
||||
{
|
||||
_defaultParams = params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the default parameters.
|
||||
* Calling this clears any prior parameters.
|
||||
*/
|
||||
public void applyDefaultParams ()
|
||||
throws Exception
|
||||
{
|
||||
resetParams ();
|
||||
Iterator<String> iter = _defaultParams.iterator ();
|
||||
while (iter.hasNext ()) {
|
||||
String parm = iter.next ();
|
||||
param (parm);
|
||||
}
|
||||
}
|
||||
|
||||
/** Reset parameter settings.
|
||||
* Returns to a default state without any parameters.
|
||||
* The default method clears the saved parameter.
|
||||
*/
|
||||
public void resetParams ()
|
||||
throws Exception
|
||||
{
|
||||
_param = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Per-instantiation initialization.
|
||||
* The default method does nothing.
|
||||
*/
|
||||
public void init (String init)
|
||||
throws Exception
|
||||
{
|
||||
_init = init;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-action initialization.
|
||||
* The default method does nothing.
|
||||
*/
|
||||
public void param (String param)
|
||||
throws Exception
|
||||
{
|
||||
_param = param;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Accessor methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Return the last modification date of this OutputHandler, as a
|
||||
* Java Date object
|
||||
*/
|
||||
public final Date getDate ()
|
||||
{
|
||||
return _date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the OutputHandler name
|
||||
*/
|
||||
public final String getName ()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the OutputHandler note
|
||||
*/
|
||||
public final String getNote ()
|
||||
{
|
||||
return _note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the release identifier
|
||||
*/
|
||||
public final String getRelease ()
|
||||
{
|
||||
return _release;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the copyright information string
|
||||
*/
|
||||
public final String getRights ()
|
||||
{
|
||||
return _rights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of <code>Document</code> objects (one for each
|
||||
* specification document). The specification
|
||||
* list is generated by the OutputHandler, and specifications cannot
|
||||
* be added by callers.
|
||||
*
|
||||
* @see Document
|
||||
*/
|
||||
public final List<Document> getSpecification ()
|
||||
{
|
||||
return _specification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the vendor information
|
||||
*/
|
||||
public final Agent getVendor ()
|
||||
{
|
||||
return _vendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this handler's encoding.
|
||||
*/
|
||||
public String getEncoding ()
|
||||
{
|
||||
return _encoding;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Mutator methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Pass the associated App object to this Module.
|
||||
* The App makes various services available.
|
||||
*/
|
||||
public final void setApp (App app)
|
||||
{
|
||||
_app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the JHOVE engine object to provide services to this handler
|
||||
*/
|
||||
public final void setBase (JhoveBase je)
|
||||
{
|
||||
_je = je;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the encoding to be used by this OutputHandler
|
||||
*/
|
||||
public void setEncoding (String encoding)
|
||||
{
|
||||
_encoding = encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a PrintWriter to do output for this OutputHandler
|
||||
*/
|
||||
public final void setWriter (PrintWriter writer)
|
||||
{
|
||||
_writer = writer;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Serialization methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Callback allowing post-parse, pre-show analysis of object
|
||||
* representation information.
|
||||
* @param info Object representation information
|
||||
*/
|
||||
public void analyze (RepInfo info)
|
||||
{
|
||||
/* Do nothing, which is sufficient for most handlers. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback indicating a directory is finished being processed.
|
||||
*/
|
||||
public void endDirectory ()
|
||||
{
|
||||
/* Do nothing, which is sufficient for most handlers. */
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to give the handler the opportunity to decide whether or
|
||||
* not to process a file. Most handlers will always return true.
|
||||
* @param filepath File pathname
|
||||
*/
|
||||
public boolean okToProcess (String filepath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs information about a Module
|
||||
*/
|
||||
public abstract void show (Module module);
|
||||
|
||||
/**
|
||||
* Outputs the information contained in a RepInfo object
|
||||
*/
|
||||
public abstract void show (RepInfo info);
|
||||
|
||||
/**
|
||||
* Outputs information about the OutputHandler specified
|
||||
* in the parameter
|
||||
*/
|
||||
public abstract void show (OutputHandler handler);
|
||||
|
||||
/**
|
||||
* Outputs minimal information about the application
|
||||
*/
|
||||
public abstract void show ();
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the application,
|
||||
* including configuration, available modules and handlers,
|
||||
* etc.
|
||||
*/
|
||||
public abstract void show (App app);
|
||||
|
||||
/**
|
||||
* Do the initial output. This should be in a suitable format
|
||||
* for including multiple files between the header and the footer.
|
||||
*/
|
||||
public abstract void showHeader ();
|
||||
|
||||
/**
|
||||
* Do the final output. This should be in a suitable format
|
||||
* for including multiple files between the header and the footer.
|
||||
*/
|
||||
public abstract void showFooter ();
|
||||
|
||||
/**
|
||||
* Close the writer after all output has been done.
|
||||
*/
|
||||
public void close ()
|
||||
{
|
||||
_writer.close ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback indicating a new directory is being processed.
|
||||
* @param directory Directory path
|
||||
*/
|
||||
public void startDirectory (String directory)
|
||||
{
|
||||
/* Do nothing, which is sufficient for most handlers. */
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PRIVATE CLASS METHODS.
|
||||
*
|
||||
* XML methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Return the XML DOCTYPE instruction.
|
||||
* @param root Root element of the DTD
|
||||
* @param uri URI of the DTD
|
||||
*/
|
||||
protected static String doctype (String root, String uri)
|
||||
{
|
||||
return doctype (root, null, uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the XML DOCTYPE instruction.
|
||||
* @param root Root element of the DTD
|
||||
* @param name Public name of the DTD
|
||||
* @param uri URI of the DTD
|
||||
*/
|
||||
protected static String doctype (String root, String name, String uri)
|
||||
{
|
||||
StringBuffer s = new StringBuffer ("<!DOCTYPE " + root);
|
||||
if (name != null) {
|
||||
s.append (" PUBLIC \"" + name + "\" \"");
|
||||
}
|
||||
else {
|
||||
s.append (" SYSTEM \"");
|
||||
}
|
||||
s.append (uri + "\">");
|
||||
|
||||
return s.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as a String, an empty XML.
|
||||
*
|
||||
* @param tag XML tag
|
||||
*/
|
||||
protected static String element (String tag)
|
||||
{
|
||||
return "<" + tag + "/>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as a String, an XML element with a given tag and content
|
||||
*
|
||||
* @param tag An XML tag
|
||||
* @param content Content string. Characters requiring
|
||||
* conversion to entitites will be converted.
|
||||
*/
|
||||
protected static String element (String tag, String content)
|
||||
{
|
||||
return elementStart (tag) + encodeContent (content) + elementEnd (tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as a String,
|
||||
* an XML element with a given tag and attributes
|
||||
*
|
||||
* @param tag An XML tag
|
||||
* @param attrs An array of String[2] elements, where for each
|
||||
* element, attrs[i][0] is the attribute key and
|
||||
* attrs[i][1] is the attribute value.
|
||||
* Null values are skipped.
|
||||
*/
|
||||
protected static String element (String tag, String [][] attrs)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ("<");
|
||||
buffer.append (tag);
|
||||
for (int i=0; i<attrs.length; i++) {
|
||||
if (attrs[i][0] != null && attrs[i][1] != null) {
|
||||
buffer.append (" ");
|
||||
buffer.append (attrs[i][0]);
|
||||
buffer.append ("=\"");
|
||||
buffer.append (encodeValue (attrs[i][1]));
|
||||
buffer.append ("\"");
|
||||
}
|
||||
}
|
||||
buffer.append ("/>");
|
||||
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as a String,
|
||||
* an XML element with a given tag, content and attributes
|
||||
*
|
||||
* @param tag An XML tag
|
||||
* @param content Content string. Characters requiring
|
||||
* conversion to entitites will be converted.
|
||||
* @param attrs An array of String[2] elements, where for each
|
||||
* element, attrs[i][0] is the attribute key and
|
||||
* attrs[i][1] is the attribute value.
|
||||
* Null values are skipped.
|
||||
*
|
||||
*/
|
||||
protected static String element (String tag, String [][] attrs,
|
||||
String content)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ("<");
|
||||
buffer.append (tag);
|
||||
for (int i=0; i<attrs.length; i++) {
|
||||
if (attrs[i][0] != null && attrs[i][1] != null) {
|
||||
buffer.append (" ");
|
||||
buffer.append (attrs[i][0]);
|
||||
buffer.append ("=\"");
|
||||
buffer.append (encodeValue (attrs[i][1]));
|
||||
buffer.append ("\"");
|
||||
}
|
||||
}
|
||||
buffer.append (">");
|
||||
buffer.append (encodeContent (content));
|
||||
buffer.append (elementEnd (tag));
|
||||
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as a String, the closing tag of an element.
|
||||
* No checking is done that opening and closing tags match.
|
||||
*
|
||||
* @param tag An XML tag
|
||||
*/
|
||||
protected static String elementEnd (String tag)
|
||||
{
|
||||
return "</" + tag + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as a String, the opening tag of an element.
|
||||
*
|
||||
* @param tag An XML tag
|
||||
*/
|
||||
protected static String elementStart (String tag)
|
||||
{
|
||||
return "<" + tag + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as a String, the opening tag of an element with
|
||||
* specified attributes.
|
||||
*
|
||||
* @param tag An XML tag
|
||||
* @param attrs An array of String[2] elements, where for each
|
||||
* element, attrs[i][0] is the attribute key and
|
||||
* attrs[i][1] is the attribute value.
|
||||
*/
|
||||
protected static String elementStart (String tag, String [][] attrs)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ("<");
|
||||
buffer.append (tag);
|
||||
for (int i=0; i<attrs.length; i++) {
|
||||
buffer.append (" ");
|
||||
buffer.append (attrs[i][0]);
|
||||
buffer.append ("=\"");
|
||||
buffer.append (encodeValue (attrs[i][1]));
|
||||
buffer.append ("\"");
|
||||
}
|
||||
buffer.append (">");
|
||||
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a content String in XML-clean form, converting characters
|
||||
* to entities as necessary and removing control characters disallowed
|
||||
* by XML. The null string will be converted to an empty string.
|
||||
*/
|
||||
private static String encodeContent (String content)
|
||||
{
|
||||
if (content == null) {
|
||||
content = "";
|
||||
}
|
||||
StringBuffer buffer = new StringBuffer (content);
|
||||
|
||||
/* Remove disallowed control characters from the content string. */
|
||||
int n = buffer.length ();
|
||||
for (int i=0; i<n; i++) {
|
||||
char ch = buffer.charAt (i);
|
||||
if ((0x00 <= ch && ch <= 0x08) || (0x0b <= ch && ch <= 0x0c) ||
|
||||
(0x0e <= ch && ch <= 0x1f) || 0x7f == ch) {
|
||||
buffer.deleteCharAt (i--);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf ("&", n)) > -1) {
|
||||
buffer.insert (n+1, "amp;");
|
||||
n +=5;
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf ("<", n)) > -1) {
|
||||
buffer.replace (n, n+1, "<");
|
||||
n += 4;
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf (">", n)) > -1) {
|
||||
buffer.replace (n, n+1, ">");
|
||||
n += 4;
|
||||
}
|
||||
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes an attribute value String in XML-clean form,
|
||||
* converting quote characters to entities and removing control
|
||||
* characters disallowed by XML.
|
||||
*/
|
||||
private static String encodeValue (String value)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer (value);
|
||||
|
||||
/* Remove disallowed control characters from the value string. */
|
||||
int n = buffer.length ();
|
||||
for (int i=0; i<n; i++) {
|
||||
char ch = buffer.charAt (i);
|
||||
if ((0x00 <= ch && ch <= 0x08) || (0x0b <= ch && ch <= 0x0c) ||
|
||||
(0x0e <= ch && ch <= 0x1f) || 0x7f == ch) {
|
||||
buffer.deleteCharAt (i--);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
// [CC], escape &, < and > characters which are disallowed in xml
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf ("&", n)) > -1) {
|
||||
buffer.insert (n+1, "amp;");
|
||||
n +=5;
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf ("<", n)) > -1) {
|
||||
buffer.replace (n, n+1, "<");
|
||||
n += 4;
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf (">", n)) > -1) {
|
||||
buffer.replace (n, n+1, ">");
|
||||
n += 4;
|
||||
}
|
||||
n = 0;
|
||||
while ((n = buffer.indexOf ("\"", n)) > -1) {
|
||||
// [LP] fix for invalid escaping, "" quotes were accidentally left in place.
|
||||
buffer.replace (n, n+1, """);
|
||||
n +=7;
|
||||
}
|
||||
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a canonical XML declaration with default encoding.
|
||||
*/
|
||||
protected static String xmlDecl ()
|
||||
{
|
||||
return "<?xml version=\"1.0\"?>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a canonical XML declaration with specified encoding.
|
||||
*/
|
||||
protected static String xmlDecl (String encoding)
|
||||
{
|
||||
return "<?xml version=\"1.0\" encoding=\"" +
|
||||
encoding +
|
||||
"\"?>";
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Nesting level methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Returns a String containing a number of spaces equal
|
||||
* to the current indent level.
|
||||
*/
|
||||
protected static String getIndent (int level)
|
||||
{
|
||||
StringBuffer s = new StringBuffer ();
|
||||
for (int i=0; i<level; i++) {
|
||||
s.append (" ");
|
||||
}
|
||||
|
||||
return s.toString ();
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* Array methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Return String representation of an integer array.
|
||||
*/
|
||||
protected static String integerArray (int [] iarray)
|
||||
{
|
||||
return integerArray (iarray, ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return String representation of an integer array with
|
||||
* specified separator.
|
||||
*/
|
||||
protected static String integerArray (int [] iarray, char separator)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
for (int i=0; i<iarray.length; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append (separator);
|
||||
}
|
||||
buffer.append (Integer.toString (iarray[i]));
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return String representation of an array of long with
|
||||
* space separator.
|
||||
*/
|
||||
protected static String longArray (long [] larray)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
for (int i=0; i<larray.length; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append (" ");
|
||||
}
|
||||
buffer.append (Long.toString (larray[i]));
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return String representation of an array of Rational, each evaluated
|
||||
* as a double, with space separator.
|
||||
*/
|
||||
protected static String rationalArray (Rational [] rarray)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
for (int i=0; i<rarray.length; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append (" ");
|
||||
}
|
||||
buffer.append (rarray[i].toDouble ());
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return String representation of an array of Rational, each as
|
||||
* two integers, with space separator.
|
||||
*/
|
||||
protected static String rationalArray10 (Rational [] rarray)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
for (int i=0; i<rarray.length; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append (" ");
|
||||
}
|
||||
buffer.append (rarray[i].getNumerator ());
|
||||
buffer.append (" ");
|
||||
buffer.append (rarray[i].getNumerator ());
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return String representation of an array of double.
|
||||
*/
|
||||
protected static String doubleArray (double [] darray)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
for (int i=0; i<darray.length; i++) {
|
||||
if (i > 0) {
|
||||
buffer.append (" ");
|
||||
}
|
||||
buffer.append (Double.toString (darray[i]));
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
|
||||
/* Text formatting methods. */
|
||||
/* Convert a date to the dateTime format used by the
|
||||
* XML schema. This is ISO 8610 with a colon between
|
||||
* the hour and minute fields of the time zone. Unfortunately,
|
||||
* SimpleDateFormat generates the time zone without the
|
||||
* colon; this also conforms to 8601, but doesn't conform
|
||||
* to the schema, so we have to diddle it.
|
||||
*/
|
||||
protected String toDateTime (Date date)
|
||||
{
|
||||
String isoStr = iso8601.format (date);
|
||||
// We can't directly use a SimpleDateFormat, because
|
||||
// the 'z' field gives us the colonless time zone.
|
||||
int len = isoStr.length ();
|
||||
// Add the colon before the last two characters.
|
||||
return isoStr.substring (0, len - 2) +
|
||||
":" +
|
||||
isoStr.substring (len - 2);
|
||||
}
|
||||
|
||||
/** A DateFormat class to address an issue of thread safety. */
|
||||
public static class SynchronizedDateFormat extends SimpleDateFormat
|
||||
{
|
||||
public SynchronizedDateFormat(String pattern) {
|
||||
super(pattern);
|
||||
}
|
||||
public synchronized StringBuffer format(Date date,
|
||||
StringBuffer toAppendTo, FieldPosition pos) {
|
||||
return super.format(date, toAppendTo, pos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* This class encapsulates information about an identifier
|
||||
* for a specification document.
|
||||
*/
|
||||
public class Identifier
|
||||
{
|
||||
private IdentifierType _type;
|
||||
private String _value;
|
||||
private String _note;
|
||||
|
||||
/**
|
||||
* Create an Identifier.
|
||||
* @param value The text displayed for this Identifier.
|
||||
* @param type The type of identification.
|
||||
*/
|
||||
public Identifier (String value, IdentifierType type)
|
||||
{
|
||||
_value = value;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Identifier.
|
||||
* @param value The text displayed for this Identifier.
|
||||
* @param type The type of identification.
|
||||
* @param note A note giving supplementary information.
|
||||
*/
|
||||
public Identifier (String value, IdentifierType type, String note)
|
||||
{
|
||||
this (value, type);
|
||||
_note = note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identifier type.
|
||||
*/
|
||||
public IdentifierType getType ()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the displayable string.
|
||||
*/
|
||||
public String getValue ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the note, which will be null if none was specified.
|
||||
*/
|
||||
public String getNote()
|
||||
{
|
||||
return _note;
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines enumerated types for an Identifier of a
|
||||
* format specification document.
|
||||
* Applications will not create or modify IdentifierTypes, but will
|
||||
* use one of the predefined IdentifierType instances
|
||||
* ANSI, DDC, DOI, ECMA, HANDLE, ISO, ISBN, LC, LCCN,
|
||||
* NISO, PII, RFC, SICI, URI, URL, URN, or OTHER.
|
||||
*
|
||||
* @see Identifier
|
||||
*/
|
||||
public final class IdentifierType
|
||||
extends EnumerationType
|
||||
{
|
||||
/**
|
||||
* Identifier type for American National Standards Institute.
|
||||
*/
|
||||
public static final IdentifierType ANSI = new IdentifierType ("ANSI");
|
||||
/**
|
||||
* Identifier type for Dewey Decimal Classification.
|
||||
*/
|
||||
public static final IdentifierType DDC = new IdentifierType ("DDC");
|
||||
/**
|
||||
* Identifier type for Digital Object Identifier.
|
||||
*/
|
||||
public static final IdentifierType DOI = new IdentifierType ("DOI");
|
||||
/**
|
||||
* Identifier type for ECMA.
|
||||
*/
|
||||
public static final IdentifierType ECMA = new IdentifierType ("ECMA");
|
||||
/**
|
||||
* Identifier type for CNRI Handle.
|
||||
*/
|
||||
public static final IdentifierType HANDLE = new IdentifierType ("Handle");
|
||||
/**
|
||||
* Identifier type for International Standards Organization.
|
||||
*/
|
||||
public static final IdentifierType ISO = new IdentifierType ("ISO");
|
||||
/**
|
||||
* Identifier type for International Standard Book Number.
|
||||
*/
|
||||
public static final IdentifierType ISBN = new IdentifierType ("ISBN");
|
||||
/**
|
||||
* Identifier type for Library of Congress classification.
|
||||
*/
|
||||
public static final IdentifierType LC = new IdentifierType ("LC");
|
||||
/**
|
||||
* Identifier type for Library of Congress catalogue number.
|
||||
*/
|
||||
public static final IdentifierType LCCN = new IdentifierType ("LCCN");
|
||||
/**
|
||||
* Identifier type for NISO standard number.
|
||||
*/
|
||||
public static final IdentifierType NISO = new IdentifierType ("NISO");
|
||||
/**
|
||||
* Identifier type for Publisher Item Identifier.
|
||||
*/
|
||||
public static final IdentifierType PII = new IdentifierType ("PII");
|
||||
/**
|
||||
* Identifier type for IETF Request for Comment.
|
||||
*/
|
||||
public static final IdentifierType RFC = new IdentifierType ("RFC");
|
||||
/**
|
||||
* Identifier type for Serial Item and Contribution Identifier.
|
||||
*/
|
||||
public static final IdentifierType SICI = new IdentifierType ("SICI");
|
||||
/**
|
||||
* Identifier type for Uniform Resource Identifier.
|
||||
*/
|
||||
public static final IdentifierType URI = new IdentifierType ("URI");
|
||||
/**
|
||||
* Identifier type for Uniform Resource Locator.
|
||||
*/
|
||||
public static final IdentifierType URL = new IdentifierType ("URL");
|
||||
/**
|
||||
* Identifier type for Uniform Resource Name.
|
||||
*/
|
||||
public static final IdentifierType URN = new IdentifierType ("URN");
|
||||
/**
|
||||
* Identifier type for CCITT.
|
||||
*/
|
||||
public static final IdentifierType CCITT = new IdentifierType ("CCITT");
|
||||
/**
|
||||
* Identifier type for International Telecommunication Union.
|
||||
*/
|
||||
public static final IdentifierType ITU = new IdentifierType ("ITU");
|
||||
/**
|
||||
* Identifier type for Japan Electronics and Information Technology
|
||||
* Industries Association.
|
||||
*/
|
||||
public static final IdentifierType JEITA = new IdentifierType ("JEITA");
|
||||
/**
|
||||
* Identifier type for whatever doesn't fit other categories.
|
||||
*/
|
||||
public static final IdentifierType OTHER = new IdentifierType ("Other");
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Applications will never create SignatureTypes directly.
|
||||
**/
|
||||
private IdentifierType (String value)
|
||||
{
|
||||
super (value);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* This class encapsulates an informational message from a Module, giving
|
||||
* information (not necessarily a problem)
|
||||
* about the content being analyzed or the way that Jhove
|
||||
* deals with it.
|
||||
*/
|
||||
public class InfoMessage
|
||||
extends Message
|
||||
{
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Create an InfoMessage.
|
||||
* @param message Human-readable string giving the information.
|
||||
*/
|
||||
public InfoMessage (String message)
|
||||
{
|
||||
super (message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an InfoMessage.
|
||||
* @param message Human-readable string giving the information.
|
||||
* @param offset The offset in the file relevant to the
|
||||
* situation being described
|
||||
*/
|
||||
public InfoMessage (String message, long offset)
|
||||
{
|
||||
super (message, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an InfoMessage.
|
||||
* @param message Human-readable string giving the information.
|
||||
* @param subMessage Human-readable additional information.
|
||||
*/
|
||||
public InfoMessage (String message, String subMessage)
|
||||
{
|
||||
super (message, subMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an InfoMessage.
|
||||
* @param message Human-readable string giving the information.
|
||||
* @param subMessage Human-readable additional information.
|
||||
* @param offset The offset in the file relevant to the
|
||||
* situation being described
|
||||
*/
|
||||
public InfoMessage (String message, String subMessage, long offset)
|
||||
{
|
||||
super (message, subMessage, offset);
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* This class encapsulates information about internal format signatures.
|
||||
* The value of a Signature may be either a String or a byte array
|
||||
* (stored as an int array to avoid signed byte problems).
|
||||
*/
|
||||
public class InternalSignature
|
||||
extends Signature
|
||||
{
|
||||
private boolean _hasFixedOffset;
|
||||
private int _offset;
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a string value, a type,
|
||||
* and a use requirement. An InternalSignature created with
|
||||
* this constructor does not have a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (String value, SignatureType type,
|
||||
SignatureUseType use)
|
||||
{
|
||||
super (value, type, use);
|
||||
_hasFixedOffset = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a byte array, a type,
|
||||
* and a use requirement. An InternalSignature created with
|
||||
* this constructor does not have a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (int[] value, SignatureType type,
|
||||
SignatureUseType use)
|
||||
{
|
||||
super (value, type, use);
|
||||
_hasFixedOffset = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a string value, a type,
|
||||
* a use requirement, and a byte offset. An InternalSignature
|
||||
* created with this constructor has a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (String value, SignatureType type,
|
||||
SignatureUseType use, int offset)
|
||||
{
|
||||
super (value, type, use);
|
||||
_offset = offset;
|
||||
_hasFixedOffset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a byte array, a type,
|
||||
* a use requirement, and a byte offset. An InternalSignature
|
||||
* created with this constructor has a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (int[] value, SignatureType type,
|
||||
SignatureUseType use, int offset)
|
||||
{
|
||||
super (value, type, use);
|
||||
_offset = offset;
|
||||
_hasFixedOffset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a string value, a type,
|
||||
* a use requirement, and a note. An InternalSignature created with
|
||||
* this constructor does not have a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (String value, SignatureType type,
|
||||
SignatureUseType use, String note)
|
||||
{
|
||||
super (value, type, use, note);
|
||||
_hasFixedOffset = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a byte array, a type,
|
||||
* a use requirement, and a note. An InternalSignature created with
|
||||
* this constructor does not have a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (int[] value, SignatureType type,
|
||||
SignatureUseType use, String note)
|
||||
{
|
||||
super (value, type, use, note);
|
||||
_hasFixedOffset = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a string value, a type,
|
||||
* a use requirement, a byte offset, and a note.
|
||||
* An InternalSignature created with
|
||||
* this constructor has a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (String value, SignatureType type,
|
||||
SignatureUseType use, int offset,
|
||||
String note)
|
||||
{
|
||||
super (value, type, use, note);
|
||||
_offset = offset;
|
||||
_hasFixedOffset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalSignature given a string value, a type,
|
||||
* a use requirement, a byte offset, and a note.
|
||||
* An InternalSignature created with
|
||||
* this constructor has a fixed byte offset.
|
||||
*/
|
||||
public InternalSignature (int[] value, SignatureType type,
|
||||
SignatureUseType use, int offset,
|
||||
String note)
|
||||
{
|
||||
super (value, type, use, note);
|
||||
_offset = offset;
|
||||
_hasFixedOffset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte offset. This value is meaningful only
|
||||
* if this InternalSignature has a fixed byte offset.
|
||||
*/
|
||||
public int getOffset ()
|
||||
{
|
||||
return _offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this InternalSignature
|
||||
* has a fixed byte offset.
|
||||
*/
|
||||
public boolean hasFixedOffset ()
|
||||
{
|
||||
return _hasFixedOffset;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
public class JhoveException
|
||||
extends Exception
|
||||
{
|
||||
public JhoveException ()
|
||||
{
|
||||
super ();
|
||||
}
|
||||
public JhoveException (String message)
|
||||
{
|
||||
super (message);
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
//import com.apple.eio.FileManager;
|
||||
|
||||
|
||||
/**
|
||||
* Code specific to Macintosh Java. This class consists of static
|
||||
* methods, and should not be instantiated. Its methods should be
|
||||
* called only on the Macintosh OS X platform. It requires the
|
||||
* package com.apple.eio.FileManager.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class MacStuff {
|
||||
|
||||
/** Private constructor to prevent instantiation.*/
|
||||
private MacStuff ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if we're running on a Macintosh,
|
||||
* so appropriate UI adjustments can be made. In accordance
|
||||
* with Apple's recommendations, this checks for the existence
|
||||
* of the mrj.version property rather than checking the os.name
|
||||
* property.
|
||||
*/
|
||||
public static boolean isMacintosh ()
|
||||
{
|
||||
return (System.getProperty ("mrj.version") != null);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if a file has the given file type.
|
||||
* This method uses FileManager in a dynamic way, so
|
||||
* that it will merely throw a ClassNotFound exception
|
||||
* if it fails.
|
||||
*
|
||||
* Currently this code isn't actually used, since the
|
||||
* Jhove application is specified as checking only internal
|
||||
* signatures. Should some future version or add-on
|
||||
* code wish to use it, the code should
|
||||
* look something like this:
|
||||
*
|
||||
* <code><pre>
|
||||
* try {
|
||||
* if (sig.getType() == SignatureType.FILETYPE &&
|
||||
* MacStuff.isMacintosh ()) {
|
||||
* if (!MacStuff.fileHasType(file, sig.getValueString())) {
|
||||
* info.setConsistent (false);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* catch (ClassNotFoundException e) {
|
||||
* // Mac classes missing -- can't check filetype.
|
||||
* }
|
||||
* </pre></code>
|
||||
*/
|
||||
public static boolean fileHasType(File file, String type)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
// Need to make this completely dynamic.
|
||||
//return type.equals (FileManager.getFileType (file));
|
||||
try {
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
Class fmclass = Class.forName ("com.apple.eio.FileManager");
|
||||
Class[] params = new Class[1];
|
||||
params[0] = Class.forName ("java.io.File");
|
||||
Object[] args = new Object[1];
|
||||
args[0] = file;
|
||||
Method method = fmclass.getMethod ("getFileType", params);
|
||||
String ftype = (String) method.invoke (null, args);
|
||||
return (type.equals (ftype));
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/**
|
||||
* This class encapsulates a String to be displayed.
|
||||
*/
|
||||
public abstract class Message
|
||||
{
|
||||
/******************************************************************
|
||||
* PUBLIC CLASS FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Value indicating a null offset. */
|
||||
public static final long NULL = -1;
|
||||
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
/** Message text. */
|
||||
protected String _message;
|
||||
|
||||
/** Additional information. */
|
||||
protected String _subMessage;
|
||||
|
||||
/** Byte offset to which message applies. */
|
||||
protected long _offset;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Create a Message. This constructor cannot be invoked directly,
|
||||
* since Message is abstract.
|
||||
* @param message Human-readable string.
|
||||
*/
|
||||
protected Message (String message)
|
||||
{
|
||||
init (message, null, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message. This constructor cannot be invoked directly,
|
||||
* since Message is abstract. The second argument
|
||||
* adds secondary details to the primary message;
|
||||
* the message will typically be displayed in the
|
||||
* form "message:subMessage".
|
||||
* @param message Human-readable string.
|
||||
* @param subMessage Human-readable additional information.
|
||||
*/
|
||||
protected Message (String message, String subMessage)
|
||||
{
|
||||
init (message, subMessage, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message. This constructor cannot be invoked directly,
|
||||
* since Message is abstract. The second argument
|
||||
* adds secondary details to the primary message;
|
||||
* the message will typically be displayed in the
|
||||
* form "message:subMessage".
|
||||
* @param message Human-readable string.
|
||||
* @param offset Byte offset associated with the message.
|
||||
*/
|
||||
protected Message (String message, long offset)
|
||||
{
|
||||
init (message, null, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message. This constructor cannot be invoked directly,
|
||||
* since Message is abstract. The second argument
|
||||
* adds secondary details to the primary message;
|
||||
* the message will typically be displayed in the
|
||||
* form "message:subMessage".
|
||||
* @param message Human-readable string.
|
||||
* @param subMessage Human-readable additional information.
|
||||
* @param offset Byte offset associated with the message.
|
||||
*/
|
||||
protected Message (String message, String subMessage, long offset)
|
||||
{
|
||||
init (message, subMessage, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the <tt>Message</tt> object.
|
||||
* @param message Human-readable string.
|
||||
* @param subMessage Human-readable additional information.
|
||||
*/
|
||||
private void init (String message, String subMessage, long offset)
|
||||
{
|
||||
_message = message;
|
||||
_subMessage = subMessage;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Accessor methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Get the message string.
|
||||
*/
|
||||
public String getMessage ()
|
||||
{
|
||||
return _message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the submessage string.
|
||||
*/
|
||||
public String getSubMessage ()
|
||||
{
|
||||
return _subMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the offset to which the information is related.
|
||||
*/
|
||||
public long getOffset ()
|
||||
{
|
||||
return _offset;
|
||||
}
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003-4 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Public interface for Jhove format-specific plug-in modules.
|
||||
*
|
||||
* All format modules must implement the Module interface;
|
||||
* usually the best way to do this will be to subclass ModuleBase.
|
||||
* Modules must be declared in the configuration file and present
|
||||
* in the Classpath to be recognized by Jhove.
|
||||
*
|
||||
* @see ModuleBase
|
||||
*/
|
||||
public interface Module
|
||||
{
|
||||
public static final int
|
||||
MAXIMUM_VERBOSITY = 1,
|
||||
MINIMUM_VERBOSITY = 2;
|
||||
|
||||
/**
|
||||
* Per-instantiation initialization.
|
||||
*
|
||||
* @param init Initialization parameter. This is typically obtained
|
||||
* from the configuration file.
|
||||
*/
|
||||
public void init (String init)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Sets list of default parameters.
|
||||
*
|
||||
* @param params A List whose elements are Strings.
|
||||
* May be empty.
|
||||
*/
|
||||
public void setDefaultParams (List<String> params);
|
||||
|
||||
|
||||
/**
|
||||
* Applies the default parameters.
|
||||
*/
|
||||
public void applyDefaultParams ()
|
||||
throws Exception;
|
||||
|
||||
/** Reset parameter settings.
|
||||
* Returns to a default state without any parameters.
|
||||
*/
|
||||
public void resetParams ()
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Per-action initialization.
|
||||
* May be called multiple times.
|
||||
*
|
||||
* @param param Initialization parameter.
|
||||
*/
|
||||
public void param (String param)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Pass the associated App object to this Module.
|
||||
* The App makes various services available.
|
||||
*/
|
||||
public void setApp (App app);
|
||||
|
||||
/**
|
||||
* Pass the JHOVE engine object to this Module.
|
||||
*/
|
||||
public void setBase (JhoveBase je);
|
||||
|
||||
/**
|
||||
* Set the degree of verbosity desired from the module.
|
||||
*
|
||||
* @param verbosity The requested verbosity value.
|
||||
*/
|
||||
public void setVerbosity (int verbosity);
|
||||
|
||||
/**
|
||||
* Return the name of this Module.
|
||||
*/
|
||||
public String getName ();
|
||||
|
||||
/**
|
||||
* Return the release identifier
|
||||
*/
|
||||
public String getRelease ();
|
||||
|
||||
/**
|
||||
* Return the last modification date of the Module, as a
|
||||
* Java Date object
|
||||
*/
|
||||
public Date getDate ();
|
||||
|
||||
/**
|
||||
* Return the vendor information
|
||||
*/
|
||||
public Agent getVendor ();
|
||||
|
||||
/**
|
||||
* Return the copyright information string
|
||||
*/
|
||||
public String getRights ();
|
||||
|
||||
/**
|
||||
* Return the Module note
|
||||
*/
|
||||
public String getNote ();
|
||||
|
||||
/**
|
||||
* Return the array of format names supported by this Module
|
||||
*/
|
||||
public String [] getFormat ();
|
||||
|
||||
/**
|
||||
* Return the array of MIME type strings for formats supported
|
||||
* by this Module
|
||||
*/
|
||||
public String [] getMimeType ();
|
||||
|
||||
/**
|
||||
* Return details as to the specific format versions or
|
||||
* variants that are supported by this Module
|
||||
*/
|
||||
public String getCoverage ();
|
||||
|
||||
/**
|
||||
* Return the List of Signatures recognized by this Module
|
||||
*/
|
||||
public List<Signature> getSignature ();
|
||||
|
||||
/**
|
||||
* Returns a list of <code>Document</code> objects (one for each
|
||||
* specification document of the format). The specification
|
||||
* list is generated by the Module, and specifications cannot
|
||||
* be added by callers.
|
||||
*
|
||||
* @see Document
|
||||
*/
|
||||
public List<Document> getSpecification ();
|
||||
|
||||
/**
|
||||
* Return the string describing well-formedness criteria
|
||||
*/
|
||||
public String getWellFormedNote ();
|
||||
|
||||
/**
|
||||
* Returns the RepInfo note
|
||||
*/
|
||||
public String getRepInfoNote ();
|
||||
|
||||
/**
|
||||
* Returns the string describing validity criteria
|
||||
*/
|
||||
public String getValidityNote ();
|
||||
|
||||
/**
|
||||
* Returns the random access flag (true if the module operates
|
||||
* on random access files, false if it operates on streams)
|
||||
*/
|
||||
public boolean isRandomAccess ();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the module supports a given
|
||||
* named feature, and <code>false</code> if the feature is
|
||||
* unsupported or unknown.
|
||||
*/
|
||||
public boolean hasFeature (String feature);
|
||||
|
||||
/**
|
||||
* Returns the full list of features.
|
||||
*/
|
||||
public List<String> getFeatures ();
|
||||
|
||||
/**
|
||||
* Returns the list of default parameters.
|
||||
*/
|
||||
public List<String> getDefaultParams ();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse the content of a stream digital object and store the
|
||||
* results in RepInfo.
|
||||
* A given Module will normally implement only one of the two
|
||||
* parse methods, leaving the other as a stub.
|
||||
*
|
||||
* @param stream An InputStream, positioned at its beginning,
|
||||
* which is generated from the object to be parsed.
|
||||
* If multiple calls to <code>parse</code> are made
|
||||
* on the basis of a nonzero value being returned,
|
||||
* a new InputStream must be provided each time.
|
||||
*
|
||||
* @param info A fresh (on the first call) RepInfo object
|
||||
* which will be modified
|
||||
* to reflect the results of the parsing
|
||||
* If multiple calls to <code>parse</code> are made
|
||||
* on the basis of a nonzero value being returned,
|
||||
* the same RepInfo object should be passed with each
|
||||
* call.
|
||||
*
|
||||
* @param parseIndex Must be 0 in first call to <code>parse</code>. If
|
||||
* <code>parse</code> returns a nonzero value, it must be
|
||||
* called again with <code>parseIndex</code>
|
||||
* equal to that return value.
|
||||
*/
|
||||
public int parse (InputStream stream, RepInfo info, int parseIndex)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Parse the content of a random access digital object and store the
|
||||
* results in RepInfo.
|
||||
* A given Module will normally implement only one of the two
|
||||
* parse methods, leaving the other as a stub.
|
||||
*
|
||||
* @param file A RandomAccessFile, positioned at its beginning,
|
||||
* which is generated from the object to be parsed
|
||||
* @param info A fresh RepInfo object which will be modified
|
||||
* to reflect the results of the parsing
|
||||
*/
|
||||
public void parse (RandomAccessFile file, RepInfo info)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Check if the digital object conforms to this Module's
|
||||
* internal signature information.
|
||||
*
|
||||
* @param file A File object for the object being parsed
|
||||
* @param stream An InputStream, positioned at its beginning,
|
||||
* which is generated from the object to be parsed
|
||||
* @param info A fresh RepInfo object which will be modified
|
||||
* to reflect the results of the test
|
||||
*/
|
||||
public void checkSignatures (File file,
|
||||
InputStream stream,
|
||||
RepInfo info)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Check if the digital object conforms to this Module's
|
||||
* internal signature information.
|
||||
*
|
||||
* @param file A File object for the object being parsed
|
||||
* @param raf A RandomAccessFile, positioned at its beginning,
|
||||
* which is generated from the object to be parsed
|
||||
* @param info A fresh RepInfo object which will be modified
|
||||
* to reflect the results of the test
|
||||
*/
|
||||
public void checkSignatures (File file,
|
||||
RandomAccessFile raf,
|
||||
RepInfo info)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Generates information about this Module.
|
||||
* The format of the output depends on the OutputHandler.
|
||||
*/
|
||||
public void show (OutputHandler handler);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
/** A small class to hold information about a module. */
|
||||
public class ModuleInfo {
|
||||
public String clas;
|
||||
public String init;
|
||||
public String[] params;
|
||||
|
||||
public ModuleInfo (String className) {
|
||||
clas = className;
|
||||
}
|
||||
|
||||
public ModuleInfo (String className, String init) {
|
||||
clas = className;
|
||||
this.init = init;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,118 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003-4 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Module for identification of a document. "Identification"
|
||||
* means determining, by querying modules successively, what the format
|
||||
* of a document is. The Bytestream module is always queried last,
|
||||
* so a document will by identified as a Bytestream if all else fails.
|
||||
*/
|
||||
public class ObjectIdentifier
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
private List _moduleList;
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
public ObjectIdentifier (List moduleList)
|
||||
{
|
||||
_moduleList = moduleList;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Processing methods.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Perform identification on a file. The file is parsed by
|
||||
* each of the modules in the module list until one
|
||||
* declares that the file is well-formed. It is assumed
|
||||
* that there is a module in the list (normally Bytestream
|
||||
* at the end) which will always consider a file well-formed.
|
||||
*/
|
||||
public void identify (File file, RepInfo info,
|
||||
String parm, boolean verbose,
|
||||
boolean shortCheck)
|
||||
throws IOException
|
||||
{
|
||||
/******************************************************
|
||||
* Go through all modules, in the order in the config
|
||||
* file, calling the parse method till we find one
|
||||
* which matches.
|
||||
******************************************************/
|
||||
|
||||
ListIterator modIter = _moduleList.listIterator();
|
||||
while (modIter.hasNext ()) {
|
||||
/* We need clean RepInfo for each run */
|
||||
RepInfo info1;
|
||||
info1 = (RepInfo) info.clone ();
|
||||
|
||||
Module mod = (Module) modIter.next ();
|
||||
try {
|
||||
if (!mod.hasFeature("edu.harvard.hul.ois.jhove.canValidate")) {
|
||||
continue;
|
||||
}
|
||||
if (mod.isRandomAccess ()) {
|
||||
RandomAccessFile raf =
|
||||
new RandomAccessFile (file, "r");
|
||||
mod.param (parm);
|
||||
if (verbose) {
|
||||
mod.setVerbosity (Module.MAXIMUM_VERBOSITY);
|
||||
}
|
||||
if (shortCheck) {
|
||||
mod.checkSignatures (file, raf, info1);
|
||||
}
|
||||
else {
|
||||
mod.parse (raf, info1);
|
||||
}
|
||||
raf.close ();
|
||||
}
|
||||
else {
|
||||
InputStream stream = new FileInputStream (file);
|
||||
mod.param (parm);
|
||||
if (shortCheck) {
|
||||
mod.checkSignatures (file, stream, info1);
|
||||
}
|
||||
else {
|
||||
int parseIndex = mod.parse (stream, info1, 0);
|
||||
while (parseIndex != 0) {
|
||||
stream.close ();
|
||||
stream = new FileInputStream (file);
|
||||
parseIndex = mod.parse (stream, info1, parseIndex);
|
||||
}
|
||||
}
|
||||
stream.close ();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
/* The assumption is that in trying to analyze
|
||||
the wrong type of file, the module may go
|
||||
off its track and throw an exception, so we
|
||||
just continue on to the next module.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (info1.getWellFormed () == RepInfo.TRUE) {
|
||||
info.copy (info1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Public interface for Jhove output handlers.
|
||||
* All output handlers must implement OutputHandler, and in
|
||||
* normal cases should subclass HandlerBase.
|
||||
*/
|
||||
public interface OutputHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Reset the handler. This needs to be called before each invocation.
|
||||
*/
|
||||
public void reset ();
|
||||
|
||||
/**
|
||||
* Callback allowing post-parse, pre-show analysis of object
|
||||
* representation information.
|
||||
* @param info Object representation information
|
||||
*/
|
||||
public void analyze (RepInfo info);
|
||||
|
||||
/**
|
||||
* Callback indicating a directory is finished being processed.
|
||||
* Most handlers will do nothing.
|
||||
*/
|
||||
public void endDirectory ();
|
||||
|
||||
/**
|
||||
* Returns the name of this handler
|
||||
*/
|
||||
public String getName ();
|
||||
/**
|
||||
* Returns release information for this handler
|
||||
*/
|
||||
public String getRelease ();
|
||||
|
||||
/**
|
||||
* Returns the last modification date of this handler
|
||||
*/
|
||||
public Date getDate ();
|
||||
|
||||
/**
|
||||
* Returns a List of Document objects giving the format
|
||||
* specification documentation
|
||||
*
|
||||
* @see Document
|
||||
*/
|
||||
public List<Document> getSpecification ();
|
||||
|
||||
/**
|
||||
* Returns a List of Agent objects giving the vendor(s)
|
||||
* of this handler.
|
||||
*/
|
||||
public Agent getVendor ();
|
||||
|
||||
/**
|
||||
* Returns this handler's note
|
||||
*/
|
||||
public String getNote ();
|
||||
|
||||
/**
|
||||
* Returns this handler's copyright information
|
||||
*/
|
||||
public String getRights ();
|
||||
|
||||
/**
|
||||
* Returns this handler's encoding.
|
||||
*/
|
||||
public String getEncoding ();
|
||||
|
||||
/**
|
||||
* Per-instantiation initialization.
|
||||
*
|
||||
* @param init Initialization parameter. This is typically obtained
|
||||
* from the configuration file.
|
||||
*/
|
||||
public void init (String init)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Callback to give the handler the opportunity to decide whether or
|
||||
* not to process a file. Most handlers will always return true.
|
||||
* @param filepath File pathname
|
||||
*/
|
||||
public boolean okToProcess (String filepath);
|
||||
|
||||
/**
|
||||
* Sets list of default parameters.
|
||||
*
|
||||
* @param params A List whose elements are Strings.
|
||||
* May be empty.
|
||||
*/
|
||||
public void setDefaultParams (List<String> params);
|
||||
|
||||
|
||||
/**
|
||||
* Applies the default parameters.
|
||||
*/
|
||||
public void applyDefaultParams ()
|
||||
throws Exception;
|
||||
|
||||
/** Reset parameter settings.
|
||||
* Returns to a default state without any parameters.
|
||||
*/
|
||||
public void resetParams ()
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Per-action initialization.
|
||||
*
|
||||
* @param param Initialization parameter.
|
||||
*/
|
||||
public void param (String param)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Assigns an application object to provide services to this handler
|
||||
*/
|
||||
public void setApp (App app);
|
||||
|
||||
/**
|
||||
* Assigns the JHOVE engine object to provide services to this handler
|
||||
*/
|
||||
public void setBase (JhoveBase je);
|
||||
|
||||
/**
|
||||
* Assigns the encoding to be used by this OutputHandler
|
||||
*/
|
||||
public void setEncoding (String encoding);
|
||||
|
||||
/**
|
||||
* Assigns a PrintWriter to do output for this OutputHandler
|
||||
*/
|
||||
public void setWriter (PrintWriter output);
|
||||
|
||||
/**
|
||||
* Outputs information about a Module
|
||||
*/
|
||||
public void show (Module module);
|
||||
|
||||
/**
|
||||
* Outputs the information contained in a RepInfo object
|
||||
*/
|
||||
public void show (RepInfo info);
|
||||
|
||||
/**
|
||||
* Outputs information about the OutputHandler specified
|
||||
* in the parameter
|
||||
*/
|
||||
public void show (OutputHandler handler);
|
||||
|
||||
/**
|
||||
* Outputs minimal information about the application
|
||||
*/
|
||||
public void show ();
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the application,
|
||||
* including configuration, available modules and handlers,
|
||||
* etc.
|
||||
*/
|
||||
public void show (App app);
|
||||
|
||||
/**
|
||||
* Do the initial output. This should be in a suitable format
|
||||
* for including multiple files between the header and the footer.
|
||||
*/
|
||||
public void showHeader ();
|
||||
|
||||
/**
|
||||
* Do the final output. This should be in a suitable format
|
||||
* for including multiple files between the header and the footer.
|
||||
*/
|
||||
public void showFooter ();
|
||||
|
||||
/**
|
||||
* Do appropriate finalization after all output is complete.
|
||||
*/
|
||||
public void close ();
|
||||
|
||||
/**
|
||||
* Callback indicating a new directory is being processed.
|
||||
* Most handlers will do nothing.
|
||||
* @param directory Directory path
|
||||
*/
|
||||
public void startDirectory (String directory);
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class encapsulates arbitrary format-specific properties.
|
||||
* A Property's value can be a simple object or a structure.
|
||||
* If it is a simple object, it has arity SCALAR. If it is
|
||||
* a structure, its must be a Map, a List, a Set, or an array,
|
||||
* with corresponding Arity. The simple object (in the case of
|
||||
* arity SCALAR) or the components of the structure must have a
|
||||
* type corresponding to one of the enumerations given by
|
||||
* <code>PropertyType</code>.
|
||||
*
|
||||
* The components of a Property may themselves be Property
|
||||
* objects, allowing nested structures.
|
||||
*
|
||||
* @see PropertyType
|
||||
* @see PropertyArity
|
||||
*/
|
||||
public class Property
|
||||
{
|
||||
/******************************************************************
|
||||
* PRIVATE INSTANCE FIELDS.
|
||||
******************************************************************/
|
||||
|
||||
private String _name;
|
||||
private PropertyType _type;
|
||||
private PropertyArity _arity;
|
||||
private Object _value;
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Creates a Property with arity SCALAR.
|
||||
*
|
||||
* @param name The displayable name of the property
|
||||
* @param type The type of property
|
||||
* @param value The value of the property. The type of the
|
||||
* parameter must agree with <code>type</code>.
|
||||
*/
|
||||
public Property (String name, PropertyType type, Object value)
|
||||
{
|
||||
init (name, type, PropertyArity.SCALAR, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Property with a given name, type, arity and value.
|
||||
*
|
||||
* @param name The displayable name of the property.
|
||||
* @param type The type of property.
|
||||
* @param arity The arity of the property.
|
||||
* @param value The value of the property. If the arity is
|
||||
* SCALAR, the type of this parameter must agree
|
||||
* with <code>type</code>. Otherwise, the arity
|
||||
* must agree with <code>arity</code>, and its
|
||||
* components must agree with <code>type</code>.
|
||||
*/
|
||||
public Property (String name, PropertyType type, PropertyArity arity,
|
||||
Object value)
|
||||
{
|
||||
init (name, type, arity, value);
|
||||
}
|
||||
|
||||
private void init (String name, PropertyType type, PropertyArity arity,
|
||||
Object value)
|
||||
{
|
||||
/* Some limited type checking. Checking for mismatched
|
||||
types here may help avoid difficult chasing down
|
||||
of the bugs such mismatches cause. */
|
||||
if (value == null) {
|
||||
throw new NullPointerException ("Null value for Property not permitted");
|
||||
}
|
||||
if (arity == PropertyArity.SCALAR) {
|
||||
if (value instanceof List ||
|
||||
value instanceof Map ||
|
||||
value instanceof Set) {
|
||||
throw new IncompatibleClassChangeError
|
||||
("Wrong class for Scalar Property");
|
||||
}
|
||||
}
|
||||
else if (arity == PropertyArity.MAP) {
|
||||
if (!(value instanceof Map)) {
|
||||
throw new IncompatibleClassChangeError
|
||||
("Wrong class for Map Property");
|
||||
}
|
||||
|
||||
}
|
||||
else if (arity == PropertyArity.SET) {
|
||||
if (!(value instanceof Set)) {
|
||||
throw new IncompatibleClassChangeError
|
||||
("Wrong class for Set Property");
|
||||
}
|
||||
|
||||
}
|
||||
else if (arity == PropertyArity.LIST) {
|
||||
if (!(value instanceof List)) {
|
||||
throw new IncompatibleClassChangeError
|
||||
("Wrong class for List Property");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_name = name;
|
||||
_type = type;
|
||||
_arity = arity;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* PUBLIC INSTANCE METHODS.
|
||||
*
|
||||
* Accessor methods.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Returns the arity (type of structure) of this Property.
|
||||
*/
|
||||
public PropertyArity getArity ()
|
||||
{
|
||||
return _arity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a property by its name, regardless of its position in the
|
||||
* structural hierarchy of properties.
|
||||
* @param name Property name
|
||||
* @return Named property (or null)
|
||||
*/
|
||||
public Property getByName (String name)
|
||||
{
|
||||
if (_name.equals (name)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (!_arity.equals (PropertyArity.SCALAR) &&
|
||||
_type.equals (PropertyType.PROPERTY)) {
|
||||
if (_arity.equals (PropertyArity.ARRAY)) {
|
||||
Property [] array = (Property []) _value;
|
||||
for (int i=0; i<array.length; i++) {
|
||||
Property prop = array[i].getByName (name);
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_arity.equals (PropertyArity.LIST)) {
|
||||
List list = (List) _value;
|
||||
int len = list.size ();
|
||||
for (int i=0; i<len; i++) {
|
||||
Property prop = ((Property) list.get (i)).getByName (name);
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_arity.equals (PropertyArity.MAP)) {
|
||||
Collection coll = ((Map) _value).values ();
|
||||
Iterator iter = coll.iterator ();
|
||||
while (iter.hasNext ()) {
|
||||
Property prop = ((Property) iter.next ()).getByName (name);
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_arity.equals (PropertyArity.SET)) {
|
||||
Iterator iter = ((Set) _value).iterator ();
|
||||
while (iter.hasNext ()) {
|
||||
Property prop = ((Property) iter.next ()).getByName (name);
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the displayable name of this Property.
|
||||
*/
|
||||
public String getName ()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this Property.
|
||||
* If the arity is other than SCALAR, the type refers to the
|
||||
* compononents of the Property structure.
|
||||
*/
|
||||
public PropertyType getType ()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Object which is the Property's value.
|
||||
*/
|
||||
public Object getValue ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* This class represents the arity (structure type) of a Property.
|
||||
* Applications will not create or modify PropertyArities, but will
|
||||
* use one of the predefined PropertyArity instances
|
||||
* ARRAY, LIST, MAP, SCALAR, or SET.
|
||||
*
|
||||
* @see Property
|
||||
*/
|
||||
public final class PropertyArity
|
||||
extends EnumerationType
|
||||
{
|
||||
/**
|
||||
* An Arity corresponding to a Java array. For the Java types
|
||||
* <code>Integer</code>, <code>Boolean</code>, <code>Byte</code>,
|
||||
* <code>Character</code>, <code>Double</code>,
|
||||
* <code>Float</code>, <code>Long</code>, and
|
||||
* <code>Short</code>, a Property with arity ARRAY is an array of primitive
|
||||
* Java types rather than Objects (e.g., <code>int</code>
|
||||
* rather than <code>Integer</code>).
|
||||
*/
|
||||
public static final PropertyArity ARRAY = new PropertyArity ("Array");
|
||||
|
||||
/**
|
||||
* An Arity corresponding to java.util.List or any of its derived classes.
|
||||
*/
|
||||
public static final PropertyArity LIST = new PropertyArity ("List");
|
||||
|
||||
/**
|
||||
* An Arity corresponding to java.util.Map or any of its derived classes.
|
||||
*/
|
||||
public static final PropertyArity MAP = new PropertyArity ("Map");
|
||||
|
||||
/**
|
||||
* An Arity corresponding to a simple object, which must be of a
|
||||
* type corresponding to one of the instances of
|
||||
* <code>PropertyType</code>.
|
||||
*/
|
||||
public static final PropertyArity SCALAR = new PropertyArity ("Scalar");
|
||||
|
||||
/**
|
||||
* An Arity corresponding to java.util.Set or any of its derived classes.
|
||||
*/
|
||||
public static final PropertyArity SET = new PropertyArity ("Set");
|
||||
|
||||
/**
|
||||
* Applications will never create PropertyArities directly.
|
||||
**/
|
||||
private PropertyArity (String value)
|
||||
{
|
||||
super (value);
|
||||
}
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A description of the location of a Property in a
|
||||
* RepInfo object. Properties can be nested under other
|
||||
* properties, in lists, maps, or subproperties. This class
|
||||
* provides a general way to specify their location.
|
||||
*
|
||||
* For the moment, only paths by name are fully supported.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class PropertyPath {
|
||||
|
||||
private List pathInfo;
|
||||
|
||||
/**
|
||||
* No-argument constructor.
|
||||
* Creates an empty path.
|
||||
*/
|
||||
public PropertyPath ()
|
||||
{
|
||||
pathInfo = new LinkedList ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning constructor.
|
||||
* This creates a new pathInfo list, whose elements
|
||||
* are shared with the original PropertyPath's list.
|
||||
*/
|
||||
public PropertyPath (PropertyPath path)
|
||||
{
|
||||
pathInfo = new LinkedList ();
|
||||
pathInfo.addAll (path.pathInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* String array constructor.
|
||||
* This allows creation of a path in a common and simple
|
||||
* case: a hierarchy of named subproperties. It's the
|
||||
* equivalent of creating an empty PropertyPath and then
|
||||
* calling addElement successively with each of the strings
|
||||
* in the array.
|
||||
*/
|
||||
public PropertyPath (String[] pathArray)
|
||||
{
|
||||
pathInfo = new LinkedList ();
|
||||
for (int i = 0; i < pathArray.length; i++) {
|
||||
pathInfo.add (pathArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a property name to the path.
|
||||
*/
|
||||
public void addPropertyName (String str)
|
||||
{
|
||||
pathInfo.add (str);
|
||||
// Now -- how do we add a key and distinguish it from a
|
||||
// property name? We could define an internal type for
|
||||
// keys. Do that for the moment and see what that leads
|
||||
// to in retrieval. Alternatively, it isn't needed because
|
||||
// we can see that a property has arity Map.
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key to the path, for a property map.
|
||||
*/
|
||||
public void addPropertyKey (Object obj)
|
||||
{
|
||||
pathInfo.add (new PropertyKey (obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an index to the path, for an indexed property.
|
||||
*/
|
||||
public void addPropertyIndex (int idx)
|
||||
{
|
||||
pathInfo.add (new Integer (idx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk down the path and return the specified Property.
|
||||
*
|
||||
* @param info The RepInfo object to search
|
||||
*
|
||||
* @return The specified Property if found, otherwise null.
|
||||
*/
|
||||
public Property locateProperty (RepInfo info)
|
||||
{
|
||||
return locateProperty (info, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Walk down the path and return the specified Property.
|
||||
*
|
||||
* @param info The RepInfo object to search
|
||||
* @param trace If <code>true</code>, write debugging information
|
||||
* to standard output.
|
||||
*
|
||||
* @return The specified Property if found, otherwise null.
|
||||
*/
|
||||
public Property locateProperty (RepInfo info, boolean trace)
|
||||
{
|
||||
if (pathInfo.isEmpty ()) {
|
||||
// An empty path can't reach any property
|
||||
if (trace) {
|
||||
System.out.println ("Empty property path");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Object obj = pathInfo.get(0);
|
||||
if (!(obj instanceof String)) {
|
||||
// The initial qualifier must be a property name
|
||||
if (trace) {
|
||||
System.out.println ("Not a property name");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
String top = (String) obj;
|
||||
if (trace) {
|
||||
System.out.println ("Getting proprerty " + top);
|
||||
}
|
||||
Property prop = info.getProperty (top);
|
||||
if (prop == null) {
|
||||
// No property of that name in RepInfo
|
||||
if (trace) {
|
||||
System.out.println ("Property is null");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
int pathLen = pathInfo.size ();
|
||||
// Pass the CDR of the list to locateSubProperty.
|
||||
return locateSubProperty (prop, pathInfo.subList (1, pathLen), trace);
|
||||
}
|
||||
|
||||
/* Recursive function for extracting a subproperty of a property. */
|
||||
private Property locateSubProperty (Property property, List path, boolean trace)
|
||||
{
|
||||
// If there's nothing left of the path, we're done.
|
||||
if (path.isEmpty ()) {
|
||||
return property;
|
||||
}
|
||||
List cdr = path.subList (1, path.size());
|
||||
PropertyArity arity = property.getArity ();
|
||||
PropertyType type = property.getType ();
|
||||
Object val = property.getValue ();
|
||||
if (trace) {
|
||||
System.out.println ("Property arity = " + arity + ", type = " + type);
|
||||
}
|
||||
// If the type isn't PROPERTY, then there are no subproperties.
|
||||
if (type != PropertyType.PROPERTY) {
|
||||
if (trace) {
|
||||
System.out.println ("Not a property, type is " + type.toString ());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Object obj = path.get (0);
|
||||
|
||||
if (obj instanceof String) {
|
||||
Iterator iter;
|
||||
// Iterate through the property and see if any of the elements
|
||||
// are Properties that match the name.
|
||||
String name = (String) obj;
|
||||
if (trace) {
|
||||
System.out.println ("Looking for subproperty " + name +
|
||||
" arity= " + arity.toString ());
|
||||
}
|
||||
if (arity.equals (PropertyArity.SCALAR)) {
|
||||
// There's just one shot at matching a scalar.
|
||||
Property p = (Property) property.getValue ();
|
||||
if (p.getName().equals (name)) {
|
||||
return locateSubProperty (p, cdr, trace);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (arity.equals (PropertyArity.ARRAY)) {
|
||||
// We know it's an array of Properties, which saves much
|
||||
// hair-tearing.
|
||||
Property[] parray = (Property []) val;
|
||||
for (int i = 0; i < parray.length; i++) {
|
||||
Property p = parray[i];
|
||||
if (p.getName ().equals (name)) {
|
||||
return locateSubProperty (p, cdr, trace);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (arity.equals (PropertyArity.LIST)) {
|
||||
iter = ((List) val).listIterator ();
|
||||
return getIteratedSubProperty (iter, name, cdr, trace);
|
||||
}
|
||||
else if (arity.equals (PropertyArity.SET)) {
|
||||
iter = ((Set) val).iterator ();
|
||||
return getIteratedSubProperty (iter, name, cdr, trace);
|
||||
}
|
||||
else if (arity.equals (PropertyArity.MAP)) {
|
||||
iter = ((Map) val).values().iterator();
|
||||
return getIteratedSubProperty (iter, name, cdr, trace);
|
||||
}
|
||||
else {
|
||||
// Should never happen, but keep compiler happy
|
||||
//System.out.println ("Unknown arity");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (obj instanceof Integer) {
|
||||
int idx = ((Integer) obj).intValue();
|
||||
//System.out.println ("Property index = " + idx + ", arity= " + arity.toString ());
|
||||
if (arity.equals (PropertyArity.LIST)) {
|
||||
List propList = (List) val;
|
||||
return locateSubProperty
|
||||
((Property) propList.get (idx), cdr, trace);
|
||||
}
|
||||
else if (arity.equals (PropertyArity.ARRAY)) {
|
||||
Property[] propArr = (Property []) val;
|
||||
return locateSubProperty (propArr[idx], cdr, trace);
|
||||
}
|
||||
else {
|
||||
// Other arities are not indexable
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (obj instanceof PropertyKey) {
|
||||
// This is applicable only to a Map.
|
||||
if (arity != PropertyArity.MAP) {
|
||||
return null;
|
||||
}
|
||||
return null; // I'm not sure this case is even meaningful
|
||||
}
|
||||
else {
|
||||
// We should never get here
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Walk through an Iterator, whose elements are Properties,
|
||||
* and return the subproperty by <code>path</code> of the first element
|
||||
* whose name matches <code>name</code>.
|
||||
*/
|
||||
private Property getIteratedSubProperty (Iterator iter,
|
||||
String name,
|
||||
List path,
|
||||
boolean trace)
|
||||
{
|
||||
while (iter.hasNext ()) {
|
||||
Property p = (Property) iter.next ();
|
||||
if (p.getName ().equals (name)) {
|
||||
return locateSubProperty (p, path, trace);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class PropertyKey
|
||||
{
|
||||
public Object key;
|
||||
|
||||
public PropertyKey (Object obj)
|
||||
{
|
||||
key = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003-2009 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines enumerated types for an Property of
|
||||
* some given content.
|
||||
* Applications will not create or modify PropertyTypes, but will
|
||||
* use one of the predefined PropertyType instances
|
||||
* BOOLEAN, BYTE, CHARACTER, DATE, DOUBLE, FLOAT, INTEGER,
|
||||
* LONG, OBJECT, PROPERTY, SHORT, STRING, RATIONAL, or
|
||||
* NISOIMAGEMETADATA.
|
||||
*
|
||||
* @see Property
|
||||
*/
|
||||
public final class PropertyType
|
||||
extends EnumerationType
|
||||
{
|
||||
/**
|
||||
* Property type for a <code>Boolean</code> object, or a
|
||||
* <code>boolean</code> if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType BOOLEAN = new PropertyType ("Boolean");
|
||||
/**
|
||||
* Property type for a <code>Byte</code> object, or a <code>byte</code>
|
||||
* if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType BYTE = new PropertyType ("Byte");
|
||||
/**
|
||||
* Property type for a <code>Character</code> object, or a
|
||||
* <code>char</code> if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType CHARACTER = new PropertyType("Character");
|
||||
/**
|
||||
* Property type for a <code>Date</code> object.
|
||||
*/
|
||||
public static final PropertyType DATE = new PropertyType ("Date");
|
||||
/**
|
||||
* Property type for a <code>Double</code> object, or
|
||||
*a <code>double</code> if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType DOUBLE = new PropertyType ("Double");
|
||||
/**
|
||||
* Property type for a <code>Float</code> object, or a
|
||||
* <code>float</code> if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType FLOAT = new PropertyType ("Float");
|
||||
/**
|
||||
* Property type for an <code>Integer</code> object, or an
|
||||
* <code>integer</code> if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType INTEGER = new PropertyType ("Integer");
|
||||
/**
|
||||
* Property type for a <code>Long</code> object, or a
|
||||
* <code>long</code> if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType LONG = new PropertyType ("Long");
|
||||
/**
|
||||
* Property type for an <code>Object</code>.
|
||||
*/
|
||||
public static final PropertyType OBJECT = new PropertyType ("Object");
|
||||
/**
|
||||
* Property type for an <code>AESAudioMetadata</code>.
|
||||
*/
|
||||
public static final PropertyType AESAUDIOMETADATA =
|
||||
new PropertyType ("AESAudioMetadata");
|
||||
/**
|
||||
* Property type for a <code>NisoImageMetadata</code>.
|
||||
*/
|
||||
public static final PropertyType NISOIMAGEMETADATA =
|
||||
new PropertyType ("NISOImageMetadata");
|
||||
/**
|
||||
* Property type for a <code>TextMDMetadata</code>.
|
||||
*/
|
||||
public static final PropertyType TEXTMDMETADATA =
|
||||
new PropertyType ("TextMDMetadata");
|
||||
/**
|
||||
* Property type for a <code>Property</code> object.
|
||||
*/
|
||||
public static final PropertyType PROPERTY = new PropertyType ("Property");
|
||||
/**
|
||||
* Property type for a <code>Short</code> object, or a
|
||||
* <code>short</code> if the Arity is Array.
|
||||
*/
|
||||
public static final PropertyType SHORT = new PropertyType ("Short");
|
||||
/**
|
||||
* Property type for a <code>String</code> object.
|
||||
*/
|
||||
public static final PropertyType STRING = new PropertyType ("String");
|
||||
/**
|
||||
* Property type for a <code>Rational</code> object.
|
||||
*/
|
||||
public static final PropertyType RATIONAL = new PropertyType ("Rational");
|
||||
|
||||
/******************************************************************
|
||||
* CLASS CONSTRUCTOR.
|
||||
******************************************************************/
|
||||
|
||||
/**
|
||||
* Applications will never create PropertyTypes directly.
|
||||
**/
|
||||
private PropertyType (String value)
|
||||
{
|
||||
super (value);
|
||||
}
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2004 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* An InputStream layered on top of a RandomAccessFile.
|
||||
* This is useful for a Module which has requirements that
|
||||
* force it to use a RandomAccessFile, but is usually
|
||||
* accessed sequentially.
|
||||
*
|
||||
* An RAFInputStream maintains its own position information
|
||||
* in the file, so multiple RAFInputStreams in the same file
|
||||
* will work without interference. However, this class is
|
||||
* not thread-safe.
|
||||
*
|
||||
* @author Gary McGath
|
||||
*
|
||||
*/
|
||||
public class RAFInputStream extends InputStream {
|
||||
|
||||
/* The file on which the stream is based */
|
||||
private RandomAccessFile _raf;
|
||||
|
||||
/* Size of fileBuf */
|
||||
private int fileBufSize;
|
||||
|
||||
/* Buffer for reading from the file */
|
||||
private byte[] fileBuf;
|
||||
|
||||
/* Offset for reading next byte from filebuf */
|
||||
private int fileBufPos;
|
||||
|
||||
/* Number of valid bytes in fileBuf */
|
||||
private int fileBufBytes;
|
||||
|
||||
/* Position in file for next read from RandomAccessFile */
|
||||
private long fileOffset;
|
||||
|
||||
/* EOF flag */
|
||||
boolean eof;
|
||||
|
||||
/**
|
||||
* Constructor with default buffer size.
|
||||
* The stream starts at the current position of the
|
||||
* RandomAccessFile.
|
||||
*
|
||||
* @param raf The file on which the
|
||||
* stream is to be based.
|
||||
*/
|
||||
public RAFInputStream(RandomAccessFile raf) {
|
||||
super();
|
||||
_raf = raf;
|
||||
fileBufSize = 65536; // pick a size, any size
|
||||
init ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor with buffer size.
|
||||
* The stream starts at the current position of the
|
||||
* RandomAccessFile.
|
||||
*
|
||||
* @param raf The file on which the
|
||||
* stream is to be based.
|
||||
*
|
||||
* @param bufferSize The buffer size to be used.
|
||||
* If less than or equal to 0, the
|
||||
* default buffer size is used.
|
||||
*/
|
||||
public RAFInputStream(RandomAccessFile raf, int bufferSize) {
|
||||
super();
|
||||
_raf = raf;
|
||||
fileBufSize = (bufferSize <= 0 ? 65536 : bufferSize);
|
||||
init ();
|
||||
}
|
||||
|
||||
private void init ()
|
||||
{
|
||||
fileBufBytes = 0;
|
||||
fileBufPos = 0;
|
||||
fileBuf = new byte[fileBufSize];
|
||||
try {
|
||||
fileOffset = _raf.getFilePointer ();
|
||||
}
|
||||
catch (IOException e) {}
|
||||
eof = false;
|
||||
|
||||
}
|
||||
/**
|
||||
* Reads a single byte from the file.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
if (eof) {
|
||||
return -1;
|
||||
}
|
||||
if (fileBufPos >= fileBufBytes) {
|
||||
// Need to read another bufferful
|
||||
_raf.seek (fileOffset);
|
||||
fileBufBytes = _raf.read (fileBuf);
|
||||
fileBufPos = 0;
|
||||
if (fileBufBytes <= 0) {
|
||||
// No more in file
|
||||
eof = true;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
fileOffset += fileBufBytes;
|
||||
}
|
||||
}
|
||||
return ((int) fileBuf[fileBufPos++] & 0XFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads some number of bytes from the input stream and
|
||||
* stores them into the buffer array b. The number of
|
||||
* bytes actually read is returned as an integer.
|
||||
*/
|
||||
public int read (byte[] b) throws IOException
|
||||
{
|
||||
int bytesToRead = b.length;
|
||||
int bytesRead = 0;
|
||||
for (;;) {
|
||||
// See how many bytes are available in fileBuf.
|
||||
int fbAvail = fileBufBytes - fileBufPos;
|
||||
if (fbAvail <= 0) {
|
||||
// Need to read another bufferful
|
||||
_raf.seek (fileOffset);
|
||||
fileBufBytes = _raf.read (fileBuf);
|
||||
fileBufPos = 0;
|
||||
if (fileBufBytes <= 0) {
|
||||
// No more in file -- return what we have
|
||||
eof = true;
|
||||
return bytesRead;
|
||||
}
|
||||
fbAvail = fileBufBytes;
|
||||
fileOffset += fileBufBytes;
|
||||
}
|
||||
if (fbAvail > bytesToRead) {
|
||||
// We have more than enough bytes.
|
||||
fbAvail = bytesToRead;
|
||||
}
|
||||
for (int i = 0; i < fbAvail; i++) {
|
||||
b[bytesRead++] = fileBuf[fileBufPos++];
|
||||
bytesToRead--;
|
||||
}
|
||||
if (bytesToRead == 0) {
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to len bytes of data from the input stream
|
||||
* into an array of bytes. An attempt is made to read as
|
||||
* many as len bytes, but a smaller number may be read,
|
||||
* possibly zero. The number of bytes actually read is
|
||||
* returned as an integer.
|
||||
*
|
||||
*/
|
||||
public int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
int bytesToRead = len;
|
||||
int bytesRead = 0;
|
||||
for (;;) {
|
||||
// See how many bytes are available in fileBuf.
|
||||
int fbAvail = fileBufBytes - fileBufPos;
|
||||
if (fbAvail <= 0) {
|
||||
// Need to read another bufferful
|
||||
_raf.seek (fileOffset);
|
||||
fileBufBytes = _raf.read (fileBuf);
|
||||
fileBufPos = 0;
|
||||
if (fileBufBytes <= 0) {
|
||||
// No more in file -- return what we have
|
||||
eof = true;
|
||||
return bytesRead;
|
||||
}
|
||||
fbAvail = fileBufBytes;
|
||||
fileOffset += fileBufBytes;
|
||||
}
|
||||
if (fbAvail > bytesToRead) {
|
||||
// We have more than enough bytes.
|
||||
fbAvail = bytesToRead;
|
||||
}
|
||||
for (int i = 0; i < fbAvail; i++) {
|
||||
b[off + bytesRead++] = fileBuf[fileBufPos++];
|
||||
bytesToRead--;
|
||||
}
|
||||
if (bytesToRead == 0) {
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Skips some number of bytes.
|
||||
*
|
||||
* @return The number of bytes actually skipped.
|
||||
*/
|
||||
public long skip (long n) throws IOException
|
||||
{
|
||||
// If the range of the skip lies
|
||||
// within the current buffer, we just adjust
|
||||
// the buffer offset.
|
||||
int bytesLeft = fileBufBytes - fileBufPos;
|
||||
if (bytesLeft > n) {
|
||||
fileBufPos += (int) n;
|
||||
}
|
||||
else {
|
||||
// doesn't fit within the buffer.
|
||||
// Set up to seek to the new position.
|
||||
//long curPos = _raf.getFilePointer ();
|
||||
if (fileOffset + n - bytesLeft > _raf.length ()) {
|
||||
fileOffset = _raf.length ();
|
||||
}
|
||||
//seek (curPos + n - bytesLeft);
|
||||
else {
|
||||
fileOffset += n - bytesLeft;
|
||||
}
|
||||
fileBufBytes = 0; // Invalidate current buffer
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the RandomAccessFile object.
|
||||
*/
|
||||
public RandomAccessFile getRAF ()
|
||||
{
|
||||
return _raf;
|
||||
}
|
||||
|
||||
|
||||
/** Positions the stream to a different point in the file.
|
||||
* This invalidates the buffer.
|
||||
*/
|
||||
public void seek (long offset) throws IOException
|
||||
{
|
||||
_raf.seek (offset);
|
||||
fileBufBytes = 0;
|
||||
fileBufPos = 0;
|
||||
eof = false;
|
||||
}
|
||||
|
||||
/** Returns the current position in the file.
|
||||
* What is reported is the position of the byte
|
||||
* in the file which was last extracted from
|
||||
* the buffer.
|
||||
*/
|
||||
public long getFilePos () throws IOException
|
||||
{
|
||||
return _raf.getFilePointer() -
|
||||
(fileBufBytes - fileBufPos);
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
|
||||
/**********************************************************************
|
||||
* Jhove - JSTOR/Harvard Object Validation Environment
|
||||
* Copyright 2003 by JSTOR and the President and Fellows of Harvard College
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
package edu.harvard.hul.ois.jhove;
|
||||
|
||||
|
||||
/**
|
||||
* Class encapsulating RFC-1766 language codes.
|
||||
*/
|
||||
public final class RFC1766Lang
|
||||
{
|
||||
|
||||
String _langCode;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param str The ASCII string for the language code.
|
||||
*/
|
||||
public RFC1766Lang (String str)
|
||||
{
|
||||
_langCode = str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the language code string.
|
||||
*/
|
||||
public String getLangCode ()
|
||||
{
|
||||
return _langCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the language code
|
||||
* string is syntactically compliant.
|
||||
* The primary tag must be either a two-letter code,
|
||||
* the letter i, or the letter x (case insensitive);
|
||||
* no checking is done against registry lists.
|
||||
*/
|
||||
public boolean isSyntaxCorrect ()
|
||||
{
|
||||
int i;
|
||||
if (_langCode == null) {
|
||||
return false;
|
||||
}
|
||||
char[] chrs = _langCode.toLowerCase().toCharArray();
|
||||
char firstChar = '\0';
|
||||
|
||||
int ntags = 0;
|
||||
int taglength = 0;
|
||||
for (i = 0; i < chrs.length; i++) {
|
||||
char ch = chrs[i];
|
||||
if (i == 0) {
|
||||
firstChar = ch;
|
||||
}
|
||||
if (!Character.isLetter (ch) && ch != '-') {
|
||||
return false;
|
||||
}
|
||||
if (ch == '-') {
|
||||
taglength = 0;
|
||||
|
||||
// If this is the primary tag, do some checks
|
||||
if (ntags++ == 0) {
|
||||
if (taglength == 1) {
|
||||
if (firstChar != 'i' && firstChar != 'x') {
|
||||
return false;
|
||||
}
|
||||
else if (taglength != 2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
taglength++;
|
||||
if (taglength > 8) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// A dangling hyphen at the end isn't allowed.
|
||||
if (taglength == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user