/
prism.c
130 lines (109 loc) · 2.94 KB
/
prism.c
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <prism.h>
int isRecoverableError(char* errorStr) {
if (!strcmp(errorStr, "Invalid SOS parameters for sequential JPEG") ||
!strcmp(errorStr, "Premature end of JPEG file")) {
return 1;
}
return 0;
}
void printError(char* errorStr) {
fprintf(stderr, "prism: %s\n", errorStr);
fflush(stderr);
}
IplImage* prismDecode(void* data, unsigned int dataSize) {
int err;
IplImage* iplImage;
tjhandle jpeg = tjInitDecompress();
int width, height, subsamp, colorspace;
// attempt to decode JPEG header
err = tjDecompressHeader3(jpeg, (unsigned char*)data, dataSize, &width, &height, &subsamp, &colorspace);
if (err) {
tjDestroy(jpeg);
// fall back to OpenCV decoding
CvMat* cvMat = cvCreateMatHeader(1, dataSize, CV_8UC1);
cvSetData(cvMat, data, dataSize);
iplImage = cvDecodeImage(cvMat, CV_LOAD_IMAGE_UNCHANGED);
cvReleaseMat(&cvMat);
if (iplImage) {
return iplImage;
}
printError(tjGetErrorStr());
return NULL;
}
int channels = 3, pixelFmt = TJPF_BGR;
if (colorspace == TJCS_GRAY) {
channels = 1;
pixelFmt = TJPF_GRAY;
}
unsigned char* buffer = cvAlloc(width * height * channels);
err = tjDecompress2(
jpeg, (unsigned char*)data, dataSize, buffer, 0, 0, 0, pixelFmt, TJFLAG_FASTDCT
);
tjDestroy(jpeg);
if (err) {
char* errorStr = tjGetErrorStr();
if (!isRecoverableError(errorStr)) {
cvFree(&buffer);
printError(errorStr);
return NULL;
}
}
iplImage = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, channels);
cvSetData(iplImage, buffer, width * channels);
return iplImage;
}
PrismEncoded* prismEncodeJPEG(IplImage* img, int quality) {
int pixFmt, subsamp;
switch (img->nChannels) {
case 1:
pixFmt = TJPF_GRAY;
subsamp = TJSAMP_GRAY;
break;
case 4:
pixFmt = TJPF_BGRA;
subsamp = TJSAMP_420;
break;
default:
pixFmt = TJPF_BGR;
subsamp = TJSAMP_420;
}
int err;
CvSize size = cvGetSize(img);
tjhandle jpeg = tjInitCompress();
PrismEncoded* enc = calloc(1, sizeof(PrismEncoded));
err = tjCompress2(
jpeg, (unsigned char*)img->imageData, size.width, img->widthStep,
size.height, pixFmt, &enc->buffer, &enc->size, subsamp, quality, 0
);
tjDestroy(jpeg);
if (err) {
printError(tjGetErrorStr());
prismRelease(enc);
return NULL;
}
return enc;
}
PrismEncoded* prismEncodePNG(IplImage* img, int compression) {
int encodeParams[5] = {
CV_IMWRITE_PNG_COMPRESSION, compression,
CV_IMWRITE_PNG_STRATEGY, 0,
0,
};
CvMat* cvMat = cvEncodeImage(".png", img, encodeParams);
if (!cvMat) {
return NULL;
}
PrismEncoded* enc = malloc(sizeof(PrismEncoded));
enc->buffer = cvMat->data.ptr;
enc->size = cvMat->cols;
enc->_mat = cvMat;
return enc;
}
void prismRelease(PrismEncoded* enc) {
if (enc->_mat) {
cvReleaseMat(&enc->_mat);
} else if (enc->buffer) {
tjFree(enc->buffer);
}
free(enc);
}