| 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 "SkImageDecoder.h" | 9 #include "SkImageDecoder.h" |
| 10 #include "SkImageEncoder.h" | 10 #include "SkImageEncoder.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include <stdio.h> | 25 #include <stdio.h> |
| 26 extern "C" { | 26 extern "C" { |
| 27 #include "jpeglib.h" | 27 #include "jpeglib.h" |
| 28 #include "jerror.h" | 28 #include "jerror.h" |
| 29 } | 29 } |
| 30 | 30 |
| 31 // These enable timing code that report milliseconds for an encoding/decoding | 31 // These enable timing code that report milliseconds for an encoding/decoding |
| 32 //#define TIME_ENCODE | 32 //#define TIME_ENCODE |
| 33 //#define TIME_DECODE | 33 //#define TIME_DECODE |
| 34 | 34 |
| 35 // this enables our rgb->yuv code, which is faster than libjpeg on ARM | |
| 36 #define WE_CONVERT_TO_YUV | |
| 37 | |
| 38 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer
s | 35 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offer
s |
| 39 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. | 36 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. |
| 40 | 37 |
| 41 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true | 38 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true |
| 42 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true | 39 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true |
| 43 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings, | 40 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings, |
| 44 "images.jpeg.suppressDecoderWarnings", | 41 "images.jpeg.suppressDecoderWarnings", |
| 45 DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS, | 42 DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS, |
| 46 "Suppress most JPG warnings when calling decode functions."); | 43 "Suppress most JPG warnings when calling decode functions."); |
| 47 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors, | 44 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors, |
| (...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 | 744 |
| 748 if (nullptr != colorSpace) { | 745 if (nullptr != colorSpace) { |
| 749 *colorSpace = kJPEG_SkYUVColorSpace; | 746 *colorSpace = kJPEG_SkYUVColorSpace; |
| 750 } | 747 } |
| 751 | 748 |
| 752 return true; | 749 return true; |
| 753 } | 750 } |
| 754 | 751 |
| 755 /////////////////////////////////////////////////////////////////////////////// | 752 /////////////////////////////////////////////////////////////////////////////// |
| 756 | 753 |
| 757 #include "SkColorPriv.h" | |
| 758 | |
| 759 // taken from jcolor.c in libjpeg | |
| 760 #if 0 // 16bit - precise but slow | |
| 761 #define CYR 19595 // 0.299 | |
| 762 #define CYG 38470 // 0.587 | |
| 763 #define CYB 7471 // 0.114 | |
| 764 | |
| 765 #define CUR -11059 // -0.16874 | |
| 766 #define CUG -21709 // -0.33126 | |
| 767 #define CUB 32768 // 0.5 | |
| 768 | |
| 769 #define CVR 32768 // 0.5 | |
| 770 #define CVG -27439 // -0.41869 | |
| 771 #define CVB -5329 // -0.08131 | |
| 772 | |
| 773 #define CSHIFT 16 | |
| 774 #else // 8bit - fast, slightly less precise | |
| 775 #define CYR 77 // 0.299 | |
| 776 #define CYG 150 // 0.587 | |
| 777 #define CYB 29 // 0.114 | |
| 778 | |
| 779 #define CUR -43 // -0.16874 | |
| 780 #define CUG -85 // -0.33126 | |
| 781 #define CUB 128 // 0.5 | |
| 782 | |
| 783 #define CVR 128 // 0.5 | |
| 784 #define CVG -107 // -0.41869 | |
| 785 #define CVB -21 // -0.08131 | |
| 786 | |
| 787 #define CSHIFT 8 | |
| 788 #endif | |
| 789 | |
| 790 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { | |
| 791 int r = SkGetPackedR32(c); | |
| 792 int g = SkGetPackedG32(c); | |
| 793 int b = SkGetPackedB32(c); | |
| 794 | |
| 795 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; | |
| 796 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; | |
| 797 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; | |
| 798 | |
| 799 dst[0] = SkToU8(y); | |
| 800 dst[1] = SkToU8(u + 128); | |
| 801 dst[2] = SkToU8(v + 128); | |
| 802 } | |
| 803 | |
| 804 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { | |
| 805 int r = SkGetPackedR4444(c); | |
| 806 int g = SkGetPackedG4444(c); | |
| 807 int b = SkGetPackedB4444(c); | |
| 808 | |
| 809 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); | |
| 810 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); | |
| 811 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); | |
| 812 | |
| 813 dst[0] = SkToU8(y); | |
| 814 dst[1] = SkToU8(u + 128); | |
| 815 dst[2] = SkToU8(v + 128); | |
| 816 } | |
| 817 | |
| 818 static void rgb2yuv_16(uint8_t dst[], U16CPU c) { | |
| 819 int r = SkGetPackedR16(c); | |
| 820 int g = SkGetPackedG16(c); | |
| 821 int b = SkGetPackedB16(c); | |
| 822 | |
| 823 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); | |
| 824 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); | |
| 825 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); | |
| 826 | |
| 827 dst[0] = SkToU8(y); | |
| 828 dst[1] = SkToU8(u + 128); | |
| 829 dst[2] = SkToU8(v + 128); | |
| 830 } | |
| 831 | |
| 832 /////////////////////////////////////////////////////////////////////////////// | |
| 833 | |
| 834 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, | 754 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, |
| 835 const void* SK_RESTRICT src, int width, | 755 const void* SK_RESTRICT src, int width, |
| 836 const SkPMColor* SK_RESTRICT ctable); | 756 const SkPMColor* SK_RESTRICT ctable); |
| 837 | 757 |
| 838 static void Write_32_YUV(uint8_t* SK_RESTRICT dst, | 758 static void Write_32_RGB(uint8_t* SK_RESTRICT dst, |
| 839 const void* SK_RESTRICT srcRow, int width, | 759 const void* SK_RESTRICT srcRow, int width, |
| 840 const SkPMColor*) { | 760 const SkPMColor*) { |
| 841 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; | 761 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; |
| 842 while (--width >= 0) { | 762 while (--width >= 0) { |
| 843 #ifdef WE_CONVERT_TO_YUV | |
| 844 rgb2yuv_32(dst, *src++); | |
| 845 #else | |
| 846 uint32_t c = *src++; | 763 uint32_t c = *src++; |
| 847 dst[0] = SkGetPackedR32(c); | 764 dst[0] = SkGetPackedR32(c); |
| 848 dst[1] = SkGetPackedG32(c); | 765 dst[1] = SkGetPackedG32(c); |
| 849 dst[2] = SkGetPackedB32(c); | 766 dst[2] = SkGetPackedB32(c); |
| 850 #endif | |
| 851 dst += 3; | 767 dst += 3; |
| 852 } | 768 } |
| 853 } | 769 } |
| 854 | 770 |
| 855 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, | 771 static void Write_4444_RGB(uint8_t* SK_RESTRICT dst, |
| 856 const void* SK_RESTRICT srcRow, int width, | 772 const void* SK_RESTRICT srcRow, int width, |
| 857 const SkPMColor*) { | 773 const SkPMColor*) { |
| 858 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; | 774 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; |
| 859 while (--width >= 0) { | 775 while (--width >= 0) { |
| 860 #ifdef WE_CONVERT_TO_YUV | |
| 861 rgb2yuv_4444(dst, *src++); | |
| 862 #else | |
| 863 SkPMColor16 c = *src++; | 776 SkPMColor16 c = *src++; |
| 864 dst[0] = SkPacked4444ToR32(c); | 777 dst[0] = SkPacked4444ToR32(c); |
| 865 dst[1] = SkPacked4444ToG32(c); | 778 dst[1] = SkPacked4444ToG32(c); |
| 866 dst[2] = SkPacked4444ToB32(c); | 779 dst[2] = SkPacked4444ToB32(c); |
| 867 #endif | |
| 868 dst += 3; | 780 dst += 3; |
| 869 } | 781 } |
| 870 } | 782 } |
| 871 | 783 |
| 872 static void Write_16_YUV(uint8_t* SK_RESTRICT dst, | 784 static void Write_16_RGB(uint8_t* SK_RESTRICT dst, |
| 873 const void* SK_RESTRICT srcRow, int width, | 785 const void* SK_RESTRICT srcRow, int width, |
| 874 const SkPMColor*) { | 786 const SkPMColor*) { |
| 875 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; | 787 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; |
| 876 while (--width >= 0) { | 788 while (--width >= 0) { |
| 877 #ifdef WE_CONVERT_TO_YUV | |
| 878 rgb2yuv_16(dst, *src++); | |
| 879 #else | |
| 880 uint16_t c = *src++; | 789 uint16_t c = *src++; |
| 881 dst[0] = SkPacked16ToR32(c); | 790 dst[0] = SkPacked16ToR32(c); |
| 882 dst[1] = SkPacked16ToG32(c); | 791 dst[1] = SkPacked16ToG32(c); |
| 883 dst[2] = SkPacked16ToB32(c); | 792 dst[2] = SkPacked16ToB32(c); |
| 884 #endif | |
| 885 dst += 3; | 793 dst += 3; |
| 886 } | 794 } |
| 887 } | 795 } |
| 888 | 796 |
| 889 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, | 797 static void Write_Index_RGB(uint8_t* SK_RESTRICT dst, |
| 890 const void* SK_RESTRICT srcRow, int width, | 798 const void* SK_RESTRICT srcRow, int width, |
| 891 const SkPMColor* SK_RESTRICT ctable) { | 799 const SkPMColor* SK_RESTRICT ctable) { |
| 892 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; | 800 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; |
| 893 while (--width >= 0) { | 801 while (--width >= 0) { |
| 894 #ifdef WE_CONVERT_TO_YUV | |
| 895 rgb2yuv_32(dst, ctable[*src++]); | |
| 896 #else | |
| 897 uint32_t c = ctable[*src++]; | 802 uint32_t c = ctable[*src++]; |
| 898 dst[0] = SkGetPackedR32(c); | 803 dst[0] = SkGetPackedR32(c); |
| 899 dst[1] = SkGetPackedG32(c); | 804 dst[1] = SkGetPackedG32(c); |
| 900 dst[2] = SkGetPackedB32(c); | 805 dst[2] = SkGetPackedB32(c); |
| 901 #endif | |
| 902 dst += 3; | 806 dst += 3; |
| 903 } | 807 } |
| 904 } | 808 } |
| 905 | 809 |
| 906 static WriteScanline ChooseWriter(const SkBitmap& bm) { | 810 static WriteScanline ChooseWriter(const SkBitmap& bm) { |
| 907 switch (bm.colorType()) { | 811 switch (bm.colorType()) { |
| 908 case kN32_SkColorType: | 812 case kN32_SkColorType: |
| 909 return Write_32_YUV; | 813 return Write_32_RGB; |
| 910 case kRGB_565_SkColorType: | 814 case kRGB_565_SkColorType: |
| 911 return Write_16_YUV; | 815 return Write_16_RGB; |
| 912 case kARGB_4444_SkColorType: | 816 case kARGB_4444_SkColorType: |
| 913 return Write_4444_YUV; | 817 return Write_4444_RGB; |
| 914 case kIndex_8_SkColorType: | 818 case kIndex_8_SkColorType: |
| 915 return Write_Index_YUV; | 819 return Write_Index_RGB; |
| 916 default: | 820 default: |
| 917 return nullptr; | 821 return nullptr; |
| 918 } | 822 } |
| 919 } | 823 } |
| 920 | 824 |
| 921 class SkJPEGImageEncoder : public SkImageEncoder { | 825 class SkJPEGImageEncoder : public SkImageEncoder { |
| 922 protected: | 826 protected: |
| 923 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { | 827 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { |
| 924 #ifdef TIME_ENCODE | 828 #ifdef TIME_ENCODE |
| 925 SkAutoTime atm("JPEG Encode"); | 829 SkAutoTime atm("JPEG Encode"); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 947 const WriteScanline writer = ChooseWriter(bm); | 851 const WriteScanline writer = ChooseWriter(bm); |
| 948 if (nullptr == writer) { | 852 if (nullptr == writer) { |
| 949 return false; | 853 return false; |
| 950 } | 854 } |
| 951 | 855 |
| 952 jpeg_create_compress(&cinfo); | 856 jpeg_create_compress(&cinfo); |
| 953 cinfo.dest = &sk_wstream; | 857 cinfo.dest = &sk_wstream; |
| 954 cinfo.image_width = bm.width(); | 858 cinfo.image_width = bm.width(); |
| 955 cinfo.image_height = bm.height(); | 859 cinfo.image_height = bm.height(); |
| 956 cinfo.input_components = 3; | 860 cinfo.input_components = 3; |
| 957 #ifdef WE_CONVERT_TO_YUV | 861 // FIXME: Can we take advantage of other in_color_spaces in libjpeg-turb
o? |
| 958 cinfo.in_color_space = JCS_YCbCr; | |
| 959 #else | |
| 960 cinfo.in_color_space = JCS_RGB; | 862 cinfo.in_color_space = JCS_RGB; |
| 961 #endif | 863 |
| 864 // The gamma value is ignored by libjpeg-turbo. |
| 962 cinfo.input_gamma = 1; | 865 cinfo.input_gamma = 1; |
| 963 | 866 |
| 964 jpeg_set_defaults(&cinfo); | 867 jpeg_set_defaults(&cinfo); |
| 868 |
| 869 // Tells libjpeg-turbo to compute optimal Huffman coding tables |
| 870 // for the image. This improves compression at the cost of |
| 871 // slower encode performance. |
| 965 cinfo.optimize_coding = TRUE; | 872 cinfo.optimize_coding = TRUE; |
| 966 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values
*/); | 873 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values
*/); |
| 967 #ifdef DCT_IFAST_SUPPORTED | |
| 968 cinfo.dct_method = JDCT_IFAST; | |
| 969 #endif | |
| 970 | 874 |
| 971 jpeg_start_compress(&cinfo, TRUE); | 875 jpeg_start_compress(&cinfo, TRUE); |
| 972 | 876 |
| 973 const int width = bm.width(); | 877 const int width = bm.width(); |
| 974 uint8_t* oneRowP = oneRow.reset(width * 3); | 878 uint8_t* oneRowP = oneRow.reset(width * 3); |
| 975 | 879 |
| 976 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC
olors() : nullptr; | 880 const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readC
olors() : nullptr; |
| 977 const void* srcRow = bm.getPixels(); | 881 const void* srcRow = bm.getPixels(); |
| 978 | 882 |
| 979 while (cinfo.next_scanline < cinfo.image_height) { | 883 while (cinfo.next_scanline < cinfo.image_height) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1028 return SkImageDecoder::kUnknown_Format; | 932 return SkImageDecoder::kUnknown_Format; |
| 1029 } | 933 } |
| 1030 | 934 |
| 1031 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 935 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { |
| 1032 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; | 936 return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; |
| 1033 } | 937 } |
| 1034 | 938 |
| 1035 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 939 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); |
| 1036 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 940 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); |
| 1037 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 941 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); |
| OLD | NEW |