Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2010, Google Inc. All rights reserved. | 2 * Copyright (c) 2010, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #include "platform/image-encoders/JPEGImageEncoder.h" | 31 #include "platform/image-encoders/JPEGImageEncoder.h" |
| 32 | 32 |
| 33 #include "SkColorPriv.h" | 33 #include "SkColorPriv.h" |
| 34 #include "platform/geometry/IntSize.h" | 34 #include "platform/geometry/IntSize.h" |
| 35 #include "platform/graphics/ImageBuffer.h" | 35 #include "platform/graphics/ImageBuffer.h" |
| 36 #include "platform/image-encoders/RGBAtoRGB.h" | |
| 36 #include "wtf/CurrentTime.h" | 37 #include "wtf/CurrentTime.h" |
| 37 #include "wtf/PtrUtil.h" | 38 #include "wtf/PtrUtil.h" |
| 38 #include <memory> | 39 #include <memory> |
| 39 | 40 |
| 40 extern "C" { | 41 extern "C" { |
| 41 #include <setjmp.h> | 42 #include <setjmp.h> |
| 42 #include <stdio.h> // jpeglib.h needs stdio.h FILE | 43 #include <stdio.h> // jpeglib.h needs stdio.h FILE |
| 43 #include "jpeglib.h" | 44 #include "jpeglib.h" |
| 44 } | 45 } |
| 45 | 46 |
| 46 namespace blink { | 47 namespace blink { |
| 47 | 48 |
| 49 void RGBAtoRGBScalar(const unsigned char* pixels, | |
| 50 unsigned pixelCount, | |
| 51 unsigned char* output) { | |
| 52 // Per <canvas> spec, composite the input image pixels source-over on black. | |
| 53 for (; pixelCount-- > 0; pixels += 4) { | |
| 54 unsigned char alpha = pixels[3]; | |
| 55 if (alpha != 255) { | |
| 56 *output++ = SkMulDiv255Round(pixels[0], alpha); | |
| 57 *output++ = SkMulDiv255Round(pixels[1], alpha); | |
| 58 *output++ = SkMulDiv255Round(pixels[2], alpha); | |
| 59 } else { | |
| 60 *output++ = pixels[0]; | |
| 61 *output++ = pixels[1]; | |
| 62 *output++ = pixels[2]; | |
| 63 } | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 // TODO(cavalcantii): use regular macro, see https://crbug.com/673067. | |
| 68 #ifdef __ARM_NEON__ | |
| 69 | |
| 70 // TODO(cavalcantii): this came straight from SkSwizzler_opts.h, I wonder | |
| 71 // how to include it? | |
|
msarett
2016/12/18 18:48:37
Sorry for being unclear, there's no plan to make t
| |
| 72 inline uint8x8_t div255Round(uint16x8_t x) { | |
| 73 return vraddhn_u16(x, vrshrq_n_u16(x, 8)); | |
| 74 } | |
| 75 | |
| 76 inline uint8x8_t scale(uint8x8_t x, uint8x8_t y) { | |
| 77 return div255Round(vmull_u8(x, y)); | |
| 78 } | |
| 79 | |
| 80 void RGBAtoRGBNeon(const unsigned char* input, | |
| 81 const unsigned pixelCount, | |
| 82 unsigned char* output) { | |
| 83 const unsigned pixelsPerLoad = 16; | |
| 84 const unsigned rgbaStep = pixelsPerLoad * 4, rgbStep = pixelsPerLoad * 3; | |
| 85 // Input registers. | |
| 86 uint8x16x4_t rgba; | |
| 87 // Output registers. | |
| 88 uint8x16x3_t rgb; | |
| 89 // Intermediate registers. | |
| 90 uint8x8_t low, high; | |
| 91 uint8x16_t result; | |
| 92 unsigned counter; | |
| 93 | |
| 94 auto transformColor = [&](size_t channel) { | |
| 95 // Extracts the low/high part of the 128 bits and scale using Skia code. | |
| 96 low = vget_low_u8(rgba.val[channel]); | |
| 97 high = vget_high_u8(rgba.val[channel]); | |
| 98 low = scale(low, vget_low_u8(rgba.val[3])); | |
| 99 high = scale(high, vget_high_u8(rgba.val[3])); | |
| 100 result = vcombine_u8(low, high); | |
| 101 // Write back the channel to a 128 bits register. | |
| 102 rgb.val[channel] = result; | |
| 103 }; | |
| 104 | |
| 105 for (counter = 0; counter + pixelsPerLoad <= pixelCount; | |
| 106 counter += pixelsPerLoad) { | |
| 107 // Reads 16 pixels at once, each color channel in a different | |
| 108 // 128 bits register. | |
| 109 rgba = vld4q_u8(input); | |
| 110 | |
| 111 transformColor(0); | |
| 112 transformColor(1); | |
| 113 transformColor(2); | |
| 114 | |
| 115 // Write back (interleaved) results to output. | |
| 116 vst3q_u8(output, rgb); | |
| 117 | |
| 118 // Advance to next elements (could be avoided loading register with | |
| 119 // increment after i.e. "vld4 {vector}, [r1]!"). | |
| 120 input += rgbaStep; | |
| 121 output += rgbStep; | |
| 122 } | |
| 123 | |
| 124 // Handle the tail elements. | |
| 125 unsigned remaining = pixelCount; | |
| 126 remaining -= counter; | |
| 127 if (remaining != 0) { | |
| 128 RGBAtoRGBScalar(input, remaining, output); | |
| 129 } | |
| 130 } | |
| 131 #endif | |
| 132 | |
| 48 struct JPEGOutputBuffer : public jpeg_destination_mgr { | 133 struct JPEGOutputBuffer : public jpeg_destination_mgr { |
| 49 DISALLOW_NEW(); | 134 DISALLOW_NEW(); |
| 50 Vector<unsigned char>* output; | 135 Vector<unsigned char>* output; |
| 51 Vector<unsigned char> buffer; | 136 Vector<unsigned char> buffer; |
| 52 }; | 137 }; |
| 53 | 138 |
| 54 class JPEGImageEncoderStateImpl final : public JPEGImageEncoderState { | 139 class JPEGImageEncoderStateImpl final : public JPEGImageEncoderState { |
| 55 public: | 140 public: |
| 56 JPEGImageEncoderStateImpl() {} | 141 JPEGImageEncoderStateImpl() {} |
| 57 ~JPEGImageEncoderStateImpl() override { | 142 ~JPEGImageEncoderStateImpl() override { |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 88 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); | 173 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); |
| 89 const size_t size = out->buffer.size() - out->free_in_buffer; | 174 const size_t size = out->buffer.size() - out->free_in_buffer; |
| 90 out->output->append(out->buffer.data(), size); | 175 out->output->append(out->buffer.data(), size); |
| 91 } | 176 } |
| 92 | 177 |
| 93 static void handleError(j_common_ptr common) { | 178 static void handleError(j_common_ptr common) { |
| 94 jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data); | 179 jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data); |
| 95 longjmp(*jumpBufferPtr, -1); | 180 longjmp(*jumpBufferPtr, -1); |
| 96 } | 181 } |
| 97 | 182 |
| 98 static void RGBAtoRGB(const unsigned char* pixels, | |
| 99 unsigned pixelCount, | |
| 100 unsigned char* output) { | |
| 101 // Per <canvas> spec, composite the input image pixels source-over on black. | |
| 102 | |
| 103 for (; pixelCount-- > 0; pixels += 4) { | |
| 104 unsigned char alpha = pixels[3]; | |
| 105 if (alpha != 255) { | |
| 106 *output++ = SkMulDiv255Round(pixels[0], alpha); | |
| 107 *output++ = SkMulDiv255Round(pixels[1], alpha); | |
| 108 *output++ = SkMulDiv255Round(pixels[2], alpha); | |
| 109 } else { | |
| 110 *output++ = pixels[0]; | |
| 111 *output++ = pixels[1]; | |
| 112 *output++ = pixels[2]; | |
| 113 } | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 static void disableSubsamplingForHighQuality(jpeg_compress_struct* cinfo, | 183 static void disableSubsamplingForHighQuality(jpeg_compress_struct* cinfo, |
| 118 int quality) { | 184 int quality) { |
| 119 if (quality < 100) | 185 if (quality < 100) |
| 120 return; | 186 return; |
| 121 | 187 |
| 122 for (int i = 0; i < MAX_COMPONENTS; ++i) { | 188 for (int i = 0; i < MAX_COMPONENTS; ++i) { |
| 123 cinfo->comp_info[i].h_samp_factor = 1; | 189 cinfo->comp_info[i].h_samp_factor = 1; |
| 124 cinfo->comp_info[i].v_samp_factor = 1; | 190 cinfo->comp_info[i].v_samp_factor = 1; |
| 125 } | 191 } |
| 126 } | 192 } |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 std::unique_ptr<JPEGImageEncoderState> encoderState = | 316 std::unique_ptr<JPEGImageEncoderState> encoderState = |
| 251 JPEGImageEncoderState::create(imageData.size(), quality, output); | 317 JPEGImageEncoderState::create(imageData.size(), quality, output); |
| 252 if (!encoderState) | 318 if (!encoderState) |
| 253 return false; | 319 return false; |
| 254 | 320 |
| 255 return JPEGImageEncoder::encodeWithPreInitializedState( | 321 return JPEGImageEncoder::encodeWithPreInitializedState( |
| 256 std::move(encoderState), imageData.pixels()); | 322 std::move(encoderState), imageData.pixels()); |
| 257 } | 323 } |
| 258 | 324 |
| 259 } // namespace blink | 325 } // namespace blink |
| OLD | NEW |