tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 1 | /* |
| 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 Canary | db68301 | 2016-11-23 08:55:18 -0700 | [diff] [blame] | 8 | #include "SkImageEncoderPriv.h" |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 9 | |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 10 | #ifdef SK_HAS_JPEG_LIBRARY |
| 11 | |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 12 | #include "SkColorPriv.h" |
Hal Canary | db68301 | 2016-11-23 08:55:18 -0700 | [diff] [blame] | 13 | #include "SkJPEGWriteUtility.h" |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 14 | #include "SkStream.h" |
| 15 | #include "SkTemplates.h" |
halcanary@google.com | fed3037 | 2013-10-04 12:46:45 +0000 | [diff] [blame] | 16 | |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 17 | #include <stdio.h> |
Hal Canary | db68301 | 2016-11-23 08:55:18 -0700 | [diff] [blame] | 18 | |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 19 | extern "C" { |
| 20 | #include "jpeglib.h" |
| 21 | #include "jerror.h" |
| 22 | } |
| 23 | |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 24 | typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, |
| 25 | const void* SK_RESTRICT src, int width, |
| 26 | const SkPMColor* SK_RESTRICT ctable); |
| 27 | |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 28 | static void Write_32_RGB(uint8_t* SK_RESTRICT dst, |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 29 | 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.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 33 | uint32_t c = *src++; |
| 34 | dst[0] = SkGetPackedR32(c); |
| 35 | dst[1] = SkGetPackedG32(c); |
| 36 | dst[2] = SkGetPackedB32(c); |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 37 | dst += 3; |
| 38 | } |
| 39 | } |
| 40 | |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 41 | static void Write_4444_RGB(uint8_t* SK_RESTRICT dst, |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 42 | 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.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 46 | SkPMColor16 c = *src++; |
| 47 | dst[0] = SkPacked4444ToR32(c); |
| 48 | dst[1] = SkPacked4444ToG32(c); |
| 49 | dst[2] = SkPacked4444ToB32(c); |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 50 | dst += 3; |
| 51 | } |
| 52 | } |
| 53 | |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 54 | static void Write_16_RGB(uint8_t* SK_RESTRICT dst, |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 55 | 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.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 59 | uint16_t c = *src++; |
| 60 | dst[0] = SkPacked16ToR32(c); |
| 61 | dst[1] = SkPacked16ToG32(c); |
| 62 | dst[2] = SkPacked16ToB32(c); |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 63 | dst += 3; |
| 64 | } |
| 65 | } |
| 66 | |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 67 | static void Write_Index_RGB(uint8_t* SK_RESTRICT dst, |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 68 | 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.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 72 | uint32_t c = ctable[*src++]; |
| 73 | dst[0] = SkGetPackedR32(c); |
| 74 | dst[1] = SkGetPackedG32(c); |
| 75 | dst[2] = SkGetPackedB32(c); |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 76 | dst += 3; |
| 77 | } |
| 78 | } |
| 79 | |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 80 | static WriteScanline ChooseWriter(SkColorType ct) { |
| 81 | switch (ct) { |
reed | 6c22573 | 2014-06-09 19:52:07 -0700 | [diff] [blame] | 82 | case kN32_SkColorType: |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 83 | return Write_32_RGB; |
reed | 6c22573 | 2014-06-09 19:52:07 -0700 | [diff] [blame] | 84 | case kRGB_565_SkColorType: |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 85 | return Write_16_RGB; |
reed | 6c22573 | 2014-06-09 19:52:07 -0700 | [diff] [blame] | 86 | case kARGB_4444_SkColorType: |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 87 | return Write_4444_RGB; |
reed | 6c22573 | 2014-06-09 19:52:07 -0700 | [diff] [blame] | 88 | case kIndex_8_SkColorType: |
msarett | c7d01d3 | 2016-04-18 14:21:55 -0700 | [diff] [blame] | 89 | return Write_Index_RGB; |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 90 | default: |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 91 | return nullptr; |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 92 | } |
| 93 | } |
| 94 | |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 95 | bool SkEncodeImageAsJPEG(SkWStream* stream, const SkPixmap& pixmap, int quality) { |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 96 | if (!pixmap.addr()) { |
| 97 | return false; |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 98 | } |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 99 | jpeg_compress_struct cinfo; |
| 100 | skjpeg_error_mgr sk_err; |
| 101 | skjpeg_destination_mgr sk_wstream(stream); |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 102 | |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 103 | // allocate these before set call setjmp |
| 104 | SkAutoTMalloc<uint8_t> oneRow; |
tomhudson@google.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 105 | |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 106 | 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.com | d33b26e | 2012-03-02 16:12:14 +0000 | [diff] [blame] | 159 | } |
Hal Canary | 1fcc404 | 2016-11-30 17:07:59 -0500 | [diff] [blame] | 160 | #endif |