OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2007 The Android Open Source Project | 2 * Copyright 2007 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 | 8 |
9 #include "SkImageEncoder.h" | 9 #include "SkImageEncoder.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include <stdio.h> | 21 #include <stdio.h> |
22 #include "SkJPEGWriteUtility.h" | 22 #include "SkJPEGWriteUtility.h" |
23 extern "C" { | 23 extern "C" { |
24 #include "jpeglib.h" | 24 #include "jpeglib.h" |
25 #include "jerror.h" | 25 #include "jerror.h" |
26 } | 26 } |
27 | 27 |
28 // These enable timing code that report milliseconds for an encoding | 28 // These enable timing code that report milliseconds for an encoding |
29 //#define TIME_ENCODE | 29 //#define TIME_ENCODE |
30 | 30 |
31 // this enables our rgb->yuv code, which is faster than libjpeg on ARM | |
32 #define WE_CONVERT_TO_YUV | |
33 | |
34 /////////////////////////////////////////////////////////////////////////////// | |
35 | |
36 #include "SkColorPriv.h" | |
37 | |
38 // taken from jcolor.c in libjpeg | |
39 #if 0 // 16bit - precise but slow | |
40 #define CYR 19595 // 0.299 | |
41 #define CYG 38470 // 0.587 | |
42 #define CYB 7471 // 0.114 | |
43 | |
44 #define CUR -11059 // -0.16874 | |
45 #define CUG -21709 // -0.33126 | |
46 #define CUB 32768 // 0.5 | |
47 | |
48 #define CVR 32768 // 0.5 | |
49 #define CVG -27439 // -0.41869 | |
50 #define CVB -5329 // -0.08131 | |
51 | |
52 #define CSHIFT 16 | |
53 #else // 8bit - fast, slightly less precise | |
54 #define CYR 77 // 0.299 | |
55 #define CYG 150 // 0.587 | |
56 #define CYB 29 // 0.114 | |
57 | |
58 #define CUR -43 // -0.16874 | |
59 #define CUG -85 // -0.33126 | |
60 #define CUB 128 // 0.5 | |
61 | |
62 #define CVR 128 // 0.5 | |
63 #define CVG -107 // -0.41869 | |
64 #define CVB -21 // -0.08131 | |
65 | |
66 #define CSHIFT 8 | |
67 #endif | |
68 | |
69 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { | |
70 int r = SkGetPackedR32(c); | |
71 int g = SkGetPackedG32(c); | |
72 int b = SkGetPackedB32(c); | |
73 | |
74 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; | |
75 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; | |
76 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; | |
77 | |
78 dst[0] = SkToU8(y); | |
79 dst[1] = SkToU8(u + 128); | |
80 dst[2] = SkToU8(v + 128); | |
81 } | |
82 | |
83 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { | |
84 int r = SkGetPackedR4444(c); | |
85 int g = SkGetPackedG4444(c); | |
86 int b = SkGetPackedB4444(c); | |
87 | |
88 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); | |
89 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); | |
90 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); | |
91 | |
92 dst[0] = SkToU8(y); | |
93 dst[1] = SkToU8(u + 128); | |
94 dst[2] = SkToU8(v + 128); | |
95 } | |
96 | |
97 static void rgb2yuv_16(uint8_t dst[], U16CPU c) { | |
98 int r = SkGetPackedR16(c); | |
99 int g = SkGetPackedG16(c); | |
100 int b = SkGetPackedB16(c); | |
101 | |
102 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); | |
103 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); | |
104 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); | |
105 | |
106 dst[0] = SkToU8(y); | |
107 dst[1] = SkToU8(u + 128); | |
108 dst[2] = SkToU8(v + 128); | |
109 } | |
110 | |
111 /////////////////////////////////////////////////////////////////////////////// | |
112 | |
113 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, | 31 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, |
114 const void* SK_RESTRICT src, int width, | 32 const void* SK_RESTRICT src, int width, |
115 const SkPMColor* SK_RESTRICT ctable); | 33 const SkPMColor* SK_RESTRICT ctable); |
116 | 34 |
117 static void Write_32_YUV(uint8_t* SK_RESTRICT dst, | 35 static void Write_32_RGB(uint8_t* SK_RESTRICT dst, |
118 const void* SK_RESTRICT srcRow, int width, | 36 const void* SK_RESTRICT srcRow, int width, |
119 const SkPMColor*) { | 37 const SkPMColor*) { |
120 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; | 38 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; |
121 while (--width >= 0) { | 39 while (--width >= 0) { |
122 #ifdef WE_CONVERT_TO_YUV | |
123 rgb2yuv_32(dst, *src++); | |
124 #else | |
125 uint32_t c = *src++; | 40 uint32_t c = *src++; |
126 dst[0] = SkGetPackedR32(c); | 41 dst[0] = SkGetPackedR32(c); |
127 dst[1] = SkGetPackedG32(c); | 42 dst[1] = SkGetPackedG32(c); |
128 dst[2] = SkGetPackedB32(c); | 43 dst[2] = SkGetPackedB32(c); |
129 #endif | |
130 dst += 3; | 44 dst += 3; |
131 } | 45 } |
132 } | 46 } |
133 | 47 |
134 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, | 48 static void Write_4444_RGB(uint8_t* SK_RESTRICT dst, |
135 const void* SK_RESTRICT srcRow, int width, | 49 const void* SK_RESTRICT srcRow, int width, |
136 const SkPMColor*) { | 50 const SkPMColor*) { |
137 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; | 51 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; |
138 while (--width >= 0) { | 52 while (--width >= 0) { |
139 #ifdef WE_CONVERT_TO_YUV | |
140 rgb2yuv_4444(dst, *src++); | |
141 #else | |
142 SkPMColor16 c = *src++; | 53 SkPMColor16 c = *src++; |
143 dst[0] = SkPacked4444ToR32(c); | 54 dst[0] = SkPacked4444ToR32(c); |
144 dst[1] = SkPacked4444ToG32(c); | 55 dst[1] = SkPacked4444ToG32(c); |
145 dst[2] = SkPacked4444ToB32(c); | 56 dst[2] = SkPacked4444ToB32(c); |
146 #endif | |
147 dst += 3; | 57 dst += 3; |
148 } | 58 } |
149 } | 59 } |
150 | 60 |
151 static void Write_16_YUV(uint8_t* SK_RESTRICT dst, | 61 static void Write_16_RGB(uint8_t* SK_RESTRICT dst, |
152 const void* SK_RESTRICT srcRow, int width, | 62 const void* SK_RESTRICT srcRow, int width, |
153 const SkPMColor*) { | 63 const SkPMColor*) { |
154 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; | 64 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; |
155 while (--width >= 0) { | 65 while (--width >= 0) { |
156 #ifdef WE_CONVERT_TO_YUV | |
157 rgb2yuv_16(dst, *src++); | |
158 #else | |
159 uint16_t c = *src++; | 66 uint16_t c = *src++; |
160 dst[0] = SkPacked16ToR32(c); | 67 dst[0] = SkPacked16ToR32(c); |
161 dst[1] = SkPacked16ToG32(c); | 68 dst[1] = SkPacked16ToG32(c); |
162 dst[2] = SkPacked16ToB32(c); | 69 dst[2] = SkPacked16ToB32(c); |
163 #endif | |
164 dst += 3; | 70 dst += 3; |
165 } | 71 } |
166 } | 72 } |
167 | 73 |
168 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, | 74 static void Write_Index_RGB(uint8_t* SK_RESTRICT dst, |
169 const void* SK_RESTRICT srcRow, int width, | 75 const void* SK_RESTRICT srcRow, int width, |
170 const SkPMColor* SK_RESTRICT ctable) { | 76 const SkPMColor* SK_RESTRICT ctable) { |
171 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; | 77 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; |
172 while (--width >= 0) { | 78 while (--width >= 0) { |
173 #ifdef WE_CONVERT_TO_YUV | |
174 rgb2yuv_32(dst, ctable[*src++]); | |
175 #else | |
176 uint32_t c = ctable[*src++]; | 79 uint32_t c = ctable[*src++]; |
177 dst[0] = SkGetPackedR32(c); | 80 dst[0] = SkGetPackedR32(c); |
178 dst[1] = SkGetPackedG32(c); | 81 dst[1] = SkGetPackedG32(c); |
179 dst[2] = SkGetPackedB32(c); | 82 dst[2] = SkGetPackedB32(c); |
180 #endif | |
181 dst += 3; | 83 dst += 3; |
182 } | 84 } |
183 } | 85 } |
184 | 86 |
185 static WriteScanline ChooseWriter(const SkBitmap& bm) { | 87 static WriteScanline ChooseWriter(const SkBitmap& bm) { |
186 switch (bm.colorType()) { | 88 switch (bm.colorType()) { |
187 case kN32_SkColorType: | 89 case kN32_SkColorType: |
188 return Write_32_YUV; | 90 return Write_32_RGB; |
189 case kRGB_565_SkColorType: | 91 case kRGB_565_SkColorType: |
190 return Write_16_YUV; | 92 return Write_16_RGB; |
191 case kARGB_4444_SkColorType: | 93 case kARGB_4444_SkColorType: |
192 return Write_4444_YUV; | 94 return Write_4444_RGB; |
193 case kIndex_8_SkColorType: | 95 case kIndex_8_SkColorType: |
194 return Write_Index_YUV; | 96 return Write_Index_RGB; |
195 default: | 97 default: |
196 return nullptr; | 98 return nullptr; |
197 } | 99 } |
198 } | 100 } |
199 | 101 |
200 class SkJPEGImageEncoder : public SkImageEncoder { | 102 class SkJPEGImageEncoder : public SkImageEncoder { |
201 protected: | 103 protected: |
202 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { | 104 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { |
203 #ifdef TIME_ENCODE | 105 #ifdef TIME_ENCODE |
204 SkAutoTime atm("JPEG Encode"); | 106 SkAutoTime atm("JPEG Encode"); |
(...skipping 21 matching lines...) Expand all Loading... |
226 const WriteScanline writer = ChooseWriter(bm); | 128 const WriteScanline writer = ChooseWriter(bm); |
227 if (nullptr == writer) { | 129 if (nullptr == writer) { |
228 return false; | 130 return false; |
229 } | 131 } |
230 | 132 |
231 jpeg_create_compress(&cinfo); | 133 jpeg_create_compress(&cinfo); |
232 cinfo.dest = &sk_wstream; | 134 cinfo.dest = &sk_wstream; |
233 cinfo.image_width = bm.width(); | 135 cinfo.image_width = bm.width(); |
234 cinfo.image_height = bm.height(); | 136 cinfo.image_height = bm.height(); |
235 cinfo.input_components = 3; | 137 cinfo.input_components = 3; |
236 #ifdef WE_CONVERT_TO_YUV | 138 |
237 cinfo.in_color_space = JCS_YCbCr; | 139 // FIXME: Can we take advantage of other in_color_spaces in libjpeg-turb
o? |
238 #else | |
239 cinfo.in_color_space = JCS_RGB; | 140 cinfo.in_color_space = JCS_RGB; |
240 #endif | 141 |
| 142 // The gamma value is ignored by libjpeg-turbo. |
241 cinfo.input_gamma = 1; | 143 cinfo.input_gamma = 1; |
242 | 144 |
243 jpeg_set_defaults(&cinfo); | 145 jpeg_set_defaults(&cinfo); |
| 146 |
| 147 // Tells libjpeg-turbo to compute optimal Huffman coding tables |
| 148 // for the image. This improves compression at the cost of |
| 149 // slower encode performance. |
244 cinfo.optimize_coding = TRUE; | 150 cinfo.optimize_coding = TRUE; |
245 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values
*/); | 151 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values
*/); |
246 #ifdef DCT_IFAST_SUPPORTED | |
247 cinfo.dct_method = JDCT_IFAST; | |
248 #endif | |
249 | 152 |
250 jpeg_start_compress(&cinfo, TRUE); | 153 jpeg_start_compress(&cinfo, TRUE); |
251 | 154 |
252 const int width = bm.width(); | 155 const int width = bm.width(); |
253 uint8_t* oneRowP = oneRow.reset(width * 3); | 156 uint8_t* oneRowP = oneRow.reset(width * 3); |
254 | 157 |
255 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC
olors() : nullptr; | 158 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC
olors() : nullptr; |
256 const void* srcRow = bm.getPixels(); | 159 const void* srcRow = bm.getPixels(); |
257 | 160 |
258 while (cinfo.next_scanline < cinfo.image_height) { | 161 while (cinfo.next_scanline < cinfo.image_height) { |
(...skipping 14 matching lines...) Expand all Loading... |
273 | 176 |
274 /////////////////////////////////////////////////////////////////////////////// | 177 /////////////////////////////////////////////////////////////////////////////// |
275 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); | 178 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); |
276 /////////////////////////////////////////////////////////////////////////////// | 179 /////////////////////////////////////////////////////////////////////////////// |
277 | 180 |
278 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 181 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
279 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; | 182 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; |
280 } | 183 } |
281 | 184 |
282 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 185 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |
OLD | NEW |