Changeset 147048 in webkit


Ignore:
Timestamp:
Mar 27, 2013 8:04:45 PM (11 years ago)
Author:
noel.gordon@gmail.com
Message:

Add webp image color profile support
https://bugs.webkit.org/show_bug.cgi?id=113184

Reviewed by Eric Seidel.

Source/WebCore:

Requires libwebp version 0.3.0 (decoder ABI version 0x201). For images
with an ICC color profile chunk, poll the incremental decoder for the
current decoded height with the WebPIDecGetRGB() API and color correct
any newly decoded rows in-situ in the frame buffer.

Note: the ICC chunk appears before the encoded image frame in the webp
encoding (RIFF container) format. When the incremental decoder outputs
decoded pixels, enough encoded data has arrived to read the entire ICC
color profile data chunk.

Tests: fast/images/webp-color-profile-lossless.html

fast/images/webp-color-profile-lossy-alpha.html
fast/images/webp-color-profile-lossy.html

  • platform/image-decoders/webp/WEBPImageDecoder.cpp:

(WebCore::WEBPImageDecoder::WEBPImageDecoder):
(WebCore::WEBPImageDecoder::~WEBPImageDecoder): Call clear().
(WebCore):
(WebCore::WEBPImageDecoder::clear):
Added. Helper to clean up the webp decoder and color transform members.
(WebCore::WEBPImageDecoder::createColorTransform):
Create m_transform using the supplied profile memory data. Note that
the |deviceProfile| is not owned, but the |inputProfile| temporary is
so release it here with qcms_release_profile().
(WebCore::WEBPImageDecoder::readColorProfile):
Called once only when the decoder begins to output decoded rows of an
image containing an ICC chunk, to read the ICC color profile data from
the encoded data stream, verify it, and use it to create m_transform.
(WebCore::WEBPImageDecoder::applyColorProfile):
Since there is no row callback in libwebp, poll for the decoded height
of the image so far. If new rows are decoded, color correct the pixels
of those new rows and re-write them back into the frame buffer using
buffer.setRGBA() to 1) alpha pre-multiply the pixels if needed, and 2)
shuffle the pixel bytes into the platform's RGBA pixel endian-ness.
(WebCore::WEBPImageDecoder::decode):
If the container format indicates the image has an ICC color profile,
decode the image to RGBA format for subsequent input to the QCMS color
correction library in applyColorProfile().

  • platform/image-decoders/webp/WEBPImageDecoder.h:

(WEBPImageDecoder):
(WebCore::WEBPImageDecoder::colorTransform): m_transform getter.

LayoutTests:

  • fast/images/resources/webp-color-profile-lossless.webp: Added.
  • fast/images/resources/webp-color-profile-lossy-alpha.webp: Added.
  • fast/images/resources/webp-color-profile-lossy.webp: Added.
  • fast/images/webp-color-profile-lossless-expected.txt: Added.
  • fast/images/webp-color-profile-lossless.html: Added.
  • fast/images/webp-color-profile-lossy-alpha-expected.txt: Added.
  • fast/images/webp-color-profile-lossy-alpha.html: Added.
  • fast/images/webp-color-profile-lossy-expected.txt: Added.
  • fast/images/webp-color-profile-lossy.html: Added.
  • platform/chromium-mac/fast/images/webp-color-profile-lossless-expected.png: Added.
  • platform/chromium-mac/fast/images/webp-color-profile-lossy-alpha-expected.png: Added.
  • platform/chromium-mac/fast/images/webp-color-profile-lossy-expected.png: Added.
  • platform/chromium-win/fast/images/webp-color-profile-lossless-expected.png: Added.
  • platform/chromium-win/fast/images/webp-color-profile-lossy-alpha-expected.png: Added.
  • platform/chromium-win/fast/images/webp-color-profile-lossy-expected.png: Added.
  • platform/efl/TestExpectations:
  • platform/gtk/TestExpectations:
  • platform/mac/TestExpectations:
  • platform/qt/TestExpectations:
  • platform/win/TestExpectations:
  • platform/wincairo/TestExpectations:
Location:
trunk
Files:
15 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r147047 r147048  
     12013-03-27  Noel Gordon  <noel.gordon@gmail.com>
     2
     3        Add webp image color profile support
     4        https://bugs.webkit.org/show_bug.cgi?id=113184
     5
     6        Reviewed by Eric Seidel.
     7
     8        * fast/images/resources/webp-color-profile-lossless.webp: Added.
     9        * fast/images/resources/webp-color-profile-lossy-alpha.webp: Added.
     10        * fast/images/resources/webp-color-profile-lossy.webp: Added.
     11        * fast/images/webp-color-profile-lossless-expected.txt: Added.
     12        * fast/images/webp-color-profile-lossless.html: Added.
     13        * fast/images/webp-color-profile-lossy-alpha-expected.txt: Added.
     14        * fast/images/webp-color-profile-lossy-alpha.html: Added.
     15        * fast/images/webp-color-profile-lossy-expected.txt: Added.
     16        * fast/images/webp-color-profile-lossy.html: Added.
     17        * platform/chromium-mac/fast/images/webp-color-profile-lossless-expected.png: Added.
     18        * platform/chromium-mac/fast/images/webp-color-profile-lossy-alpha-expected.png: Added.
     19        * platform/chromium-mac/fast/images/webp-color-profile-lossy-expected.png: Added.
     20        * platform/chromium-win/fast/images/webp-color-profile-lossless-expected.png: Added.
     21        * platform/chromium-win/fast/images/webp-color-profile-lossy-alpha-expected.png: Added.
     22        * platform/chromium-win/fast/images/webp-color-profile-lossy-expected.png: Added.
     23        * platform/efl/TestExpectations:
     24        * platform/gtk/TestExpectations:
     25        * platform/mac/TestExpectations:
     26        * platform/qt/TestExpectations:
     27        * platform/win/TestExpectations:
     28        * platform/wincairo/TestExpectations:
     29
    1302013-03-27  Filip Pizlo  <fpizlo@apple.com>
    231
  • trunk/LayoutTests/platform/efl/TestExpectations

    r147022 r147048  
    11871187Bug(EFL) fast/canvas/canvas-toDataURL-webp.html
    11881188Bug(EFL) fast/images/webp-image-decoding.html
     1189Bug(EFL) fast/images/webp-color-profile-lossless.html
     1190Bug(EFL) fast/images/webp-color-profile-lossy-alpha.html
     1191Bug(EFL) fast/images/webp-color-profile-lossy.html
    11891192Bug(EFL) http/tests/images/webp-partial-load.html
    11901193Bug(EFL) http/tests/images/webp-progressive-load.html
  • trunk/LayoutTests/platform/gtk/TestExpectations

    r147022 r147048  
    208208# Requires WebP 0.2 support.
    209209webkit.org/b/98939 fast/images/webp-image-decoding.html [ Skip ]
     210# Requires WebP 0.3 and color profile support.
     211webkit.org/b/98939 fast/images/webp-color-profile-lossless.html [ Skip ]
     212webkit.org/b/98939 fast/images/webp-color-profile-lossy-alpha.html [ Skip ]
     213webkit.org/b/98939 fast/images/webp-color-profile-lossy.html [ Skip ]
    210214
    211215# DataTransferItems is not yet implemented.
  • trunk/LayoutTests/platform/mac/TestExpectations

    r147001 r147048  
    355355fast/canvas/canvas-toDataURL-webp.html
    356356fast/images/webp-image-decoding.html
     357fast/images/webp-color-profile-lossless.html
     358fast/images/webp-color-profile-lossy-alpha.html
     359fast/images/webp-color-profile-lossy.html
    357360http/tests/images/webp-partial-load.html
    358361http/tests/images/webp-progressive-load.html
  • trunk/LayoutTests/platform/qt/TestExpectations

    r147022 r147048  
    18111811fast/canvas/canvas-toDataURL-webp.html
    18121812fast/images/webp-image-decoding.html
     1813fast/images/webp-color-profile-lossless.html
     1814fast/images/webp-color-profile-lossy-alpha.html
     1815fast/images/webp-color-profile-lossy.html
    18131816http/tests/images/webp-partial-load.html
    18141817http/tests/images/webp-progressive-load.html
  • trunk/LayoutTests/platform/win/TestExpectations

    r147022 r147048  
    13571357fast/canvas/canvas-toDataURL-webp.html
    13581358fast/images/webp-image-decoding.html
     1359fast/images/webp-color-profile-lossless.html
     1360fast/images/webp-color-profile-lossy-alpha.html
     1361fast/images/webp-color-profile-lossy.html
    13591362http/tests/images/webp-partial-load.html
    13601363http/tests/images/webp-progressive-load.html
  • trunk/LayoutTests/platform/wincairo/TestExpectations

    r147022 r147048  
    18771877fast/canvas/canvas-toDataURL-webp.html
    18781878fast/images/webp-image-decoding.html
     1879fast/images/webp-color-profile-lossless.html
     1880fast/images/webp-color-profile-lossy-alpha.html
     1881fast/images/webp-color-profile-lossy.html
    18791882http/tests/images/webp-partial-load.html
    18801883http/tests/images/webp-progressive-load.html
  • trunk/Source/WebCore/ChangeLog

    r147042 r147048  
     12013-03-27  Noel Gordon  <noel.gordon@gmail.com>
     2
     3        Add webp image color profile support
     4        https://bugs.webkit.org/show_bug.cgi?id=113184
     5
     6        Reviewed by Eric Seidel.
     7
     8        Requires libwebp version 0.3.0 (decoder ABI version 0x201). For images
     9        with an ICC color profile chunk, poll the incremental decoder for the
     10        current decoded height with the WebPIDecGetRGB() API and color correct
     11        any newly decoded rows in-situ in the frame buffer.
     12
     13        Note: the ICC chunk appears before the encoded image frame in the webp
     14        encoding (RIFF container) format. When the incremental decoder outputs
     15        decoded pixels, enough encoded data has arrived to read the entire ICC
     16        color profile data chunk.
     17
     18        Tests: fast/images/webp-color-profile-lossless.html
     19               fast/images/webp-color-profile-lossy-alpha.html
     20               fast/images/webp-color-profile-lossy.html
     21
     22        * platform/image-decoders/webp/WEBPImageDecoder.cpp:
     23        (WebCore::WEBPImageDecoder::WEBPImageDecoder):
     24        (WebCore::WEBPImageDecoder::~WEBPImageDecoder): Call clear().
     25        (WebCore):
     26        (WebCore::WEBPImageDecoder::clear):
     27        Added. Helper to clean up the webp decoder and color transform members.
     28        (WebCore::WEBPImageDecoder::createColorTransform):
     29        Create m_transform using the supplied profile memory data. Note that
     30        the |deviceProfile| is not owned, but the |inputProfile| temporary is
     31        so release it here with qcms_release_profile().
     32        (WebCore::WEBPImageDecoder::readColorProfile):
     33        Called once only when the decoder begins to output decoded rows of an
     34        image containing an ICC chunk, to read the ICC color profile data from
     35        the encoded data stream, verify it, and use it to create m_transform.
     36        (WebCore::WEBPImageDecoder::applyColorProfile):
     37        Since there is no row callback in libwebp, poll for the decoded height
     38        of the image so far. If new rows are decoded, color correct the pixels
     39        of those new rows and re-write them back into the frame buffer using
     40        buffer.setRGBA() to 1) alpha pre-multiply the pixels if needed, and 2)
     41        shuffle the pixel bytes into the platform's RGBA pixel endian-ness.
     42        (WebCore::WEBPImageDecoder::decode):
     43        If the container format indicates the image has an ICC color profile,
     44        decode the image to RGBA format for subsequent input to the QCMS color
     45        correction library in applyColorProfile().
     46        * platform/image-decoders/webp/WEBPImageDecoder.h:
     47        (WEBPImageDecoder):
     48        (WebCore::WEBPImageDecoder::colorTransform): m_transform getter.
     49
    1502013-03-27  Jun Jiang  <jun.a.jiang@intel.com>
    251
  • trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp

    r125869 r147048  
    3333
    3434#include "PlatformInstrumentation.h"
    35 #include "webp/decode.h"
    36 
    37 // backward emulation for earlier versions than 0.1.99
     35
     36#ifdef QCMS_WEBP_COLOR_CORRECTION
     37#include "qcms.h"
     38#include "webp/demux.h"
     39#else
     40#undef ICCP_FLAG
     41#define ICCP_FLAG 0
     42#endif
     43
     44// Backward emulation for earlier versions than 0.1.99.
    3845#if (WEBP_DECODER_ABI_VERSION < 0x0163)
    3946#define MODE_rgbA MODE_RGBA
     
    5663    , m_decoder(0)
    5764    , m_hasAlpha(false)
     65    , m_formatFlags(0)
     66#ifdef QCMS_WEBP_COLOR_CORRECTION
     67    , m_haveReadProfile(false)
     68    , m_transform(0)
     69    , m_decodedHeight(0)
     70#endif
    5871{
    5972}
     
    6174WEBPImageDecoder::~WEBPImageDecoder()
    6275{
     76    clear();
     77}
     78
     79void WEBPImageDecoder::clear()
     80{
     81#ifdef QCMS_WEBP_COLOR_CORRECTION
     82    if (m_transform)
     83        qcms_transform_release(m_transform);
     84    m_transform = 0;
     85#endif
    6386    if (m_decoder)
    6487        WebPIDelete(m_decoder);
     
    93116}
    94117
     118#ifdef QCMS_WEBP_COLOR_CORRECTION
     119
     120void WEBPImageDecoder::createColorTransform(const char* data, size_t size)
     121{
     122    if (m_transform)
     123        qcms_transform_release(m_transform);
     124    m_transform = 0;
     125
     126    qcms_profile* deviceProfile = ImageDecoder::qcmsOutputDeviceProfile();
     127    if (!deviceProfile)
     128        return;
     129    qcms_profile* inputProfile = qcms_profile_from_memory(data, size);
     130    if (!inputProfile)
     131        return;
     132
     133    // We currently only support color profiles for RGB profiled images.
     134    ASSERT(icSigRgbData == qcms_profile_get_color_space(inputProfile));
     135    // The input image pixels are RGBA format.
     136    qcms_data_type format = QCMS_DATA_RGBA_8;
     137    // FIXME: Don't force perceptual intent if the image profile contains an intent.
     138    m_transform = qcms_transform_create(inputProfile, format, deviceProfile, QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL);
     139
     140    qcms_profile_release(inputProfile);
     141}
     142
     143void WEBPImageDecoder::readColorProfile(const uint8_t* data, size_t size)
     144{
     145    WebPChunkIterator chunkIterator;
     146    WebPData inputData = { data, size };
     147    WebPDemuxState state;
     148
     149    WebPDemuxer* demuxer = WebPDemuxPartial(&inputData, &state);
     150    if (!WebPDemuxGetChunk(demuxer, "ICCP", 1, &chunkIterator)) {
     151        WebPDemuxReleaseChunkIterator(&chunkIterator);
     152        WebPDemuxDelete(demuxer);
     153        return;
     154    }
     155
     156    const char* profileData = reinterpret_cast<const char*>(chunkIterator.chunk.bytes);
     157    size_t profileSize = chunkIterator.chunk.size;
     158
     159    // Only accept RGB color profiles from input class devices.
     160    bool ignoreProfile = false;
     161    if (profileSize < ImageDecoder::iccColorProfileHeaderLength)
     162        ignoreProfile = true;
     163    else if (!ImageDecoder::rgbColorProfile(profileData, profileSize))
     164        ignoreProfile = true;
     165    else if (!ImageDecoder::inputDeviceColorProfile(profileData, profileSize))
     166        ignoreProfile = true;
     167
     168    if (!ignoreProfile)
     169        createColorTransform(profileData, profileSize);
     170
     171    WebPDemuxReleaseChunkIterator(&chunkIterator);
     172    WebPDemuxDelete(demuxer);
     173}
     174
     175void WEBPImageDecoder::applyColorProfile(const uint8_t* data, size_t size, ImageFrame& buffer)
     176{
     177    int width;
     178    int decodedHeight;
     179    if (!WebPIDecGetRGB(m_decoder, &decodedHeight, &width, 0, 0))
     180        return; // See also https://bugs.webkit.org/show_bug.cgi?id=74062
     181    if (decodedHeight <= 0)
     182        return;
     183
     184    if (!m_haveReadProfile) {
     185        readColorProfile(data, size);
     186        m_haveReadProfile = true;
     187    }
     188
     189    ASSERT(width == scaledSize().width());
     190    ASSERT(decodedHeight <= scaledSize().height());
     191
     192    for (int y = m_decodedHeight; y < decodedHeight; ++y) {
     193        uint8_t* row = reinterpret_cast<uint8_t*>(buffer.getAddr(0, y));
     194        if (qcms_transform* transform = colorTransform())
     195            qcms_transform_data_type(transform, row, row, width, QCMS_OUTPUT_RGBX);
     196        uint8_t* pixel = row;
     197        for (int x = 0; x < width; ++x, pixel += 4)
     198            buffer.setRGBA(x, y, pixel[0], pixel[1], pixel[2], pixel[3]);
     199    }
     200
     201    m_decodedHeight = decodedHeight;
     202}
     203
     204#endif // QCMS_WEBP_COLOR_CORRECTION
     205
    95206bool WEBPImageDecoder::decode(bool onlySize)
    96207{
     
    106217            return false;
    107218        int width, height;
    108 #if (WEBP_DECODER_ABI_VERSION >= 0x0163)
     219#ifdef QCMS_WEBP_COLOR_CORRECTION
     220        WebPData inputData = { dataBytes, dataSize };
     221        WebPDemuxState state;
     222        WebPDemuxer* demuxer = WebPDemuxPartial(&inputData, &state);
     223        if (!demuxer)
     224            return setFailed();
     225
     226        width = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH);
     227        height = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT);
     228        m_formatFlags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS);
     229        m_hasAlpha = !!(m_formatFlags & ALPHA_FLAG);
     230
     231        WebPDemuxDelete(demuxer);
     232        if (state <= WEBP_DEMUX_PARSING_HEADER)
     233            return false;
     234#elif (WEBP_DECODER_ABI_VERSION >= 0x0163)
    109235        WebPBitstreamFeatures features;
    110236        if (WebPGetFeatures(dataBytes, dataSize, &features) != VP8_STATUS_OK)
     
    140266
    141267    if (!m_decoder) {
     268        WEBP_CSP_MODE mode = outputMode(m_hasAlpha);
     269        if (!m_premultiplyAlpha)
     270            mode = outputMode(false);
     271        if ((m_formatFlags & ICCP_FLAG) && !ignoresGammaAndColorProfile())
     272            mode = MODE_RGBA; // Decode to RGBA for input to libqcms.
    142273        int rowStride = size().width() * sizeof(ImageFrame::PixelData);
    143274        uint8_t* output = reinterpret_cast<uint8_t*>(buffer.getAddr(0, 0));
    144275        int outputSize = size().height() * rowStride;
    145         m_decoder = WebPINewRGB(outputMode(m_hasAlpha), output, outputSize, rowStride);
     276        m_decoder = WebPINewRGB(mode, output, outputSize, rowStride);
    146277        if (!m_decoder)
    147278            return setFailed();
     
    150281    switch (WebPIUpdate(m_decoder, dataBytes, dataSize)) {
    151282    case VP8_STATUS_OK:
     283        if ((m_formatFlags & ICCP_FLAG) && !ignoresGammaAndColorProfile())
     284            applyColorProfile(dataBytes, dataSize, buffer);
    152285        buffer.setStatus(ImageFrame::FrameComplete);
    153         WebPIDelete(m_decoder);
    154         m_decoder = 0;
     286        clear();
    155287        return true;
    156288    case VP8_STATUS_SUSPENDED:
     289        if ((m_formatFlags & ICCP_FLAG) && !ignoresGammaAndColorProfile())
     290            applyColorProfile(dataBytes, dataSize, buffer);
    157291        return false;
    158292    default:
    159         WebPIDelete(m_decoder);
    160         m_decoder = 0;
     293        clear();                         
    161294        return setFailed();
    162295    }
  • trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.h

    r125869 r147048  
    3434#if USE(WEBP)
    3535
    36 typedef struct WebPIDecoder WebPIDecoder;
     36#include "webp/decode.h"
     37#if USE(QCMSLIB) && (WEBP_DECODER_ABI_VERSION > 0x200)
     38#define QCMS_WEBP_COLOR_CORRECTION
     39#endif
    3740
    3841namespace WebCore {
     
    5255    WebPIDecoder* m_decoder;
    5356    bool m_hasAlpha;
     57    int m_formatFlags;
     58
     59#ifdef QCMS_WEBP_COLOR_CORRECTION
     60    qcms_transform* colorTransform() const { return m_transform; }
     61    void createColorTransform(const char* data, size_t);
     62    void readColorProfile(const uint8_t* data, size_t);
     63    void applyColorProfile(const uint8_t* data, size_t, ImageFrame&);
     64
     65    bool m_haveReadProfile;
     66    qcms_transform* m_transform;
     67    int m_decodedHeight;
     68#else
     69    void applyColorProfile(const uint8_t*, size_t, ImageFrame&) { };
     70#endif
     71    void clear();
    5472};
    5573
Note: See TracChangeset for help on using the changeset viewer.