-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPngParser.java
More file actions
81 lines (65 loc) · 2.62 KB
/
PngParser.java
File metadata and controls
81 lines (65 loc) · 2.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package me.tamkungz.codecmedia.internal.image.png;
import me.tamkungz.codecmedia.CodecMediaException;
public final class PngParser {
private static final byte[] PNG_SIGNATURE = new byte[] {
(byte) 0x89, 0x50, 0x4E, 0x47,
0x0D, 0x0A, 0x1A, 0x0A
};
private PngParser() {
}
public static boolean isLikelyPng(byte[] bytes) {
if (bytes.length < PNG_SIGNATURE.length) {
return false;
}
for (int i = 0; i < PNG_SIGNATURE.length; i++) {
if (bytes[i] != PNG_SIGNATURE[i]) {
return false;
}
}
return true;
}
public static PngProbeInfo parse(byte[] bytes) throws CodecMediaException {
if (!isLikelyPng(bytes)) {
throw new CodecMediaException("Not a PNG file");
}
if (bytes.length < 33) {
throw new CodecMediaException("PNG is too small");
}
int ihdrLength = readBeInt(bytes, 8);
if (ihdrLength != 13) {
throw new CodecMediaException("Invalid IHDR length: " + ihdrLength);
}
if (!(bytes[12] == 'I' && bytes[13] == 'H' && bytes[14] == 'D' && bytes[15] == 'R')) {
throw new CodecMediaException("PNG missing IHDR chunk");
}
int width = readBeInt(bytes, 16);
int height = readBeInt(bytes, 20);
int bitDepth = bytes[24] & 0xFF;
int colorType = bytes[25] & 0xFF;
if (width <= 0 || height <= 0) {
throw new CodecMediaException("PNG has invalid dimensions");
}
if (!isValidBitDepth(bitDepth)) {
throw new CodecMediaException("PNG has invalid bit depth: " + bitDepth);
}
if (!isValidColorType(colorType)) {
throw new CodecMediaException("PNG has invalid color type: " + colorType);
}
return new PngProbeInfo(width, height, bitDepth, colorType);
}
private static boolean isValidBitDepth(int bitDepth) {
return bitDepth == 1 || bitDepth == 2 || bitDepth == 4 || bitDepth == 8 || bitDepth == 16;
}
private static boolean isValidColorType(int colorType) {
return colorType == 0 || colorType == 2 || colorType == 3 || colorType == 4 || colorType == 6;
}
private static int readBeInt(byte[] bytes, int offset) throws CodecMediaException {
if (offset + 4 > bytes.length) {
throw new CodecMediaException("Unexpected end of PNG data");
}
return ((bytes[offset] & 0xFF) << 24)
| ((bytes[offset + 1] & 0xFF) << 16)
| ((bytes[offset + 2] & 0xFF) << 8)
| (bytes[offset + 3] & 0xFF);
}
}