blob: 345f869d3c5b8535822fb7cce0f5a7c61e0cedc3 [file] [log] [blame]
tomhudson@google.comd33b26e2012-03-02 16:12:14 +00001/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Hal Canarydb683012016-11-23 08:55:18 -07008#include "SkImageEncoderPriv.h"
tomhudson@google.comd33b26e2012-03-02 16:12:14 +00009
Hal Canary1fcc4042016-11-30 17:07:59 -050010#ifdef SK_HAS_JPEG_LIBRARY
11
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000012#include "SkColorPriv.h"
Hal Canarydb683012016-11-23 08:55:18 -070013#include "SkJPEGWriteUtility.h"
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000014#include "SkStream.h"
15#include "SkTemplates.h"
halcanary@google.comfed30372013-10-04 12:46:45 +000016
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000017#include <stdio.h>
Hal Canarydb683012016-11-23 08:55:18 -070018
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000019extern "C" {
20 #include "jpeglib.h"
21 #include "jerror.h"
22}
23
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000024typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
25 const void* SK_RESTRICT src, int width,
26 const SkPMColor* SK_RESTRICT ctable);
27
msarettc7d01d32016-04-18 14:21:55 -070028static void Write_32_RGB(uint8_t* SK_RESTRICT dst,
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000029 const void* SK_RESTRICT srcRow, int width,
30 const SkPMColor*) {
31 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
32 while (--width >= 0) {
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000033 uint32_t c = *src++;
34 dst[0] = SkGetPackedR32(c);
35 dst[1] = SkGetPackedG32(c);
36 dst[2] = SkGetPackedB32(c);
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000037 dst += 3;
38 }
39}
40
msarettc7d01d32016-04-18 14:21:55 -070041static void Write_4444_RGB(uint8_t* SK_RESTRICT dst,
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000042 const void* SK_RESTRICT srcRow, int width,
43 const SkPMColor*) {
44 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
45 while (--width >= 0) {
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000046 SkPMColor16 c = *src++;
47 dst[0] = SkPacked4444ToR32(c);
48 dst[1] = SkPacked4444ToG32(c);
49 dst[2] = SkPacked4444ToB32(c);
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000050 dst += 3;
51 }
52}
53
msarettc7d01d32016-04-18 14:21:55 -070054static void Write_16_RGB(uint8_t* SK_RESTRICT dst,
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000055 const void* SK_RESTRICT srcRow, int width,
56 const SkPMColor*) {
57 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
58 while (--width >= 0) {
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000059 uint16_t c = *src++;
60 dst[0] = SkPacked16ToR32(c);
61 dst[1] = SkPacked16ToG32(c);
62 dst[2] = SkPacked16ToB32(c);
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000063 dst += 3;
64 }
65}
66
msarettc7d01d32016-04-18 14:21:55 -070067static void Write_Index_RGB(uint8_t* SK_RESTRICT dst,
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000068 const void* SK_RESTRICT srcRow, int width,
69 const SkPMColor* SK_RESTRICT ctable) {
70 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
71 while (--width >= 0) {
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000072 uint32_t c = ctable[*src++];
73 dst[0] = SkGetPackedR32(c);
74 dst[1] = SkGetPackedG32(c);
75 dst[2] = SkGetPackedB32(c);
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000076 dst += 3;
77 }
78}
79
Hal Canary1fcc4042016-11-30 17:07:59 -050080static WriteScanline ChooseWriter(SkColorType ct) {
81 switch (ct) {
reed6c225732014-06-09 19:52:07 -070082 case kN32_SkColorType:
msarettc7d01d32016-04-18 14:21:55 -070083 return Write_32_RGB;
reed6c225732014-06-09 19:52:07 -070084 case kRGB_565_SkColorType:
msarettc7d01d32016-04-18 14:21:55 -070085 return Write_16_RGB;
reed6c225732014-06-09 19:52:07 -070086 case kARGB_4444_SkColorType:
msarettc7d01d32016-04-18 14:21:55 -070087 return Write_4444_RGB;
reed6c225732014-06-09 19:52:07 -070088 case kIndex_8_SkColorType:
msarettc7d01d32016-04-18 14:21:55 -070089 return Write_Index_RGB;
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000090 default:
halcanary96fcdcc2015-08-27 07:41:13 -070091 return nullptr;
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000092 }
93}
94
Hal Canary1fcc4042016-11-30 17:07:59 -050095bool SkEncodeImageAsJPEG(SkWStream* stream, const SkPixmap& pixmap, int quality) {
Hal Canary1fcc4042016-11-30 17:07:59 -050096 if (!pixmap.addr()) {
97 return false;
tomhudson@google.comd33b26e2012-03-02 16:12:14 +000098 }
Hal Canary1fcc4042016-11-30 17:07:59 -050099 jpeg_compress_struct cinfo;
100 skjpeg_error_mgr sk_err;
101 skjpeg_destination_mgr sk_wstream(stream);
tomhudson@google.comd33b26e2012-03-02 16:12:14 +0000102
Hal Canary1fcc4042016-11-30 17:07:59 -0500103 // allocate these before set call setjmp
104 SkAutoTMalloc<uint8_t> oneRow;
tomhudson@google.comd33b26e2012-03-02 16:12:14 +0000105
Hal Canary1fcc4042016-11-30 17:07:59 -0500106 cinfo.err = jpeg_std_error(&sk_err);
107 sk_err.error_exit = skjpeg_error_exit;
108 if (setjmp(sk_err.fJmpBuf)) {
109 return false;
110 }
111
112 // Keep after setjmp or mark volatile.
113 const WriteScanline writer = ChooseWriter(pixmap.colorType());
114 if (!writer) {
115 return false;
116 }
117
118 jpeg_create_compress(&cinfo);
119 cinfo.dest = &sk_wstream;
120 cinfo.image_width = pixmap.width();
121 cinfo.image_height = pixmap.height();
122 cinfo.input_components = 3;
123
124 // FIXME: Can we take advantage of other in_color_spaces in libjpeg-turbo?
125 cinfo.in_color_space = JCS_RGB;
126
127 // The gamma value is ignored by libjpeg-turbo.
128 cinfo.input_gamma = 1;
129
130 jpeg_set_defaults(&cinfo);
131
132 // Tells libjpeg-turbo to compute optimal Huffman coding tables
133 // for the image. This improves compression at the cost of
134 // slower encode performance.
135 cinfo.optimize_coding = TRUE;
136 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
137
138 jpeg_start_compress(&cinfo, TRUE);
139
140 const int width = pixmap.width();
141 uint8_t* oneRowP = oneRow.reset(width * 3);
142
143 const SkPMColor* colors = pixmap.ctable() ? pixmap.ctable()->readColors() : nullptr;
144 const void* srcRow = pixmap.addr();
145
146 while (cinfo.next_scanline < cinfo.image_height) {
147 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
148
149 writer(oneRowP, srcRow, width, colors);
150 row_pointer[0] = oneRowP;
151 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
152 srcRow = (const void*)((const char*)srcRow + pixmap.rowBytes());
153 }
154
155 jpeg_finish_compress(&cinfo);
156 jpeg_destroy_compress(&cinfo);
157
158 return true;
tomhudson@google.comd33b26e2012-03-02 16:12:14 +0000159}
Hal Canary1fcc4042016-11-30 17:07:59 -0500160#endif