121 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | ||
|  * Copyright 2021 Google Inc.
 | ||
|  *
 | ||
|  * Use of this source code is governed by a BSD-style license that can be
 | ||
|  * found in the LICENSE file.
 | ||
|  */
 | ||
| 
 | ||
| #include "gm/gm.h"
 | ||
| #include "include/core/SkCanvas.h"
 | ||
| #include "include/core/SkFont.h"
 | ||
| #include "include/core/SkSurface.h"
 | ||
| #include "tools/Resources.h"
 | ||
| 
 | ||
| static const skcms_TransferFunction gTFs[] = {
 | ||
|     SkNamedTransferFn::kSRGB,
 | ||
|     SkNamedTransferFn::k2Dot2,
 | ||
|     SkNamedTransferFn::kLinear,
 | ||
|     SkNamedTransferFn::kRec2020,
 | ||
|     SkNamedTransferFn::kPQ,
 | ||
|     SkNamedTransferFn::kHLG,
 | ||
|     {-3.0f, 2.0f, 2.0f, 1/0.17883277f, 0.28466892f, 0.55991073f,  3.0f },   // HLG scaled 4x
 | ||
| };
 | ||
| 
 | ||
| static const skcms_Matrix3x3 gGamuts[] = {
 | ||
|     SkNamedGamut::kSRGB,
 | ||
|     SkNamedGamut::kAdobeRGB,
 | ||
|     SkNamedGamut::kDisplayP3,
 | ||
|     SkNamedGamut::kRec2020,
 | ||
|     SkNamedGamut::kXYZ,
 | ||
| };
 | ||
| 
 | ||
| static const int W = 128,
 | ||
|                  H = 128;
 | ||
| 
 | ||
| // These GMs demonstrate that our color space management is self-consistent.
 | ||
| // (Important to note, self-consistent, not necessarily correct in an objective sense.)
 | ||
| //
 | ||
| // Let's let,
 | ||
| //
 | ||
| //     SkColorSpace* imgCS = img->colorSpace();
 | ||
| //     SkColorSpace* dstCS = canvas->imageInfo().colorSpace();
 | ||
| //
 | ||
| // Ordinarily we'd just
 | ||
| //
 | ||
| //     canvas->drawImage(img, 0,0);
 | ||
| //
 | ||
| // which would convert that img's pixels from imgCS to dstCS while drawing.
 | ||
| //
 | ||
| // But before we draw in these GMs, we convert the image to an arbitrarily different color space,
 | ||
| // letting midCS range over the cross-product gTFs × gGamuts:
 | ||
| //
 | ||
| //     canvas->drawImage(img->makeColorSpace(midCS), 0,0);
 | ||
| //
 | ||
| // This converts img first from imgCS to midCS, treating midCS as a destination color space,
 | ||
| // and then draws that midCS image to the dstCS canvas, treating midCS as a source color space.
 | ||
| // This should draw a grid of images that look identical except for small precision loss.
 | ||
| //
 | ||
| // If instead of calling SkImage::makeColorSpace() we use SkCanvas::makeSurface() to create a
 | ||
| // midCS offscreen, we construct the same logical imgCS -> midCS -> dstCS transform chain while
 | ||
| // exercising different drawing code paths.  Both strategies should draw roughly the same.
 | ||
| 
 | ||
| namespace {
 | ||
|     enum Strategy { SkImage_makeColorSpace, SkCanvas_makeSurface };
 | ||
| }
 | ||
| 
 | ||
| static void draw_colorspace_gm(Strategy strategy, SkCanvas* canvas) {
 | ||
|     if (!canvas->imageInfo().colorSpace()) {
 | ||
|         canvas->drawString("This GM only makes sense with color-managed drawing.",
 | ||
|                            W,H, SkFont{}, SkPaint{});
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     sk_sp<SkImage> img = GetResourceAsImage("images/mandrill_128.png");
 | ||
|     if (!img) {
 | ||
|         canvas->drawString("Could not load our test image!",
 | ||
|                            W,H, SkFont{}, SkPaint{});
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     SkASSERT(img->width()  == W);
 | ||
|     SkASSERT(img->height() == H);
 | ||
|     SkASSERT(img->colorSpace());
 | ||
| 
 | ||
|     for (skcms_Matrix3x3 gamut : gGamuts) {
 | ||
|         canvas->save();
 | ||
|         for (skcms_TransferFunction tf : gTFs) {
 | ||
|             sk_sp<SkColorSpace> midCS = SkColorSpace::MakeRGB(tf, gamut);
 | ||
| 
 | ||
|             switch (strategy) {
 | ||
|                 case SkImage_makeColorSpace: {
 | ||
|                     canvas->drawImage(img->makeColorSpace(midCS), 0,0);
 | ||
|                 } break;
 | ||
| 
 | ||
|                 case SkCanvas_makeSurface: {
 | ||
|                     sk_sp<SkSurface> offscreen =
 | ||
|                         canvas->makeSurface(canvas->imageInfo().makeColorSpace(midCS));
 | ||
|                     if (!offscreen) {
 | ||
|                         canvas->drawString("Could not allocate offscreen surface!",
 | ||
|                                            W,H, SkFont{}, SkPaint{});
 | ||
|                         return;
 | ||
|                     }
 | ||
|                     offscreen->getCanvas()->drawImage(img, 0,0);
 | ||
|                     canvas->drawImage(offscreen->makeImageSnapshot(), 0,0);
 | ||
|                 } break;
 | ||
|             }
 | ||
| 
 | ||
|             canvas->translate(W, 0);
 | ||
|         }
 | ||
|         canvas->restore();
 | ||
|         canvas->translate(0, H);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| DEF_SIMPLE_GM(colorspace, canvas, W*SK_ARRAY_COUNT(gTFs), H*SK_ARRAY_COUNT(gGamuts)) {
 | ||
|     draw_colorspace_gm(SkImage_makeColorSpace, canvas);
 | ||
| }
 | ||
| 
 | ||
| DEF_SIMPLE_GM(colorspace2, canvas, W*SK_ARRAY_COUNT(gTFs), H*SK_ARRAY_COUNT(gGamuts)) {
 | ||
|     draw_colorspace_gm(SkCanvas_makeSurface, canvas);
 | ||
| }
 |