/*
* Copyright 2019 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/core/SkYUVMath.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkM44.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkDebug.h"
#include <cstring>
// in SkColorMatrix order (row-major)
// Created by running SkColorMatrix_DumpYUVMatrixTables()
const float JPEG_full_rgb_to_yuv[] = {
0 .299000 f, 0 .587000 f, 0 .114000 f, 0 .000000 f, 0 .000000 f,
-0 .168736 f, -0 .331264 f, 0 .500000 f, 0 .000000 f, 0 .501961 f,
0 .500000 f, -0 .418688 f, -0 .081312 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float JPEG_full_yuv_to_rgb[] = {
1 .000000 f, -0 .000000 f, 1 .402000 f, 0 .000000 f, -0 .703749 f,
1 .000000 f, -0 .344136 f, -0 .714136 f, 0 .000000 f, 0 .531211 f,
1 .000000 f, 1 .772000 f, 0 .000000 f, 0 .000000 f, -0 .889475 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float Rec601_limited_rgb_to_yuv[] = {
0 .256788 f, 0 .504129 f, 0 .097906 f, 0 .000000 f, 0 .062745 f,
-0 .148223 f, -0 .290993 f, 0 .439216 f, 0 .000000 f, 0 .501961 f,
0 .439216 f, -0 .367788 f, -0 .071427 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float Rec601_limited_yuv_to_rgb[] = {
1 .164384 f, -0 .000000 f, 1 .596027 f, 0 .000000 f, -0 .874202 f,
1 .164384 f, -0 .391762 f, -0 .812968 f, 0 .000000 f, 0 .531668 f,
1 .164384 f, 2 .017232 f, 0 .000000 f, 0 .000000 f, -1 .085631 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float Rec709_full_rgb_to_yuv[] = {
0 .212600 f, 0 .715200 f, 0 .072200 f, 0 .000000 f, 0 .000000 f,
-0 .114572 f, -0 .385428 f, 0 .500000 f, 0 .000000 f, 0 .501961 f,
0 .500000 f, -0 .454153 f, -0 .045847 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float Rec709_full_yuv_to_rgb[] = {
1 .000000 f, -0 .000000 f, 1 .574800 f, 0 .000000 f, -0 .790488 f,
1 .000000 f, -0 .187324 f, -0 .468124 f, 0 .000000 f, 0 .329010 f,
1 .000000 f, 1 .855600 f, -0 .000000 f, 0 .000000 f, -0 .931439 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float Rec709_limited_rgb_to_yuv[] = {
0 .182586 f, 0 .614231 f, 0 .062007 f, 0 .000000 f, 0 .062745 f,
-0 .100644 f, -0 .338572 f, 0 .439216 f, 0 .000000 f, 0 .501961 f,
0 .439216 f, -0 .398942 f, -0 .040274 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float Rec709_limited_yuv_to_rgb[] = {
1 .164384 f, -0 .000000 f, 1 .792741 f, 0 .000000 f, -0 .972945 f,
1 .164384 f, -0 .213249 f, -0 .532909 f, 0 .000000 f, 0 .301483 f,
1 .164384 f, 2 .112402 f, -0 .000000 f, 0 .000000 f, -1 .133402 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_8bit_full_rgb_to_yuv[] = {
0 .262700 f, 0 .678000 f, 0 .059300 f, 0 .000000 f, 0 .000000 f,
-0 .139630 f, -0 .360370 f, 0 .500000 f, 0 .000000 f, 0 .501961 f,
0 .500000 f, -0 .459786 f, -0 .040214 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_8bit_full_yuv_to_rgb[] = {
1 .000000 f, -0 .000000 f, 1 .474600 f, 0 .000000 f, -0 .740191 f,
1 .000000 f, -0 .164553 f, -0 .571353 f, 0 .000000 f, 0 .369396 f,
1 .000000 f, 1 .881400 f, -0 .000000 f, 0 .000000 f, -0 .944389 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_8bit_limited_rgb_to_yuv[] = {
0 .225613 f, 0 .582282 f, 0 .050928 f, 0 .000000 f, 0 .062745 f,
-0 .122655 f, -0 .316560 f, 0 .439216 f, 0 .000000 f, 0 .501961 f,
0 .439216 f, -0 .403890 f, -0 .035326 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_8bit_limited_yuv_to_rgb[] = {
1 .164384 f, -0 .000000 f, 1 .678674 f, 0 .000000 f, -0 .915688 f,
1 .164384 f, -0 .187326 f, -0 .650424 f, 0 .000000 f, 0 .347458 f,
1 .164384 f, 2 .141772 f, -0 .000000 f, 0 .000000 f, -1 .148145 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_10bit_full_rgb_to_yuv[] = {
0 .262700 f, 0 .678000 f, 0 .059300 f, 0 .000000 f, 0 .000000 f,
-0 .139630 f, -0 .360370 f, 0 .500000 f, 0 .000000 f, 0 .500489 f,
0 .500000 f, -0 .459786 f, -0 .040214 f, 0 .000000 f, 0 .500489 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_10bit_full_yuv_to_rgb[] = {
1 .000000 f, -0 .000000 f, 1 .474600 f, 0 .000000 f, -0 .738021 f,
1 .000000 f, -0 .164553 f, -0 .571353 f, 0 .000000 f, 0 .368313 f,
1 .000000 f, 1 .881400 f, -0 .000000 f, 0 .000000 f, -0 .941620 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_10bit_limited_rgb_to_yuv[] = {
0 .224951 f, 0 .580575 f, 0 .050779 f, 0 .000000 f, 0 .062561 f,
-0 .122296 f, -0 .315632 f, 0 .437928 f, 0 .000000 f, 0 .500489 f,
0 .437928 f, -0 .402706 f, -0 .035222 f, 0 .000000 f, 0 .500489 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_10bit_limited_yuv_to_rgb[] = {
1 .167808 f, -0 .000000 f, 1 .683611 f, 0 .000000 f, -0 .915688 f,
1 .167808 f, -0 .187877 f, -0 .652337 f, 0 .000000 f, 0 .347458 f,
1 .167808 f, 2 .148072 f, -0 .000000 f, 0 .000000 f, -1 .148145 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_12bit_full_rgb_to_yuv[] = {
0 .262700 f, 0 .678000 f, 0 .059300 f, 0 .000000 f, 0 .000000 f,
-0 .139630 f, -0 .360370 f, 0 .500000 f, 0 .000000 f, 0 .500122 f,
0 .500000 f, -0 .459786 f, -0 .040214 f, 0 .000000 f, 0 .500122 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_12bit_full_yuv_to_rgb[] = {
1 .000000 f, -0 .000000 f, 1 .474600 f, 0 .000000 f, -0 .737480 f,
1 .000000 f, -0 .164553 f, -0 .571353 f, 0 .000000 f, 0 .368043 f,
1 .000000 f, 1 .881400 f, -0 .000000 f, 0 .000000 f, -0 .940930 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_12bit_limited_rgb_to_yuv[] = {
0 .224787 f, 0 .580149 f, 0 .050742 f, 0 .000000 f, 0 .062515 f,
-0 .122206 f, -0 .315401 f, 0 .437607 f, 0 .000000 f, 0 .500122 f,
0 .437607 f, -0 .402411 f, -0 .035196 f, 0 .000000 f, 0 .500122 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_12bit_limited_yuv_to_rgb[] = {
1 .168664 f, -0 .000000 f, 1 .684846 f, 0 .000000 f, -0 .915688 f,
1 .168664 f, -0 .188015 f, -0 .652816 f, 0 .000000 f, 0 .347458 f,
1 .168664 f, 2 .149647 f, -0 .000000 f, 0 .000000 f, -1 .148145 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_16bit_full_rgb_to_yuv[] = {
0 .262700 f, 0 .678000 f, 0 .059300 f, 0 .000000 f, 0 .000000 f,
-0 .139630 f, -0 .360370 f, 0 .500000 f, 0 .000000 f, 0 .500008 f,
0 .500000 f, -0 .459786 f, -0 .040214 f, 0 .000000 f, 0 .500008 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_16bit_full_yuv_to_rgb[] = {
1 .000000 f, -0 .000000 f, 1 .474600 f, 0 .000000 f, -0 .737311 f,
1 .000000 f, -0 .164553 f, -0 .571353 f, 0 .000000 f, 0 .367959 f,
1 .000000 f, 1 .881400 f, -0 .000000 f, 0 .000000 f, -0 .940714 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_16bit_limited_rgb_to_yuv[] = {
0 .224735 f, 0 .580017 f, 0 .050730 f, 0 .000000 f, 0 .062501 f,
-0 .122178 f, -0 .315329 f, 0 .437507 f, 0 .000000 f, 0 .500008 f,
0 .437507 f, -0 .402319 f, -0 .035188 f, 0 .000000 f, 0 .500008 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float BT2020_16bit_limited_yuv_to_rgb[] = {
1 .168932 f, 0 .000000 f, 1 .685231 f, 0 .000000 f, -0 .915688 f,
1 .168932 f, -0 .188058 f, -0 .652965 f, 0 .000000 f, 0 .347458 f,
1 .168932 f, 2 .150139 f, -0 .000000 f, 0 .000000 f, -1 .148145 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float FCC_full_rgb_to_yuv[] = {
0 .300000 f, 0 .590000 f, 0 .110000 f, 0 .000000 f, 0 .000000 f,
-0 .168539 f, -0 .331461 f, 0 .500000 f, 0 .000000 f, 0 .501961 f,
0 .500000 f, -0 .421429 f, -0 .078571 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float FCC_full_yuv_to_rgb[] = {
1 .000000 f, 0 .000000 f, 1 .400000 f, 0 .000000 f, -0 .702745 f,
1 .000000 f, -0 .331864 f, -0 .711864 f, 0 .000000 f, 0 .523911 f,
1 .000000 f, 1 .780000 f, 0 .000000 f, 0 .000000 f, -0 .893490 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float FCC_limited_rgb_to_yuv[] = {
0 .257647 f, 0 .506706 f, 0 .094471 f, 0 .000000 f, 0 .062745 f,
-0 .148050 f, -0 .291165 f, 0 .439216 f, 0 .000000 f, 0 .501961 f,
0 .439216 f, -0 .370196 f, -0 .069020 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float FCC_limited_yuv_to_rgb[] = {
1 .164384 f, -0 .000000 f, 1 .593750 f, 0 .000000 f, -0 .873059 f,
1 .164384 f, -0 .377792 f, -0 .810381 f, 0 .000000 f, 0 .523357 f,
1 .164384 f, 2 .026339 f, 0 .000000 f, 0 .000000 f, -1 .090202 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float SMPTE240_full_rgb_to_yuv[] = {
0 .212000 f, 0 .701000 f, 0 .087000 f, 0 .000000 f, 0 .000000 f,
-0 .116101 f, -0 .383899 f, 0 .500000 f, 0 .000000 f, 0 .501961 f,
0 .500000 f, -0 .444797 f, -0 .055203 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float SMPTE240_full_yuv_to_rgb[] = {
1 .000000 f, 0 .000000 f, 1 .576000 f, 0 .000000 f, -0 .791090 f,
1 .000000 f, -0 .226622 f, -0 .476622 f, 0 .000000 f, 0 .353001 f,
1 .000000 f, 1 .826000 f, 0 .000000 f, 0 .000000 f, -0 .916580 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float SMPTE240_limited_rgb_to_yuv[] = {
0 .182071 f, 0 .602035 f, 0 .074718 f, 0 .000000 f, 0 .062745 f,
-0 .101987 f, -0 .337229 f, 0 .439216 f, 0 .000000 f, 0 .501961 f,
0 .439216 f, -0 .390724 f, -0 .048492 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float SMPTE240_limited_yuv_to_rgb[] = {
1 .164384 f, -0 .000000 f, 1 .794107 f, 0 .000000 f, -0 .973631 f,
1 .164384 f, -0 .257985 f, -0 .542583 f, 0 .000000 f, 0 .328794 f,
1 .164384 f, 2 .078705 f, 0 .000000 f, 0 .000000 f, -1 .116488 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YDZDX_full_rgb_to_yuv[] = {
0 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f,
0 .000000 f, -0 .500000 f, 0 .493283 f, 0 .000000 f, 0 .501961 f,
0 .500000 f, -0 .495951 f, 0 .000000 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YDZDX_full_yuv_to_rgb[] = {
0 .991902 f, -0 .000000 f, 2 .000000 f, 0 .000000 f, -1 .003922 f,
1 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f,
1 .013617 f, 2 .027234 f, 0 .000000 f, 0 .000000 f, -1 .017592 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YDZDX_limited_rgb_to_yuv[] = {
0 .000000 f, 0 .858824 f, 0 .000000 f, 0 .000000 f, 0 .062745 f,
0 .000000 f, -0 .439216 f, 0 .433315 f, 0 .000000 f, 0 .501961 f,
0 .439216 f, -0 .435659 f, 0 .000000 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YDZDX_limited_yuv_to_rgb[] = {
1 .154954 f, -0 .000000 f, 2 .276786 f, 0 .000000 f, -1 .215325 f,
1 .164384 f, 0 .000000 f, 0 .000000 f, 0 .000000 f, -0 .073059 f,
1 .180239 f, 2 .307788 f, 0 .000000 f, 0 .000000 f, -1 .232474 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float GBR_full_rgb_to_yuv[] = {
0 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f,
0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f,
1 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float GBR_full_yuv_to_rgb[] = {
0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f,
1 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f, 0 .000000 f,
0 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f, -0 .000000 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float GBR_limited_rgb_to_yuv[] = {
0 .000000 f, 0 .858824 f, 0 .000000 f, 0 .000000 f, 0 .062745 f,
0 .000000 f, 0 .000000 f, 0 .858824 f, 0 .000000 f, 0 .062745 f,
0 .858824 f, 0 .000000 f, 0 .000000 f, 0 .000000 f, 0 .062745 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float GBR_limited_yuv_to_rgb[] = {
0 .000000 f, 0 .000000 f, 1 .164384 f, 0 .000000 f, -0 .073059 f,
1 .164384 f, 0 .000000 f, 0 .000000 f, 0 .000000 f, -0 .073059 f,
0 .000000 f, 1 .164384 f, 0 .000000 f, 0 .000000 f, -0 .073059 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_8bit_full_rgb_to_yuv[] = {
0 .250000 f, 0 .500000 f, 0 .250000 f, 0 .000000 f, 0 .000000 f,
-0 .250000 f, 0 .500000 f, -0 .250000 f, 0 .000000 f, 0 .501961 f,
0 .500000 f, 0 .000000 f, -0 .500000 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_8bit_full_yuv_to_rgb[] = {
1 .000000 f, -1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f,
1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f, -0 .501961 f,
1 .000000 f, -1 .000000 f, -1 .000000 f, 0 .000000 f, 1 .003922 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_8bit_limited_rgb_to_yuv[] = {
0 .214706 f, 0 .429412 f, 0 .214706 f, 0 .000000 f, 0 .062745 f,
-0 .214706 f, 0 .429412 f, -0 .214706 f, 0 .000000 f, 0 .501961 f,
0 .429412 f, 0 .000000 f, -0 .429412 f, 0 .000000 f, 0 .501961 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_8bit_limited_yuv_to_rgb[] = {
1 .164384 f, -1 .164384 f, 1 .164384 f, 0 .000000 f, -0 .073059 f,
1 .164384 f, 1 .164384 f, 0 .000000 f, 0 .000000 f, -0 .657534 f,
1 .164384 f, -1 .164384 f, -1 .164384 f, 0 .000000 f, 1 .095891 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_10bit_full_rgb_to_yuv[] = {
0 .250000 f, 0 .500000 f, 0 .250000 f, 0 .000000 f, 0 .000000 f,
-0 .250000 f, 0 .500000 f, -0 .250000 f, 0 .000000 f, 0 .500489 f,
0 .500000 f, 0 .000000 f, -0 .500000 f, 0 .000000 f, 0 .500489 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_10bit_full_yuv_to_rgb[] = {
1 .000000 f, -1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f,
1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f, -0 .500489 f,
1 .000000 f, -1 .000000 f, -1 .000000 f, 0 .000000 f, 1 .000978 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_10bit_limited_rgb_to_yuv[] = {
0 .214076 f, 0 .428153 f, 0 .214076 f, 0 .000000 f, 0 .062561 f,
-0 .214076 f, 0 .428153 f, -0 .214076 f, 0 .000000 f, 0 .500489 f,
0 .428153 f, 0 .000000 f, -0 .428153 f, 0 .000000 f, 0 .500489 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_10bit_limited_yuv_to_rgb[] = {
1 .167808 f, -1 .167808 f, 1 .167808 f, 0 .000000 f, -0 .073059 f,
1 .167808 f, 1 .167808 f, 0 .000000 f, 0 .000000 f, -0 .657534 f,
1 .167808 f, -1 .167808 f, -1 .167808 f, 0 .000000 f, 1 .095890 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_12bit_full_rgb_to_yuv[] = {
0 .250000 f, 0 .500000 f, 0 .250000 f, 0 .000000 f, 0 .000000 f,
-0 .250000 f, 0 .500000 f, -0 .250000 f, 0 .000000 f, 0 .500122 f,
0 .500000 f, 0 .000000 f, -0 .500000 f, 0 .000000 f, 0 .500122 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_12bit_full_yuv_to_rgb[] = {
1 .000000 f, -1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f,
1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f, -0 .500122 f,
1 .000000 f, -1 .000000 f, -1 .000000 f, 0 .000000 f, 1 .000244 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_12bit_limited_rgb_to_yuv[] = {
0 .213919 f, 0 .427839 f, 0 .213919 f, 0 .000000 f, 0 .062515 f,
-0 .213919 f, 0 .427839 f, -0 .213919 f, 0 .000000 f, 0 .500122 f,
0 .427839 f, 0 .000000 f, -0 .427839 f, 0 .000000 f, 0 .500122 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_12bit_limited_yuv_to_rgb[] = {
1 .168664 f, -1 .168664 f, 1 .168664 f, 0 .000000 f, -0 .073059 f,
1 .168664 f, 1 .168664 f, 0 .000000 f, 0 .000000 f, -0 .657534 f,
1 .168664 f, -1 .168664 f, -1 .168664 f, 0 .000000 f, 1 .095891 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_16bit_full_rgb_to_yuv[] = {
0 .250000 f, 0 .500000 f, 0 .250000 f, 0 .000000 f, 0 .000000 f,
-0 .250000 f, 0 .500000 f, -0 .250000 f, 0 .000000 f, 0 .500008 f,
0 .500000 f, 0 .000000 f, -0 .500000 f, 0 .000000 f, 0 .500008 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_16bit_full_yuv_to_rgb[] = {
1 .000000 f, -1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f,
1 .000000 f, 1 .000000 f, 0 .000000 f, 0 .000000 f, -0 .500008 f,
1 .000000 f, -1 .000000 f, -1 .000000 f, 0 .000000 f, 1 .000015 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_16bit_limited_rgb_to_yuv[] = {
0 .213870 f, 0 .427741 f, 0 .213870 f, 0 .000000 f, 0 .062501 f,
-0 .213870 f, 0 .427741 f, -0 .213870 f, 0 .000000 f, 0 .500008 f,
0 .427741 f, 0 .000000 f, -0 .427741 f, 0 .000000 f, 0 .500008 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
const float YCgCo_16bit_limited_yuv_to_rgb[] = {
1 .168932 f, -1 .168932 f, 1 .168932 f, 0 .000000 f, -0 .073059 f,
1 .168932 f, 1 .168932 f, 0 .000000 f, 0 .000000 f, -0 .657534 f,
1 .168932 f, -1 .168932 f, -1 .168932 f, 0 .000000 f, 1 .095890 f,
0 .000000 f, 0 .000000 f, 0 .000000 f, 1 .000000 f, 0 .000000 f,
};
static_assert(kJPEG_Full_SkYUVColorSpace == 0 , "" );
static_assert(kRec601_Limited_SkYUVColorSpace == 1 , "" );
static_assert(kRec709_Full_SkYUVColorSpace == 2 , "" );
static_assert(kRec709_Limited_SkYUVColorSpace == 3 , "" );
static_assert(kBT2020_8bit_Full_SkYUVColorSpace == 4 , "" );
static_assert(kBT2020_8bit_Limited_SkYUVColorSpace == 5 , "" );
static_assert(kBT2020_10bit_Full_SkYUVColorSpace == 6 , "" );
static_assert(kBT2020_10bit_Limited_SkYUVColorSpace == 7 , "" );
static_assert(kBT2020_12bit_Full_SkYUVColorSpace == 8 , "" );
static_assert(kBT2020_12bit_Limited_SkYUVColorSpace == 9 , "" );
static_assert(kBT2020_16bit_Full_SkYUVColorSpace == 10 , "" );
static_assert(kBT2020_16bit_Limited_SkYUVColorSpace == 11 , "" );
static_assert(kFCC_Full_SkYUVColorSpace == 12 , "" );
static_assert(kFCC_Limited_SkYUVColorSpace == 13 , "" );
static_assert(kSMPTE240_Full_SkYUVColorSpace == 14 , "" );
static_assert(kSMPTE240_Limited_SkYUVColorSpace == 15 , "" );
static_assert(kYDZDX_Full_SkYUVColorSpace == 16 , "" );
static_assert(kYDZDX_Limited_SkYUVColorSpace == 17 , "" );
static_assert(kGBR_Full_SkYUVColorSpace == 18 , "" );
static_assert(kGBR_Limited_SkYUVColorSpace == 19 , "" );
static_assert(kYCgCo_8bit_Full_SkYUVColorSpace == 20 , "" );
static_assert(kYCgCo_8bit_Limited_SkYUVColorSpace == 21 , "" );
static_assert(kYCgCo_10bit_Full_SkYUVColorSpace == 22 , "" );
static_assert(kYCgCo_10bit_Limited_SkYUVColorSpace == 23 , "" );
static_assert(kYCgCo_12bit_Full_SkYUVColorSpace == 24 , "" );
static_assert(kYCgCo_12bit_Limited_SkYUVColorSpace == 25 , "" );
static_assert(kYCgCo_16bit_Full_SkYUVColorSpace == 26 , "" );
static_assert(kYCgCo_16bit_Limited_SkYUVColorSpace == 27 , "" );
const float * yuv_to_rgb_array[] = {
JPEG_full_yuv_to_rgb,
Rec601_limited_yuv_to_rgb,
Rec709_full_yuv_to_rgb,
Rec709_limited_yuv_to_rgb,
BT2020_8bit_full_yuv_to_rgb,
BT2020_8bit_limited_yuv_to_rgb,
BT2020_10bit_full_yuv_to_rgb,
BT2020_10bit_limited_yuv_to_rgb,
BT2020_12bit_full_yuv_to_rgb,
BT2020_12bit_limited_yuv_to_rgb,
BT2020_16bit_full_yuv_to_rgb,
BT2020_16bit_limited_yuv_to_rgb,
FCC_full_yuv_to_rgb,
FCC_limited_yuv_to_rgb,
SMPTE240_full_yuv_to_rgb,
SMPTE240_limited_yuv_to_rgb,
YDZDX_full_yuv_to_rgb,
YDZDX_limited_yuv_to_rgb,
GBR_full_yuv_to_rgb,
GBR_limited_yuv_to_rgb,
YCgCo_8bit_full_yuv_to_rgb,
YCgCo_8bit_limited_yuv_to_rgb,
YCgCo_10bit_full_yuv_to_rgb,
YCgCo_10bit_limited_yuv_to_rgb,
YCgCo_12bit_full_yuv_to_rgb,
YCgCo_12bit_limited_yuv_to_rgb,
YCgCo_16bit_full_yuv_to_rgb,
YCgCo_16bit_limited_yuv_to_rgb,
};
const float * rgb_to_yuv_array[] = {
JPEG_full_rgb_to_yuv,
Rec601_limited_rgb_to_yuv,
Rec709_full_rgb_to_yuv,
Rec709_limited_rgb_to_yuv,
BT2020_8bit_full_rgb_to_yuv,
BT2020_8bit_limited_rgb_to_yuv,
BT2020_10bit_full_rgb_to_yuv,
BT2020_10bit_limited_rgb_to_yuv,
BT2020_12bit_full_rgb_to_yuv,
BT2020_12bit_limited_rgb_to_yuv,
BT2020_16bit_full_rgb_to_yuv,
BT2020_16bit_limited_rgb_to_yuv,
FCC_full_rgb_to_yuv,
FCC_limited_rgb_to_yuv,
SMPTE240_full_rgb_to_yuv,
SMPTE240_limited_rgb_to_yuv,
YDZDX_full_rgb_to_yuv,
YDZDX_limited_rgb_to_yuv,
GBR_full_rgb_to_yuv,
GBR_limited_rgb_to_yuv,
YCgCo_8bit_full_rgb_to_yuv,
YCgCo_8bit_limited_rgb_to_yuv,
YCgCo_10bit_full_rgb_to_yuv,
YCgCo_10bit_limited_rgb_to_yuv,
YCgCo_12bit_full_rgb_to_yuv,
YCgCo_12bit_limited_rgb_to_yuv,
YCgCo_16bit_full_rgb_to_yuv,
YCgCo_16bit_limited_rgb_to_yuv,
};
constexpr size_t kSizeOfColorMatrix = 20 * sizeof (float );
void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20 ]) {
if ((unsigned )cs < (unsigned )kIdentity_SkYUVColorSpace) {
memcpy(m, rgb_to_yuv_array[(unsigned )cs], kSizeOfColorMatrix);
} else {
memset(m, 0 , kSizeOfColorMatrix);
m[0 ] = m[6 ] = m[12 ] = m[18 ] = 1 ;
}
}
void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20 ]) {
if ((unsigned )cs < (unsigned )kIdentity_SkYUVColorSpace) {
memcpy(m, yuv_to_rgb_array[(unsigned )cs], kSizeOfColorMatrix);
} else {
memset(m, 0 , kSizeOfColorMatrix);
m[0 ] = m[6 ] = m[12 ] = m[18 ] = 1 ;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// we just drop the alpha rol/col from the colormatrix
// output is | tr |
// | 3x3 tg |
// | tb |
// | 0 0 0 1 |
static void colormatrix_to_matrix44(const float src[20 ], SkM44* dst) {
*dst = SkM44(src[ 0 ], src[ 1 ], src[ 2 ], src[ 4 ],
src[ 5 ], src[ 6 ], src[ 7 ], src[ 9 ],
src[10 ], src[11 ], src[12 ], src[14 ],
0 , 0 , 0 , 1 );
}
// input: ignore the bottom row
// output: inject identity row/column for alpha
static void matrix44_to_colormatrix(const SkM44& src, float dst[20 ]) {
dst[0 ] = src.rc(0 ,0 );
dst[1 ] = src.rc(0 ,1 );
dst[2 ] = src.rc(0 ,2 );
dst[3 ] = 0 ;
dst[4 ] = src.rc(0 ,3 ); // tx
dst[5 ] = src.rc(1 ,0 );
dst[6 ] = src.rc(1 ,1 );
dst[7 ] = src.rc(1 ,2 );
dst[8 ] = 0 ;
dst[9 ] = src.rc(1 ,3 ); // ty
dst[10 ] = src.rc(2 ,0 );
dst[11 ] = src.rc(2 ,1 );
dst[12 ] = src.rc(2 ,2 );
dst[13 ] = 0 ;
dst[14 ] = src.rc(2 ,3 ); // tz
dst[15 ] = dst[16 ] = dst[17 ] = dst[19 ] = 0 ;
dst[18 ] = 1 ;
}
static void scale3(float m[], float s) {
for (int i = 0 ; i < 3 ; ++i) {
m[i] *= s;
}
}
namespace {
enum Range { kFull, kLimited };
struct YUVCoeff {
float Kr, Kb;
int bits;
Range range;
};
const YUVCoeff gCoeff[] = {
{ 0 .2990 f, 0 .1140 f, 8 , kFull }, // kJPEG_Full_SkYUVColorSpace
{ 0 .2990 f, 0 .1140 f, 8 , kLimited }, // kRec601_Limited_SkYUVColorSpace
{ 0 .2126 f, 0 .0722 f, 8 , kFull }, // kRec709_Full_SkYUVColorSpace
{ 0 .2126 f, 0 .0722 f, 8 , kLimited }, // kRec709_Limited_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 8 , kFull }, // kBT2020_8bit_Full_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 8 , kLimited }, // kBT2020_8bit_Limited_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 10 , kFull }, // kBT2020_10bit_Full_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 10 , kLimited }, // kBT2020_10bit_Limited_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 12 , kFull }, // kBT2020_12bit_Full_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 12 , kLimited }, // kBT2020_12bit_Limited_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 16 , kFull }, // kBT2020_16bit_Full_SkYUVColorSpace
{ 0 .2627 f, 0 .0593 f, 16 , kLimited }, // kBT2020_16bit_Limited_SkYUVColorSpace
{ 0 .3000 f, 0 .1100 f, 8 , kFull }, // kFCC_Full_SkYUVColorSpace
{ 0 .3000 f, 0 .1100 f, 8 , kLimited }, // kFCC_Limited_SkYUVColorSpace
{ 0 .2120 f, 0 .0870 f, 8 , kFull }, // kSMPTE240_Full_SkYUVColorSpace
{ 0 .2120 f, 0 .0870 f, 8 , kLimited }, // kSMPTE240_Limited_SkYUVColorSpace
};
} // namespace
static void make_rgb_to_yuv_matrix_ycbcr(float mx[20 ], const YUVCoeff& c) {
SkASSERT(c.bits >= 8 );
const float Kr = c.Kr;
const float Kb = c.Kb;
const float Kg = 1 .0 f - Kr - Kb;
const float Cr = 0 .5 f / (1 .0 f - Kb);
const float Cb = 0 .5 f / (1 .0 f - Kr);
const int shift = c.bits - 8 ;
const float denom = static_cast <float >((1 << c.bits) - 1 );
float scaleY = 1 .0 f,
addY = 0 .0 f,
scaleUV = 1 .0 f,
addUV = (128 << shift) / denom;
if (c.range == kLimited) {
scaleY = (219 << shift) / denom;
addY = ( 16 << shift) / denom;
scaleUV = (224 << shift) / denom;
}
float m[20 ] = {
Kr, Kg, Kb, 0 , addY,
-Kr, -Kg, 1 -Kb, 0 , addUV,
1 -Kr, -Kg, -Kb, 0 , addUV,
0 , 0 , 0 , 1 , 0 ,
};
memcpy(mx, m, sizeof (m));
scale3(mx + 0 , scaleY );
scale3(mx + 5 , Cr * scaleUV);
scale3(mx + 10 , Cb * scaleUV);
}
static void make_rgb_to_yuv_matrix_ydzdx(float mx[20 ], Range range) {
const int bits = 8 ;
const float denom = static_cast <float >((1 << bits) - 1 );
float scaleY = 1 .0 f,
addY = 0 .0 f,
scaleUV = 1 .0 f,
addUV = 128 / denom;
if (range == kLimited) {
scaleY = 219 / denom;
addY = 16 / denom;
scaleUV = 224 / denom;
}
// YDZDX applies range correction to YUV values similar to YCbCr.
float m[20 ] = {
0 .0 f, 1 .0 f, 0 .0 f, 0 .0 f, addY, // Y
0 .0 f, -0 .5 f, 0 .986566 f / 2 .0 f, 0 .0 f, addUV, // DX or DZ
0 .5 f, -0 .991902 f / 2 .0 f, 0 .0 f, 0 .0 f, addUV, // DZ or DX
0 .0 f, 0 .0 f, 0 .0 f, 1 .0 f, 0 .0 f,
};
memcpy(mx, m, sizeof (m));
scale3(mx + 0 , scaleY );
scale3(mx + 5 , scaleUV);
scale3(mx + 10 , scaleUV);
}
static void make_rgb_to_yuv_matrix_gbr(float mx[20 ], Range range) {
const int bits = 8 ;
const float denom = static_cast <float >((1 << bits) - 1 );
float scaleY = 1 .0 f,
addY = 0 .0 f;
if (range == kLimited) {
scaleY = 219 / denom;
addY = 16 / denom;
}
// GBR applies range correction to RGB values similar to YCgCo.
float m[20 ] = {
0 .0 f, 1 .0 f, 0 .0 f, 0 .0 f, addY, // G
0 .0 f, 0 .0 f, 1 .0 f, 0 .0 f, addY, // B
1 .0 f, 0 .0 f, 0 .0 f, 0 .0 f, addY, // R
0 .0 f, 0 .0 f, 0 .0 f, 1 .0 f, 0 .0 f,
};
memcpy(mx, m, sizeof (m));
scale3(mx + 0 , scaleY);
scale3(mx + 5 , scaleY);
scale3(mx + 10 , scaleY);
}
static void make_rgb_to_yuv_matrix_ycgco(float mx[20 ], int bits, Range range) {
SkASSERT(bits >= 8 );
const int shift = bits - 8 ;
const float denom = static_cast <float >((1 << bits) - 1 );
float scaleY = 1 .0 f,
addY = 0 .0 f,
chroma05 = static_cast <float >(1 << (bits - 1 )) / denom;
if (range == kLimited) {
scaleY = (219 << shift) / denom;
addY = ( 16 << shift) / denom;
}
float m[20 ] = {
0 .25 f, 0 .5 f, 0 .25 f, 0 .0 f, addY,
-0 .25 f, 0 .5 f, -0 .25 f, 0 .0 f, chroma05,
0 .5 f, 0 .0 f, -0 .5 f, 0 .0 f, chroma05,
0 .0 f, 0 .0 f, 0 .0 f, 1 .0 f, 0 .0 f,
};
memcpy(mx, m, sizeof (m));
scale3(mx + 0 , scaleY);
scale3(mx + 5 , scaleY);
scale3(mx + 10 , scaleY);
}
static void make_rgb_to_yuv_matrix(float mx[20 ], SkYUVColorSpace cs) {
switch (cs) {
case kJPEG_Full_SkYUVColorSpace:
case kRec601_Limited_SkYUVColorSpace:
case kRec709_Full_SkYUVColorSpace:
case kRec709_Limited_SkYUVColorSpace:
case kBT2020_8bit_Full_SkYUVColorSpace:
case kBT2020_8bit_Limited_SkYUVColorSpace:
case kBT2020_10bit_Full_SkYUVColorSpace:
case kBT2020_10bit_Limited_SkYUVColorSpace:
case kBT2020_12bit_Full_SkYUVColorSpace:
case kBT2020_12bit_Limited_SkYUVColorSpace:
case kBT2020_16bit_Full_SkYUVColorSpace:
case kBT2020_16bit_Limited_SkYUVColorSpace:
case kFCC_Full_SkYUVColorSpace:
case kFCC_Limited_SkYUVColorSpace:
case kSMPTE240_Full_SkYUVColorSpace:
case kSMPTE240_Limited_SkYUVColorSpace:
case kIdentity_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycbcr(mx, gCoeff[(unsigned )cs]);
case kYDZDX_Full_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kFull);
case kYDZDX_Limited_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kLimited);
case kGBR_Full_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_gbr(mx, Range::kFull);
case kGBR_Limited_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_gbr(mx, Range::kLimited);
case kYCgCo_8bit_Full_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kFull);
case kYCgCo_8bit_Limited_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kLimited);
case kYCgCo_10bit_Full_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kFull);
case kYCgCo_10bit_Limited_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kLimited);
case kYCgCo_12bit_Full_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kFull);
case kYCgCo_12bit_Limited_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kLimited);
case kYCgCo_16bit_Full_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/16, Range::kFull);
case kYCgCo_16bit_Limited_SkYUVColorSpace:
return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/16, Range::kLimited);
}
}
static void dump(const float m[20 ], SkYUVColorSpace cs, bool rgb2yuv) {
const char * names[] = {
"JPEG_full" ,
"Rec601_limited" ,
"Rec709_full" ,
"Rec709_limited" ,
"BT2020_8bit_full" ,
"BT2020_8bit_limited" ,
"BT2020_10bit_full" ,
"BT2020_10bit_limited" ,
"BT2020_12bit_full" ,
"BT2020_12bit_limited" ,
"BT2020_16bit_full" ,
"BT2020_16bit_limited" ,
"FCC_full" ,
"FCC_limited" ,
"SMPTE240_full" ,
"SMPTE240_limited" ,
"YDZDX_full" ,
"YDZDX_limited" ,
"GBR_full" ,
"GBR_limited" ,
"YCgCo_8bit_full" ,
"YCgCo_8bit_limited" ,
"YCgCo_10bit_full" ,
"YCgCo_10bit_limited" ,
"YCgCo_12bit_full" ,
"YCgCo_12bit_limited" ,
"YCgCo_16bit_full" ,
"YCgCo_16bit_limited" ,
};
const char * dirnames[] = {
"yuv_to_rgb" , "rgb_to_yuv" ,
};
SkDebugf("const float %s_%s[] = {\n" , names[cs], dirnames[rgb2yuv]);
for (int i = 0 ; i < 4 ; ++i) {
SkDebugf(" " );
for (int j = 0 ; j < 5 ; ++j) {
SkDebugf(" %9.6ff," , m[i * 5 + j]);
}
SkDebugf("\n" );
}
SkDebugf("};\n" );
}
// Used to create the prebuilt tables for each colorspace.
// Don't remove this function, in case we want to recompute those tables in the future.
void SkColorMatrix_DumpYUVMatrixTables() {
for (int i = 0 ; i < kLastEnum_SkYUVColorSpace; ++i) {
SkYUVColorSpace cs = static_cast <SkYUVColorSpace>(i);
float m[20 ];
make_rgb_to_yuv_matrix(m, cs);
dump(m, cs, true );
SkM44 m44, im44;
colormatrix_to_matrix44(m, &m44);
float im[20 ];
#ifdef SK_DEBUG
// be sure our coversion between matrix44 and colormatrix is perfect
matrix44_to_colormatrix(m44, im);
SkASSERT(memcmp(m, im, sizeof (im)) == 0 );
#endif
SkAssertResult(m44.invert(&im44));
matrix44_to_colormatrix(im44, im);
dump(im, cs, false );
}
}
Messung V0.5 in Prozent C=92 H=96 G=93
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-06-06)
¤
*© Formatika GbR, Deutschland