| 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 void RGBAtoRGBNeon(const unsigned char* input, |
| 70 const unsigned pixelCount, |
| 71 unsigned char* output) { |
| 72 const unsigned pixelsPerLoad = 16; |
| 73 const unsigned rgbaStep = pixelsPerLoad * 4, rgbStep = pixelsPerLoad * 3; |
| 74 // Input registers. |
| 75 uint8x16x4_t rgba; |
| 76 // Output registers. |
| 77 uint8x16x3_t rgb; |
| 78 // Intermediate registers. |
| 79 uint8x8_t low, high; |
| 80 uint8x16_t result; |
| 81 unsigned counter; |
| 82 auto transformColor = [&](size_t channel) { |
| 83 // Extracts the low/high part of the 128 bits. |
| 84 low = vget_low_u8(rgba.val[channel]); |
| 85 high = vget_high_u8(rgba.val[channel]); |
| 86 // Scale the color and combine. |
| 87 uint16x8_t temp = vmull_u8(low, vget_low_u8(rgba.val[3])); |
| 88 low = vraddhn_u16(temp, vrshrq_n_u16(temp, 8)); |
| 89 temp = vmull_u8(high, vget_high_u8(rgba.val[3])); |
| 90 high = vraddhn_u16(temp, vrshrq_n_u16(temp, 8)); |
| 91 result = vcombine_u8(low, high); |
| 92 // Write back the channel to a 128 bits register. |
| 93 rgb.val[channel] = result; |
| 94 }; |
| 95 |
| 96 for (counter = 0; counter + pixelsPerLoad <= pixelCount; |
| 97 counter += pixelsPerLoad) { |
| 98 // Reads 16 pixels at once, each color channel in a different |
| 99 // 128 bits register. |
| 100 rgba = vld4q_u8(input); |
| 101 |
| 102 transformColor(0); |
| 103 transformColor(1); |
| 104 transformColor(2); |
| 105 |
| 106 // Write back (interleaved) results to output. |
| 107 vst3q_u8(output, rgb); |
| 108 |
| 109 // Advance to next elements (could be avoided loading register with |
| 110 // increment after i.e. "vld4 {vector}, [r1]!"). |
| 111 input += rgbaStep; |
| 112 output += rgbStep; |
| 113 } |
| 114 |
| 115 // Handle the tail elements. |
| 116 unsigned remaining = pixelCount; |
| 117 remaining -= counter; |
| 118 if (remaining != 0) { |
| 119 RGBAtoRGBScalar(input, remaining, output); |
| 120 } |
| 121 } |
| 122 #endif |
| 123 |
| 48 struct JPEGOutputBuffer : public jpeg_destination_mgr { | 124 struct JPEGOutputBuffer : public jpeg_destination_mgr { |
| 49 DISALLOW_NEW(); | 125 DISALLOW_NEW(); |
| 50 Vector<unsigned char>* output; | 126 Vector<unsigned char>* output; |
| 51 Vector<unsigned char> buffer; | 127 Vector<unsigned char> buffer; |
| 52 }; | 128 }; |
| 53 | 129 |
| 54 class JPEGImageEncoderStateImpl final : public JPEGImageEncoderState { | 130 class JPEGImageEncoderStateImpl final : public JPEGImageEncoderState { |
| 55 public: | 131 public: |
| 56 JPEGImageEncoderStateImpl() {} | 132 JPEGImageEncoderStateImpl() {} |
| 57 ~JPEGImageEncoderStateImpl() override { | 133 ~JPEGImageEncoderStateImpl() override { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 88 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); | 164 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); |
| 89 const size_t size = out->buffer.size() - out->free_in_buffer; | 165 const size_t size = out->buffer.size() - out->free_in_buffer; |
| 90 out->output->append(out->buffer.data(), size); | 166 out->output->append(out->buffer.data(), size); |
| 91 } | 167 } |
| 92 | 168 |
| 93 static void handleError(j_common_ptr common) { | 169 static void handleError(j_common_ptr common) { |
| 94 jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data); | 170 jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data); |
| 95 longjmp(*jumpBufferPtr, -1); | 171 longjmp(*jumpBufferPtr, -1); |
| 96 } | 172 } |
| 97 | 173 |
| 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, | 174 static void disableSubsamplingForHighQuality(jpeg_compress_struct* cinfo, |
| 118 int quality) { | 175 int quality) { |
| 119 if (quality < 100) | 176 if (quality < 100) |
| 120 return; | 177 return; |
| 121 | 178 |
| 122 for (int i = 0; i < MAX_COMPONENTS; ++i) { | 179 for (int i = 0; i < MAX_COMPONENTS; ++i) { |
| 123 cinfo->comp_info[i].h_samp_factor = 1; | 180 cinfo->comp_info[i].h_samp_factor = 1; |
| 124 cinfo->comp_info[i].v_samp_factor = 1; | 181 cinfo->comp_info[i].v_samp_factor = 1; |
| 125 } | 182 } |
| 126 } | 183 } |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 std::unique_ptr<JPEGImageEncoderState> encoderState = | 307 std::unique_ptr<JPEGImageEncoderState> encoderState = |
| 251 JPEGImageEncoderState::create(imageData.size(), quality, output); | 308 JPEGImageEncoderState::create(imageData.size(), quality, output); |
| 252 if (!encoderState) | 309 if (!encoderState) |
| 253 return false; | 310 return false; |
| 254 | 311 |
| 255 return JPEGImageEncoder::encodeWithPreInitializedState( | 312 return JPEGImageEncoder::encodeWithPreInitializedState( |
| 256 std::move(encoderState), imageData.pixels()); | 313 std::move(encoderState), imageData.pixels()); |
| 257 } | 314 } |
| 258 | 315 |
| 259 } // namespace blink | 316 } // namespace blink |
| OLD | NEW |