Compare commits

...

18 Commits

Author SHA1 Message Date
Benjamin Otte
abbd7f0c92 colorspace: Add gdk_color_space_get_named ()
And add a bunch of common color spaces
2021-10-28 03:41:09 +02:00
Benjamin Otte
c70a8def57 gdk: Introduce GdkColor
GdkColor is our new immutable high-level color representation that
carries a GdkColorSpace around with it.

It is explicitly designed to be 2 things:
1. small
2. compatible with GdkRGBA.
3. extensible to all sorts of colorspaces.

So the struct looks like:
  struct {
    GdkColorSpace *color_space;
    float components[colorspace->n_components];
    float alpha;
  };
which for RGB colors literally maps to:
  struct {
    GdkColorSpace *color_space;
    GdkRGBA rgba;
  };
2021-10-28 03:41:09 +02:00
Benjamin Otte
37edec1dc8 x11: Implement support for color spaces
Stole a simple implementation from eog.

This doesn't yet update the profile when it changes though.
2021-10-28 03:41:09 +02:00
Benjamin Otte
fdf9cfd5c8 API: Add GdkSurface::color-space
Unused so far, but there's a private setter for backends and a public
readable property for code.
2021-10-28 03:41:09 +02:00
Matthias Clasen
5206d02a0d Support color profiles in pixbufs
When creating a GdkTexture from a GdkPixbuf,
see if it has an icc profile attached, and if
so, use it.
2021-10-28 03:41:09 +02:00
Matthias Clasen
e20c403f9b jpeg: Handle color profiles
Read the profile when loading jpegs and embed the profile when saving
them.
2021-10-28 03:41:09 +02:00
Matthias Clasen
6b00c98c81 tiff: Handle color profiles
Apply an embedded icc profile when loading tiff
images, and save associated icc profile information
when saving tiff images.
2021-10-28 03:41:09 +02:00
Benjamin Otte
1c8cf6ae72 png: Handle color profiles 2021-10-28 03:41:09 +02:00
Benjamin Otte
755d5d5f14 widget-factory: Add tests for loading color profiles
I figured out how to generate them, yay:

  cmsHPROFILE lcms_profile;
  cmsToneCurve *curve[3];

  curve[0] = cmsBuildParametricToneCurve (NULL, 4, (double[5]) { 1.0, 0, 0, 0, 0 });
  curve[1] = cmsBuildParametricToneCurve (NULL, 4, (double[5]) { 2.4, 255.0 / 15 / 1.055, 0.055 / 1.055, 0, 15./255 });
  curve[2] = cmsBuildGamma (NULL, 2.4);
  lcms_profile = cmsCreateRGBProfile (&(cmsCIExyY) {
                                        0.3127, 0.3290, 1.0
                                      },
                                      &(cmsCIExyYTRIPLE) {
                                        { 0.6400, 0.3300, 1.0 },
                                        { 0.3000, 0.6000, 1.0 },
                                        { 0.1500, 0.0600, 1.0 }
                                      },
                                      curve);

  cmsSaveProfileToFile (lcms_profile, "foo.icc");

  cmsFreeToneCurveTriple (curve);
  cmsCloseProfile (lcms_profile);
2021-10-28 03:41:09 +02:00
Benjamin Otte
ea73fc2b31 widget-factory: Add gradient rendering test
Test how GTK draws gradients, by adding an sRGB and a linear colorspace
gradient and draw one with CSS.

Have a look which one (if any) matches.
2021-10-28 03:41:09 +02:00
Benjamin Otte
65f709f55e memorytexture: Add colorspace argument to from_texture()
Make gdk_memory_texture_from_texture() take a colorspace instead of
implicitly using sRGB.
2021-10-28 03:41:09 +02:00
Benjamin Otte
e590014aff texture: Make ::download() take a colorspace
By passing the colorspace down into the download function, we allow an
immediate conversion in the backend. This will make it possible for GL
renderers to do the conversion in a shader instead of having to use the
CPU.
2021-10-28 03:41:09 +02:00
Benjamin Otte
995a74e188 API: Add gdk_memory_texture_new_with_color_space()
A version of gdk_memory_texture_new() that allows passing a color
space. The old version just assumes sRGB.
2021-10-28 03:41:09 +02:00
Benjamin Otte
0b06e32efa memoryformat: Take a color profile when converting 2021-10-28 03:41:09 +02:00
Benjamin Otte
7054181863 texture: Add a ::color-space property
Returns the associated color space. For now, this is always sRGB.
2021-10-28 03:41:09 +02:00
Benjamin Otte
d95353c1bc gdk: Add GdkLcmsColorSpace
This is a colorspace implementation using LCMS to implement support
for random colorspaces from ICC profiles.
2021-10-28 03:41:09 +02:00
Benjamin Otte
ab4837d311 cms: Add lcms to the build
Since lcms2 is using autotools, this uses the
experimental 'external project' module of meson,
and adds a minimal meson.build file to lcms2.

It seems to work.
2021-10-28 03:41:09 +02:00
Benjamin Otte
b7630f26df gdk: Add GdkColorSpace
The code doesn't do anything yet, this is just the boilerplate.
2021-10-28 03:41:09 +02:00
48 changed files with 1985 additions and 106 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

View File

@@ -6,3 +6,10 @@
.toolbar {
-gtk-icon-style: symbolic;
}
.gtk-gradient-color {
background: linear-gradient(to right, lime, red);
}
.gtk-gradient-monochrome {
background: linear-gradient(to right, black, white);
}

View File

@@ -118,5 +118,12 @@
<file>portland-rose.jpg</file>
<file>nyc.jpg</file>
<file>beach.jpg</file>
<file>linear-gradient-color.png</file>
<file>linear-gradient-monochrome.png</file>
<file>srgb-gradient-color.png</file>
<file>srgb-gradient-monochrome.png</file>
<file>color-profile-check.png</file>
<file>color-profile-check.jpeg</file>
<file>color-profile-check.tiff</file>
</gresource>
</gresources>

View File

@@ -1342,13 +1342,173 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<child>
<object class="GtkNotebookPage">
<property name="child">
<object class="GtkBox" id="box8">
<property name="orientation">1</property>
<object class="GtkGrid">
<property name="hexpand">0</property>
<property name="row-spacing">6</property>
<property name="column-spacing">6</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="row-homogeneous">1</property>
<property name="valign">start</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">color</property>
<style>
<class name="caption-heading"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">sRGB</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/srgb-gradient-color.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">GTK</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="width-request">128</property>
<property name="keep-aspect-ratio">0</property>
<style>
<class name="gtk-gradient-color"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">linear</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/linear-gradient-color.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">monochrome</property>
<style>
<class name="caption-heading"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">sRGB</property>
<layout>
<property name="column">0</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/srgb-gradient-monochrome.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">GTK</property>
<layout>
<property name="column">0</property>
<property name="row">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="width-request">128</property>
<property name="keep-aspect-ratio">0</property>
<style>
<class name="gtk-gradient-monochrome"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">linear</property>
<layout>
<property name="column">0</property>
<property name="row">7</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/linear-gradient-monochrome.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<layout>
<property name="column">1</property>
<property name="row">7</property>
</layout>
</object>
</child>
</object>
</property>
<property name="tab">
<object class="GtkLabel" id="label8">
<property name="label" translatable="1">page 1</property>
<property name="label" translatable="1">Gradients</property>
</object>
</property>
</object>
@@ -1357,13 +1517,91 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<object class="GtkNotebookPage">
<property name="position">1</property>
<property name="child">
<object class="GtkBox" id="box10">
<property name="orientation">1</property>
<object class="GtkGrid">
<property name="hexpand">0</property>
<property name="row-spacing">6</property>
<property name="column-spacing">6</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="row-homogeneous">1</property>
<property name="valign">start</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">image loading</property>
<style>
<class name="caption-heading"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkImage">
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.png</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">PNG</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkImage">
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.jpeg</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">JPEG</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkImage">
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.tiff</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">TIFF</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
</object>
</property>
<property name="tab">
<object class="GtkLabel" id="label9">
<property name="label" translatable="1">page 2</property>
<property name="label" translatable="1">Images</property>
</object>
</property>
</object>

View File

@@ -31,6 +31,8 @@
#include <gdk/gdkcairo.h>
#include <gdk/gdkcairocontext.h>
#include <gdk/gdkclipboard.h>
#include <gdk/gdkcolor.h>
#include <gdk/gdkcolorspace.h>
#include <gdk/gdkconfig.h>
#include <gdk/gdkcontentdeserializer.h>
#include <gdk/gdkcontentformats.h>

260
gdk/gdkcolor.c Normal file
View File

@@ -0,0 +1,260 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright (C) 2021 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkcolor.h"
#include "gdkcolorspaceprivate.h"
#include "gdkrgba.h"
/**
* GdkColor:
*
* GdkColor is a high level description of a color for use in a color managed context.
*
* FIXME: Add stuff about colors in the real world and looking at `GdkColorSpace` for
* how this is important.
*
* If you only want to use RGB colors, consider using `GdkRGBA` instead.
*/
#define GDK_IS_COLOR(self) ((self) != NULL)
struct _GdkColor
{
GdkColorSpace *color_space;
float components[]; /* alpha is last component, so that RGBA is in exactly that order */
};
G_DEFINE_BOXED_TYPE (GdkColor, gdk_color,
gdk_color_copy, gdk_color_free)
static GdkColor *
gdk_color_alloc (GdkColorSpace *space)
{
gsize n_components = gdk_color_space_get_n_components (space);
GdkColor *self;
self = g_malloc (sizeof (GdkColor) + n_components * sizeof (float));
self->color_space = g_object_ref (space);
return self;
}
/**
* gdk_color_new:
* @space: the color space of the color
* @alpha: the alpha value for this color
* @components: (array length=n_components) (nullable): an array of
* component values for this color
* @n_components: number of components
*
* Creates a new GdkColor representing the color for the given component
* values in the given color space.
*
* The alpha value is independent of the component values (also known as
* "unassociated" or "component values are not premultiplied").
*
* If the number of components passed is larger than the color space's
* components, extra values will be discarded. If it is smaller, the
* remaining components will be initialized as 0.
*
* Returns: a new GdkColor.
**/
GdkColor *
gdk_color_new (GdkColorSpace *space,
float alpha,
float *components,
gsize n_components)
{
gsize n_color_components;
GdkColor *self;
g_return_val_if_fail (GDK_IS_COLOR_SPACE (space), NULL);
g_return_val_if_fail (components != NULL || n_components == 0, NULL);
self = gdk_color_alloc (space);
n_color_components = gdk_color_space_get_n_components (space);
if (n_components)
memcpy (self->components, components, MIN (n_components, n_color_components));
if (n_components < n_color_components)
memset (&self->components[n_components], 0, sizeof (float) * (n_color_components - n_components));
self->components[n_color_components] = alpha;
return self;
}
G_STATIC_ASSERT (sizeof (GdkRGBA) == 4 * sizeof (float));
/**
* gdk_color_new_from_rgba:
* @rgba: a GdkRGBA
*
* Creates a new GdkColor from the given GdkRGBA.
*
* Returns: a new GdkColor
**/
GdkColor *
gdk_color_new_from_rgba (const GdkRGBA *rgba)
{
GdkColor *self;
g_return_val_if_fail (rgba != NULL, NULL);
self = gdk_color_alloc (gdk_color_space_get_srgb ());
memcpy (self->components, rgba, sizeof (GdkRGBA));
return self;
}
/**
* gdk_color_copy:
* @self: a `GdkColor`
*
* Copies the color.
*
* Returns: a copy of the color.
**/
GdkColor *
gdk_color_copy (const GdkColor *self)
{
GdkColor *copy;
copy = gdk_color_alloc (self->color_space);
memcpy (copy->components,
self->components,
sizeof (float) * (gdk_color_space_get_n_components (self->color_space) + 1));
return copy;
}
/**
* gdk_color_free:
* @self: a #GdkColor
*
* Frees a `GdkColor`.
**/
void
gdk_color_free (GdkColor *self)
{
g_object_unref (self->color_space);
g_free (self);
}
/**
* gdk_color_get_color_space:
* @self: a `GdkColor`
*
* Returns the color space that this color is defined in.
*
* Returns: the color space this color is defined in
**/
GdkColorSpace *
gdk_color_get_color_space (const GdkColor *self)
{
g_return_val_if_fail (GDK_IS_COLOR (self), gdk_color_space_get_srgb ());
return self->color_space;
}
/**
* gdk_color_get_alpha:
* @self: a `GdkColor`
*
* Gets the alpha value of this color. Alpha values range from 0.0
* (fully translucent) to 1.0 (fully opaque).
*
* Returns: The alpha value
**/
float
gdk_color_get_alpha (const GdkColor *self)
{
g_return_val_if_fail (GDK_IS_COLOR (self), 1.f);
return self->components[gdk_color_space_get_n_components (self->color_space)];
}
/**
* gdk_color_get_components:
* @self: a `GdkColor`
*
* Returns the array of component values for this color.
*
* For an RGB color, this will be an array of 3 values with intensities of
* the red, green and blue components, respectively, in a range from 0 to 1.
*
* Other color spaces that are not RGB colors can have a different amount of
* components with different meanings and different ranges.
*
* Returns: the component values
**/
const float *
gdk_color_get_components (const GdkColor *self)
{
g_return_val_if_fail (GDK_IS_COLOR (self), NULL);
return self->components;
}
/**
* gdk_color_get_n_components:
* @self: a `GdkColor`
*
* Gets the number of components of this color. This will be the number of
* components returned by gdk_color_get_components().
*
* Returns: the number of components
**/
gsize
gdk_color_get_n_components (const GdkColor *self)
{
g_return_val_if_fail (GDK_IS_COLOR (self), 3);
return gdk_color_space_get_n_components (self->color_space);
}
/**
* gdk_color_convert:
* @self: a `GdkColor`
* @space: the color space to convert to
*
* Converts a color into a different colorspace, potentially
* tone-mapping it if it is out of gamut.
*
* Returns: a new color in the new colorspace.
**/
GdkColor *
gdk_color_convert (const GdkColor *self,
GdkColorSpace *space)
{
GdkColor *result;
gsize n_components;
g_return_val_if_fail (GDK_IS_COLOR (self), NULL);
g_return_val_if_fail (GDK_IS_COLOR_SPACE (space), NULL);
result = gdk_color_alloc (space);
n_components = gdk_color_space_get_n_components (self->color_space);
result->components[n_components] = self->components[n_components];
GDK_COLOR_SPACE_GET_CLASS (space)->convert_color (space, result->components, self);
return result;
}

70
gdk/gdkcolor.h Normal file
View File

@@ -0,0 +1,70 @@
/* gdkcolor.h
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_COLOR_H__
#define __GDK_COLOR_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdkversionmacros.h>
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_COLOR (gdk_color_get_type ())
GDK_AVAILABLE_IN_4_6
GType gdk_color_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_6
GdkColor * gdk_color_new (GdkColorSpace *space,
float alpha,
float *components,
gsize n_components);
GDK_AVAILABLE_IN_4_6
GdkColor * gdk_color_new_from_rgba (const GdkRGBA *rgba);
GDK_AVAILABLE_IN_4_6
GdkColor * gdk_color_copy (const GdkColor *self);
GDK_AVAILABLE_IN_4_6
void gdk_color_free (GdkColor *self);
GDK_AVAILABLE_IN_4_6
GdkColorSpace * gdk_color_get_color_space (const GdkColor *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_6
float gdk_color_get_alpha (const GdkColor *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_6
const float * gdk_color_get_components (const GdkColor *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_6
gsize gdk_color_get_n_components (const GdkColor *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_6
GdkColor * gdk_color_convert (const GdkColor *self,
GdkColorSpace *space);
/*
GDK_AVAILABLE_IN_4_6
GdkColor * gdk_color_mix (const GdkColor *self,
const GdkColor *other,
double progress,
GdkColorSpace *space);
*/
G_END_DECLS
#endif /* __GDK_COLOR_H__ */

View File

@@ -0,0 +1,15 @@
#ifndef __GDK_COLOR_PROFILE_PRIVATE_H__
#define __GDK_COLOR_PROFILE_PRIVATE_H__
#include "gdkcolorprofile.h"
#include <lcms2.h>
G_BEGIN_DECLS
cmsHPROFILE * gdk_color_profile_get_lcms_profile (GdkColorProfile *self);
G_END_DECLS
#endif /* __GDK_COLOR_PROFILE_PRIVATE_H__ */

312
gdk/gdkcolorspace.c Normal file
View File

@@ -0,0 +1,312 @@
/* gdkcolorspace.c
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* GdkColorSpace:
*
* `GdkColorSpace` is used to describe color spaces.
*
* Tell developers what a color space is instead of just linking to
* https://en.wikipedia.org/wiki/Color_space
*
* `GdkColorSpace` objects are immutable and therefore threadsafe.
*
* Since: 4.6
*/
#include "config.h"
#include "gdkcolorspaceprivate.h"
#include "gdkintl.h"
#include "gdklcmscolorspaceprivate.h"
enum {
PROP_0,
N_PROPS
};
//static GParamSpec *properties[N_PROPS];
G_DEFINE_TYPE (GdkColorSpace, gdk_color_space, G_TYPE_OBJECT)
static gboolean
gdk_color_space_default_supports_format (GdkColorSpace *self,
GdkMemoryFormat format)
{
return FALSE;
}
static GBytes *
gdk_color_space_default_save_to_icc_profile (GdkColorSpace *self,
GError **error)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("This color space does not support ICC profiles"));
return NULL;
}
static void
gdk_color_space_default_convert_color (GdkColorSpace *self,
float *components,
const GdkColor *source)
{
g_assert_not_reached ();
}
static void
gdk_color_space_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
//GdkColorSpace *self = GDK_COLOR_SPACE (gobject);
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gdk_color_space_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
//GdkColorSpace *self = GDK_COLOR_SPACE (gobject);
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gdk_color_space_dispose (GObject *object)
{
//GdkColorSpace *self = GDK_COLOR_SPACE (object);
G_OBJECT_CLASS (gdk_color_space_parent_class)->dispose (object);
}
static void
gdk_color_space_class_init (GdkColorSpaceClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->supports_format = gdk_color_space_default_supports_format;
klass->save_to_icc_profile = gdk_color_space_default_save_to_icc_profile;
klass->convert_color = gdk_color_space_default_convert_color;
gobject_class->set_property = gdk_color_space_set_property;
gobject_class->get_property = gdk_color_space_get_property;
gobject_class->dispose = gdk_color_space_dispose;
}
static void
gdk_color_space_init (GdkColorSpace *self)
{
}
/**
* gdk_color_space_get_srgb:
*
* Returns the color profile representing the sRGB color space.
*
* If you don't know anything about color profiles but need one for
* use with some function, this one is most likely the right one.
*
* Returns: (transfer none): the color profile for the sRGB
* color space.
*
* Since: 4.6
*/
GdkColorSpace *
gdk_color_space_get_srgb (void)
{
static GdkColorSpace *srgb_profile;
if (g_once_init_enter (&srgb_profile))
{
GdkColorSpace *new_profile;
new_profile = gdk_lcms_color_space_new_from_lcms_profile (cmsCreate_sRGBProfile ());
g_once_init_leave (&srgb_profile, new_profile);
}
return srgb_profile;
}
GdkColorSpace *
gdk_color_space_get_named (GdkNamedColorSpace name)
{
static GdkColorSpace *space_array[GDK_NAMED_COLOR_SPACE_N_SPACES];
static GdkColorSpace **color_spaces;
g_return_val_if_fail (name < GDK_NAMED_COLOR_SPACE_N_SPACES, gdk_color_space_get_srgb ());
if (g_once_init_enter (&color_spaces))
{
static const cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 };
static const cmsFloat64Number srgb_tonecurve[5] = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 };
static const cmsFloat64Number rec709_tonecurve[5] = { 1.0 / 0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081 };
cmsToneCurve *curve;
cmsHPROFILE lcms_profile;
space_array[GDK_NAMED_COLOR_SPACE_SRGB] = g_object_ref (gdk_color_space_get_srgb ());
curve = cmsBuildGamma (NULL, 1.0);
lcms_profile = cmsCreateRGBProfile (&D65,
&(cmsCIExyYTRIPLE) {
{ 0.640, 0.330, 1.0 },
{ 0.300, 0.600, 1.0 },
{ 0.150, 0.060, 1.0 }
},
(cmsToneCurve*[3]) { curve, curve, curve });
cmsFreeToneCurve (curve);
space_array[GDK_NAMED_COLOR_SPACE_SRGB_LINEAR] = gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
space_array[GDK_NAMED_COLOR_SPACE_XYZ_D50] = gdk_lcms_color_space_new_from_lcms_profile (cmsCreateXYZProfile ());
/* XXX: This needs a D65 whitepoint here */
space_array[GDK_NAMED_COLOR_SPACE_XYZ_D65] = gdk_lcms_color_space_new_from_lcms_profile (cmsCreateXYZProfile ());
curve = cmsBuildParametricToneCurve (NULL, 4, srgb_tonecurve);
lcms_profile = cmsCreateRGBProfile (&D65,
&(cmsCIExyYTRIPLE) {
{ 0.680, 0.320, 1.0 },
{ 0.265, 0.690, 1.0 },
{ 0.150, 0.060, 1.0 }
},
(cmsToneCurve*[3]) { curve, curve, curve });
cmsFreeToneCurve (curve);
space_array[GDK_NAMED_COLOR_SPACE_DISPLAY_P3] = gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
curve = cmsBuildGamma(NULL, 2.19921875);
lcms_profile = cmsCreateRGBProfile (&D65,
&(cmsCIExyYTRIPLE) {
{ 0.640, 0.330, 1.0 },
{ 0.210, 0.710, 1.0 },
{ 0.150, 0.060, 1.0 }
},
(cmsToneCurve*[3]) { curve, curve, curve });
cmsFreeToneCurve (curve);
space_array[GDK_NAMED_COLOR_SPACE_A98_RGB] = gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
curve = cmsBuildParametricToneCurve (NULL, 4, rec709_tonecurve);
lcms_profile = cmsCreateRGBProfile (cmsD50_xyY (),
&(cmsCIExyYTRIPLE) {
{ 0.734699, 0.265301, 1.0 },
{ 0.159597, 0.840403, 1.0 },
{ 0.036598, 0.000105, 1.0 }
},
(cmsToneCurve*[3]) { curve, curve, curve });
cmsFreeToneCurve (curve);
space_array[GDK_NAMED_COLOR_SPACE_PROPHOTO_RGB] = gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
curve = cmsBuildParametricToneCurve (NULL, 4, rec709_tonecurve);
lcms_profile = cmsCreateRGBProfile (&D65,
&(cmsCIExyYTRIPLE) {
{ 0.708, 0.292, 1.0 },
{ 0.170, 0.797, 1.0 },
{ 0.131, 0.046, 1.0 }
},
(cmsToneCurve*[3]) { curve, curve, curve });
cmsFreeToneCurve (curve);
space_array[GDK_NAMED_COLOR_SPACE_REC2020] = gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
g_once_init_leave (&color_spaces, space_array);
}
return color_spaces[name];
}
/**
* gdk_color_space_supports_format:
* @self: a `GdkColorSpace`
* @format: the format to check
*
* Checks if this color space can be used with textures in the given format.
*
* Returns: %TRUE if this colorspace supports the format
*
* Since: 4.6
**/
gboolean
gdk_color_space_supports_format (GdkColorSpace *self,
GdkMemoryFormat format)
{
g_return_val_if_fail (GDK_IS_COLOR_SPACE (self), FALSE);
g_return_val_if_fail (format < GDK_MEMORY_N_FORMATS, FALSE);
return GDK_COLOR_SPACE_GET_CLASS (self)->supports_format (self, format);
}
/**
* gdk_color_space_save_to_icc_profile:
* @self: a `GdkColorSpace`
* @error: Return location for an error
*
* Saves the color space to an
* [ICC profile](https://en.wikipedia.org/wiki/ICC_profile).
*
* Some color spaces cannot be represented as ICC profiles. In
* that case, an error will be set and %NULL will be returned.
*
* Returns: A new `GBytes` containing the ICC profile
*
* Since: 4.6
**/
GBytes *
gdk_color_space_save_to_icc_profile (GdkColorSpace *self,
GError **error)
{
g_return_val_if_fail (GDK_IS_COLOR_SPACE (self), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return GDK_COLOR_SPACE_GET_CLASS (self)->save_to_icc_profile (self, error);
}
/**
* gdk_color_space_equal:
* @profile1: (type GdkColorSpace): a `GdkColorSpace`
* @profile2: (type GdkColorSpace): another `GdkColorSpace`
*
* Compares two `GdkColorSpace`s for equality.
*
* Note that this function is not guaranteed to be perfect and two equal
* profiles may compare not equal. However, different profiles will
* never compare equal.
*
* Returns: %TRUE if the two color profiles compare equal
*
* Since: 4.6
*/
gboolean
gdk_color_space_equal (gconstpointer profile1,
gconstpointer profile2)
{
return profile1 == profile2;
}

70
gdk/gdkcolorspace.h Normal file
View File

@@ -0,0 +1,70 @@
/* gdkcolorspace.h
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_COLOR_SPACE_H__
#define __GDK_COLOR_SPACE_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdkenums.h>
#include <gdk/gdktypes.h>
#include <gdk/gdkversionmacros.h>
G_BEGIN_DECLS
#define GDK_TYPE_COLOR_SPACE (gdk_color_space_get_type ())
#define GDK_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_COLOR_SPACE, GdkColorSpace))
#define GDK_IS_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_COLOR_SPACE))
#define GDK_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_COLOR_SPACE, GdkColorSpaceClass))
#define GDK_IS_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_COLOR_SPACE))
#define GDK_COLOR_SPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_COLOR_SPACE, GdkColorSpaceClass))
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkColorSpace, g_object_unref)
typedef struct _GdkColorSpaceClass GdkColorSpaceClass;
GDK_AVAILABLE_IN_4_6
GType gdk_color_space_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_6
GdkColorSpace * gdk_color_space_get_srgb (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_6
GdkColorSpace * gdk_color_space_get_named (GdkNamedColorSpace name) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_6
GdkColorSpace * gdk_color_space_new_from_icc_profile (GBytes *icc_profile,
GError **error);
GDK_AVAILABLE_IN_4_6
gboolean gdk_color_space_supports_format (GdkColorSpace *self,
GdkMemoryFormat format);
GDK_AVAILABLE_IN_4_6
GBytes * gdk_color_space_save_to_icc_profile (GdkColorSpace *self,
GError **error);
GDK_AVAILABLE_IN_4_6
gboolean gdk_color_space_equal (gconstpointer profile1,
gconstpointer profile2);
G_END_DECLS
#endif /* __GDK_COLOR_SPACE_H__ */

View File

@@ -0,0 +1,37 @@
#ifndef __GDK_COLOR_SPACE_PRIVATE_H__
#define __GDK_COLOR_SPACE_PRIVATE_H__
#include "gdkcolorspace.h"
G_BEGIN_DECLS
struct _GdkColorSpace
{
GObject parent_instance;
gsize n_components;
};
struct _GdkColorSpaceClass
{
GObjectClass parent_class;
gboolean (* supports_format) (GdkColorSpace *self,
GdkMemoryFormat format);
GBytes * (* save_to_icc_profile) (GdkColorSpace *self,
GError **error);
void (* convert_color) (GdkColorSpace *self,
float *components,
const GdkColor *source);
};
static inline gsize
gdk_color_space_get_n_components (GdkColorSpace *self)
{
return self->n_components;
}
G_END_DECLS
#endif /* __GDK_COLOR_SPACE_PRIVATE_H__ */

View File

@@ -331,6 +331,50 @@ typedef enum {
GDK_MEMORY_N_FORMATS
} GdkMemoryFormat;
/**
* GdkNamedColorSpace:
* @GDK_NAMED_COLOR_SPACE_SRGB: the sRGB color space,
* see gdk_color_space_get_srgb() for details
* @GDK_NAMED_COLOR_SPACE_SRGB_LINEAR: the same sRGB color space, but
* with a linear light tone curve
* @GDK_NAMED_COLOR_SPACE_XYZ_D50: the CIE XYZ color space, with the D50
* white point
* @GDK_NAMED_COLOR_SPACE_XYZ_D65: the CIE CYZ color space, with the D65
* white point
* @GDK_NAMED_COLOR_SPACE_DISPLAY_P3: the [DCI P3](https://en.wikipedia.org/wiki/DCI-P3)
* color space with a D65 whitepoint as created by Apple
* @GDK_NAMED_COLOR_SPACE_A98_RGB: the [Adobe 1998 RGB](https://en.wikipedia.org/wiki/Adobe_RGB_color_space)
* color space
* @GDK_NAMED_COLOR_SPACE_PROPHOTO_RGB: the [ProPhoto RGB](https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space)
* color space
* @GDK_NAMED_COLOR_SPACE_REC2020: the [Rec 2020](https://en.wikipedia.org/wiki/Rec._2020)
* color space
* @GDK_NAMED_COLOR_SPACE_N_SPACES: The number of named color spaces.
* This value will change as more color spaces get added, so do not
* rely on its concrete integer.
*
*
* The list of predefined color spaces. GDK provides the common
* color spaces used by CSS and other standards so applications can make
* use of them.
*
* More color spaces may be added in the future.
*
* Since: 4.6
**/
typedef enum {
GDK_NAMED_COLOR_SPACE_SRGB,
GDK_NAMED_COLOR_SPACE_SRGB_LINEAR,
GDK_NAMED_COLOR_SPACE_XYZ_D50,
GDK_NAMED_COLOR_SPACE_XYZ_D65,
GDK_NAMED_COLOR_SPACE_DISPLAY_P3,
GDK_NAMED_COLOR_SPACE_A98_RGB,
GDK_NAMED_COLOR_SPACE_PROPHOTO_RGB,
GDK_NAMED_COLOR_SPACE_REC2020,
GDK_NAMED_COLOR_SPACE_N_SPACES
} GdkNamedColorSpace;
G_END_DECLS
#endif /* __GDK_ENUMS_H__ */

View File

@@ -20,6 +20,7 @@
#include "gdkgltextureprivate.h"
#include "gdkcolorspace.h"
#include "gdkdisplayprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
@@ -114,6 +115,7 @@ typedef struct _Download Download;
struct _Download
{
GdkMemoryFormat format;
GdkColorSpace *color_space;
guchar *data;
gsize stride;
};
@@ -156,6 +158,7 @@ gdk_gl_texture_do_download (gpointer texture_,
expected_stride = texture->width * gdk_memory_format_bytes_per_pixel (download->format);
if (download->stride == expected_stride &&
download->color_space == texture->color_space &&
!gdk_gl_context_get_use_es (self->context) &&
gdk_memory_format_gl_format (download->format, TRUE, &gl_internal_format, &gl_format, &gl_type))
{
@@ -180,6 +183,7 @@ gdk_gl_texture_do_download (gpointer texture_,
actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */
if (download->format == actual_format &&
download->color_space == texture->color_space &&
(download->stride == expected_stride))
{
glReadPixels (0, 0,
@@ -202,9 +206,11 @@ gdk_gl_texture_do_download (gpointer texture_,
gdk_memory_convert (download->data,
download->stride,
download->format,
download->color_space,
pixels,
texture->width * actual_bpp,
actual_format,
texture->color_space,
texture->width,
texture->height);
@@ -218,6 +224,7 @@ gdk_gl_texture_do_download (gpointer texture_,
static void
gdk_gl_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
@@ -226,11 +233,12 @@ gdk_gl_texture_download (GdkTexture *texture,
if (self->saved)
{
gdk_texture_do_download (self->saved, format, data, stride);
gdk_texture_do_download (self->saved, format, color_space, data, stride);
return;
}
download.format = format;
download.color_space = color_space;
download.data = data;
download.stride = stride;
@@ -285,7 +293,8 @@ gdk_gl_texture_release (GdkGLTexture *self)
texture = GDK_TEXTURE (self);
self->saved = GDK_TEXTURE (gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture)));
gdk_texture_get_format (texture),
gdk_texture_get_color_space (texture)));
if (self->destroy)
{

153
gdk/gdklcmscolorspace.c Normal file
View File

@@ -0,0 +1,153 @@
/* gdklcmscolorspace.c
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdklcmscolorspaceprivate.h"
#include "gdkintl.h"
struct _GdkLcmsColorSpace
{
GdkColorSpace parent_instance;
cmsHPROFILE lcms_profile;
};
struct _GdkLcmsColorSpaceClass
{
GdkColorSpaceClass parent_class;
};
G_DEFINE_TYPE (GdkLcmsColorSpace, gdk_lcms_color_space, GDK_TYPE_COLOR_SPACE)
static gboolean
gdk_lcms_color_space_supports_format (GdkColorSpace *space,
GdkMemoryFormat format)
{
GdkLcmsColorSpace *self = GDK_LCMS_COLOR_SPACE (space);
return cmsGetColorSpace (self->lcms_profile) == cmsSigRgbData;
}
static GBytes *
gdk_lcms_color_space_save_to_icc_profile (GdkColorSpace *space,
GError **error)
{
GdkLcmsColorSpace *self = GDK_LCMS_COLOR_SPACE (space);
cmsUInt32Number size;
guchar *data;
size = 0;
if (!cmsSaveProfileToMem (self->lcms_profile, NULL, &size))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Could not prepare ICC profile"));
return NULL;
}
data = g_malloc (size);
if (!cmsSaveProfileToMem (self->lcms_profile, data, &size))
{
g_free (data);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to save ICC profile"));
return NULL;
}
return g_bytes_new_take (data, size);
}
static void
gdk_lcms_color_space_dispose (GObject *object)
{
GdkLcmsColorSpace *self = GDK_LCMS_COLOR_SPACE (object);
g_clear_pointer (&self->lcms_profile, cmsCloseProfile);
G_OBJECT_CLASS (gdk_lcms_color_space_parent_class)->dispose (object);
}
static void
gdk_lcms_color_space_class_init (GdkLcmsColorSpaceClass *klass)
{
GdkColorSpaceClass *color_space_class = GDK_COLOR_SPACE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
color_space_class->supports_format = gdk_lcms_color_space_supports_format;
color_space_class->save_to_icc_profile = gdk_lcms_color_space_save_to_icc_profile;
gobject_class->dispose = gdk_lcms_color_space_dispose;
}
static void
gdk_lcms_color_space_init (GdkLcmsColorSpace *self)
{
}
GdkColorSpace *
gdk_lcms_color_space_new_from_lcms_profile (cmsHPROFILE lcms_profile)
{
GdkLcmsColorSpace *result;
result = g_object_new (GDK_TYPE_LCMS_COLOR_SPACE, NULL);
result->lcms_profile = lcms_profile;
return GDK_COLOR_SPACE (result);
}
/**
* gdk_color_space_new_from_icc_profile:
* @icc_profile: The ICC profiles given as a `GBytes`
* @error: Return location for an error
*
* Creates a new color profile for the given ICC profile data.
*
* if the profile is not valid, %NULL is returned and an error
* is raised.
*
* Returns: a new `GdkLcmsColorSpace` or %NULL on error
*
* Since: 4.6
*/
GdkColorSpace *
gdk_color_space_new_from_icc_profile (GBytes *icc_profile,
GError **error)
{
cmsHPROFILE lcms_profile;
const guchar *data;
gsize size;
g_return_val_if_fail (icc_profile != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
data = g_bytes_get_data (icc_profile, &size);
lcms_profile = cmsOpenProfileFromMem (data, size);
if (lcms_profile == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to load ICC profile"));
return NULL;
}
return gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
}
cmsHPROFILE
gdk_lcms_color_space_get_lcms_profile (GdkLcmsColorSpace *self)
{
return self->lcms_profile;
}

View File

@@ -0,0 +1,49 @@
/* gdklcmscolorspace.h
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_LCMS_COLOR_SPACE_PRIVATE_H__
#define __GDK_LCMS_COLOR_SPACE_PRIVATE_H__
#include "gdkcolorspaceprivate.h"
#include <lcms2.h>
G_BEGIN_DECLS
#define GDK_TYPE_LCMS_COLOR_SPACE (gdk_lcms_color_space_get_type ())
#define GDK_LCMS_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_LCMS_COLOR_SPACE, GdkLcmsColorSpace))
#define GDK_IS_LCMS_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_LCMS_COLOR_SPACE))
#define GDK_LCMS_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_LCMS_COLOR_SPACE, GdkLcmsColorSpaceClass))
#define GDK_IS_LCMS_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_LCMS_COLOR_SPACE))
#define GDK_LCMS_COLOR_SPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_LCMS_COLOR_SPACE, GdkLcmsColorSpaceClass))
typedef struct _GdkLcmsColorSpace GdkLcmsColorSpace;
typedef struct _GdkLcmsColorSpaceClass GdkLcmsColorSpaceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkLcmsColorSpace, g_object_unref)
GType gdk_lcms_color_space_get_type (void) G_GNUC_CONST;
GdkColorSpace * gdk_lcms_color_space_new_from_lcms_profile (cmsHPROFILE lcms_profile);
cmsHPROFILE gdk_lcms_color_space_get_lcms_profile (GdkLcmsColorSpace *self);
G_END_DECLS
#endif /* __GDK_LCMS_COLOR_SPACE_PRIVATE_H__ */

View File

@@ -21,6 +21,9 @@
#include "gdkmemoryformatprivate.h"
#include "gdkcolorspaceprivate.h"
#include "gdklcmscolorspaceprivate.h"
#include "gsk/gl/fp16private.h"
#include <epoxy/gl.h>
@@ -465,14 +468,17 @@ void
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorSpace *dest_space,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorSpace *src_space,
gsize width,
gsize height)
{
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
cmsHTRANSFORM transform;
float *tmp;
gsize y;
@@ -481,17 +487,46 @@ gdk_memory_convert (guchar *dest_data,
tmp = g_new (float, width * 4);
if (gdk_color_space_equal (src_space, dest_space))
{
transform = NULL;
}
else
{
transform = cmsCreateTransform (gdk_lcms_color_space_get_lcms_profile (GDK_LCMS_COLOR_SPACE (src_space)),
TYPE_RGBA_FLT,
gdk_lcms_color_space_get_lcms_profile (GDK_LCMS_COLOR_SPACE (dest_space)),
TYPE_RGBA_FLT,
INTENT_PERCEPTUAL,
cmsFLAGS_COPY_ALPHA);
}
for (y = 0; y < height; y++)
{
src_desc->to_float (tmp, src_data, width);
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
unpremultiply (tmp, width);
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
if (transform)
{
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED)
unpremultiply (tmp, width);
cmsDoTransform (transform,
tmp,
tmp,
width);
if (dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
}
else
{
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
unpremultiply (tmp, width);
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
}
dest_desc->from_float (dest_data, tmp, width);
src_data += src_stride;
dest_data += dest_stride;
}
g_free (tmp);
g_clear_pointer (&transform, cmsDeleteTransform);
}

View File

@@ -21,6 +21,7 @@
#define __GDK_MEMORY_CONVERT_PRIVATE_H__
#include "gdkenums.h"
#include "gdktypes.h"
G_BEGIN_DECLS
@@ -43,9 +44,11 @@ gboolean gdk_memory_format_gl_format (GdkMemoryFormat
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorSpace *dest_space,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorSpace *src_space,
gsize width,
gsize height);

View File

@@ -21,6 +21,7 @@
#include "gdkmemorytextureprivate.h"
#include "gdkcolorspace.h"
#include "gdkmemoryformatprivate.h"
#include "gsk/gl/fp16private.h"
@@ -58,6 +59,7 @@ gdk_memory_texture_dispose (GObject *object)
static void
gdk_memory_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
@@ -65,9 +67,11 @@ gdk_memory_texture_download (GdkTexture *texture,
gdk_memory_convert (data, stride,
format,
color_space,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
texture->format,
gdk_texture_get_color_space (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
@@ -136,6 +140,9 @@ gdk_memory_sanitize (GBytes *bytes,
* The `GBytes` must contain @stride x @height pixels
* in the given format.
*
* This function calls [ctor@Gdk.MemoryTexture.new_with_color_profile]
* with the sRGB profile.
*
* Returns: A newly-created `GdkTexture`
*/
GdkTexture *
@@ -144,11 +151,51 @@ gdk_memory_texture_new (int width,
GdkMemoryFormat format,
GBytes *bytes,
gsize stride)
{
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
return gdk_memory_texture_new_with_color_space (width, height,
format,
gdk_color_space_get_srgb (),
bytes, stride);
}
/**
* gdk_memory_texture_new_with_color_space:
* @width: the width of the texture
* @height: the height of the texture
* @format: the format of the data
* @color_space: the color space for the pixels. The color space
* must be compatible with the format.
* @bytes: the `GBytes` containing the pixel data
* @stride: rowstride for the data
*
* Creates a new texture for a blob of image data.
*
* The `GBytes` must contain @stride x @height pixels
* in the given format.
*
* Returns: A newly-created `GdkTexture`
*
* Since: 4.6
*/
GdkTexture *
gdk_memory_texture_new_with_color_space (int width,
int height,
GdkMemoryFormat format,
GdkColorSpace *color_space,
GBytes *bytes,
gsize stride)
{
GdkMemoryTexture *self;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
g_return_val_if_fail (GDK_IS_COLOR_SPACE (color_space), NULL);
g_return_val_if_fail (gdk_color_space_supports_format (color_space, format), NULL);
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
@@ -157,6 +204,7 @@ gdk_memory_texture_new (int width,
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
"width", width,
"height", height,
"color-space", color_space,
NULL);
GDK_TEXTURE (self)->format = format;
@@ -189,11 +237,12 @@ gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
size = source->stride * (height - 1) + x * bpp;
bytes = g_bytes_new_from_bytes (source->bytes, offset, size);
result = gdk_memory_texture_new (texture->width,
texture->height,
texture->format,
bytes,
source->stride);
result = gdk_memory_texture_new_with_color_space (texture->width,
texture->height,
texture->format,
texture->color_space,
bytes,
source->stride);
g_bytes_unref (bytes);
return result;
@@ -201,7 +250,8 @@ gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
GdkMemoryTexture *
gdk_memory_texture_from_texture (GdkTexture *texture,
GdkMemoryFormat format)
GdkMemoryFormat format,
GdkColorSpace *color_space)
{
GdkTexture *result;
GBytes *bytes;
@@ -221,13 +271,14 @@ gdk_memory_texture_from_texture (GdkTexture *texture,
stride = texture->width * gdk_memory_format_bytes_per_pixel (format);
data = g_malloc_n (stride, texture->height);
gdk_texture_do_download (texture, format, data, stride);
gdk_texture_do_download (texture, format, color_space, data, stride);
bytes = g_bytes_new_take (data, stride);
result = gdk_memory_texture_new (texture->width,
texture->height,
format,
bytes,
stride);
result = gdk_memory_texture_new_with_color_space (texture->width,
texture->height,
format,
color_space,
bytes,
stride);
g_bytes_unref (bytes);
return GDK_MEMORY_TEXTURE (result);

View File

@@ -60,14 +60,21 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkMemoryTexture, g_object_unref)
GDK_AVAILABLE_IN_ALL
GType gdk_memory_texture_get_type (void) G_GNUC_CONST;
GType gdk_memory_texture_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GdkTexture * gdk_memory_texture_new (int width,
int height,
GdkMemoryFormat format,
GBytes *bytes,
gsize stride);
GdkTexture * gdk_memory_texture_new (int width,
int height,
GdkMemoryFormat format,
GBytes *bytes,
gsize stride);
GDK_AVAILABLE_IN_4_6
GdkTexture * gdk_memory_texture_new_with_color_space (int width,
int height,
GdkMemoryFormat format,
GdkColorSpace *color_space,
GBytes *bytes,
gsize stride);
G_END_DECLS

View File

@@ -30,7 +30,8 @@ G_BEGIN_DECLS
#define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8
GdkMemoryTexture * gdk_memory_texture_from_texture (GdkTexture *texture,
GdkMemoryFormat format);
GdkMemoryFormat format,
GdkColorSpace *color_space);
GdkTexture * gdk_memory_texture_new_subtexture (GdkMemoryTexture *texture,
int x,
int y,

View File

@@ -24,6 +24,7 @@
#include "gdkpixbuf.h"
#include "gdkcolorspace.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdksurface.h"
@@ -245,7 +246,8 @@ gdk_pixbuf_get_from_texture (GdkTexture *texture)
memtex = gdk_memory_texture_from_texture (texture,
alpha ? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE);
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
gdk_color_space_get_srgb ());
return gdk_pixbuf_new_from_data (gdk_memory_texture_get_data (memtex),
GDK_COLORSPACE_RGB,

View File

@@ -30,6 +30,7 @@
#include "gdksurface.h"
#include "gdk-private.h"
#include "gdkcolorspace.h"
#include "gdkcontentprovider.h"
#include "gdkdeviceprivate.h"
#include "gdkdisplayprivate.h"
@@ -74,6 +75,8 @@ struct _GdkSurfacePrivate
gboolean egl_surface_high_depth;
#endif
GdkColorSpace *color_space;
gpointer widget;
};
@@ -88,13 +91,14 @@ enum {
enum {
PROP_0,
PROP_COLOR_SPACE,
PROP_CURSOR,
PROP_DISPLAY,
PROP_FRAME_CLOCK,
PROP_MAPPED,
PROP_WIDTH,
PROP_HEIGHT,
PROP_MAPPED,
PROP_SCALE_FACTOR,
PROP_WIDTH,
LAST_PROP
};
@@ -476,7 +480,7 @@ gdk_surface_event_marshallerv (GClosure *closure,
static void
gdk_surface_init (GdkSurface *surface)
{
/* 0-initialization is good for all other fields. */
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (surface);
surface->state = 0;
surface->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
@@ -485,8 +489,10 @@ gdk_surface_init (GdkSurface *surface)
surface->alpha = 255;
priv->color_space = g_object_ref (gdk_color_space_get_srgb ());
surface->device_cursor = g_hash_table_new_full (NULL, NULL,
NULL, g_object_unref);
NULL, g_object_unref);
}
static void
@@ -500,6 +506,24 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
klass->beep = gdk_surface_real_beep;
/**
* GdkSurface:color-space: (attributes org.gtk.Property.get=gdk_surface_get_color_space)
*
* The color space for rendering to the surface
*
* This space is negotiated between GTK and the compositor.
*
* The color space may change as the surface gets moved around - for example to different
* monitors or when the compositor gets reconfigured. As long as the surface isn't shown,
* the color space may not represent the actual color space that is going to be used.
*/
properties[PROP_COLOR_SPACE] =
g_param_spec_object ("color-space",
P_("Color space"),
P_("The preferred color space of the surface"),
GDK_TYPE_COLOR_SPACE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GdkSurface:cursor: (attributes org.gtk.Property.get=gdk_surface_get_cursor org.gtk.Property.set=gdk_surface_set_cursor)
*
@@ -713,6 +737,7 @@ static void
gdk_surface_finalize (GObject *object)
{
GdkSurface *surface = GDK_SURFACE (object);
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (surface);
g_clear_handle_id (&surface->request_motion_id, g_source_remove);
@@ -729,6 +754,7 @@ gdk_surface_finalize (GObject *object)
g_clear_object (&surface->cursor);
g_clear_pointer (&surface->device_cursor, g_hash_table_destroy);
g_clear_pointer (&surface->devices_inside, g_list_free);
g_clear_object (&priv->color_space);
g_clear_object (&surface->display);
@@ -783,6 +809,10 @@ gdk_surface_get_property (GObject *object,
switch (prop_id)
{
case PROP_COLOR_SPACE:
g_value_set_object (value, gdk_surface_get_color_space (surface));
break;
case PROP_CURSOR:
g_value_set_object (value, gdk_surface_get_cursor (surface));
break;
@@ -2049,6 +2079,40 @@ gdk_surface_get_height (GdkSurface *surface)
return surface->height;
}
void
gdk_surface_set_color_space (GdkSurface *self,
GdkColorSpace *color_space)
{
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
if (gdk_color_space_equal (priv->color_space, color_space))
return;
g_set_object (&priv->color_space, color_space);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_SPACE]);
}
/**
* gdk_surface_get_color_space: (attributes org.gtk.Method.get_property=color-space)
* @self: a `GdkSurface`
*
* Returns the color space for rendering to the given @surface.
*
* Renderers will need to provide data in this color space.
*
* Returns: (transfer none): The color space of @surface
*/
GdkColorSpace *
gdk_surface_get_color_space (GdkSurface *self)
{
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
g_return_val_if_fail (GDK_IS_SURFACE (self), gdk_color_space_get_srgb ());
return priv->color_space;
}
/*
* gdk_surface_get_origin:
* @surface: a `GdkSurface`

View File

@@ -86,17 +86,19 @@ GDK_AVAILABLE_IN_ALL
GdkCursor *gdk_surface_get_device_cursor (GdkSurface *surface,
GdkDevice *device);
GDK_AVAILABLE_IN_ALL
int gdk_surface_get_width (GdkSurface *surface);
int gdk_surface_get_width (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
int gdk_surface_get_height (GdkSurface *surface);
int gdk_surface_get_height (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
gboolean gdk_surface_translate_coordinates (GdkSurface *from,
GdkSurface *to,
double *x,
double *y);
int gdk_surface_get_scale_factor (GdkSurface *surface);
GDK_AVAILABLE_IN_4_6
GdkColorSpace * gdk_surface_get_color_space (GdkSurface *self);
GDK_AVAILABLE_IN_ALL
gboolean gdk_surface_translate_coordinates (GdkSurface *from,
GdkSurface *to,
double *x,
double *y);
GDK_AVAILABLE_IN_ALL
int gdk_surface_get_scale_factor (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
gboolean gdk_surface_get_device_position (GdkSurface *surface,

View File

@@ -171,6 +171,8 @@ void gdk_surface_set_state (GdkSurface *surface,
void gdk_surface_set_is_mapped (GdkSurface *surface,
gboolean is_mapped);
void gdk_surface_set_color_space (GdkSurface *self,
GdkColorSpace *color_space);
GdkMonitor * gdk_surface_get_layout_monitor (GdkSurface *surface,
GdkPopupLayout *layout,

View File

@@ -31,6 +31,11 @@
* instance; you can only make a copy of it, via [method@Gdk.Texture.download]
* or [method@Gdk.Texture.download_float].
*
* A `GdkColorSpace` is part of every GdkTexture that describes the internal
* representation of the pixel data. This is most relevant when creating
* textures yourself as you can choose the color space you provide your
* pixel data in.
*
* `GdkTexture` is an immutable object: That means you cannot change
* anything about it other than increasing the reference count via
* g_object_ref().
@@ -40,6 +45,7 @@
#include "gdktextureprivate.h"
#include "gdkcolorspace.h"
#include "gdkintl.h"
#include "gdkmemorytextureprivate.h"
#include "gdkpaintable.h"
@@ -60,8 +66,9 @@ gtk_snapshot_append_texture (GdkSnapshot *snapshot,
enum {
PROP_0,
PROP_WIDTH,
PROP_COLOR_SPACE,
PROP_HEIGHT,
PROP_WIDTH,
N_PROPS
};
@@ -224,6 +231,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
static void
gdk_texture_default_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
@@ -240,14 +248,20 @@ gdk_texture_set_property (GObject *gobject,
switch (prop_id)
{
case PROP_WIDTH:
self->width = g_value_get_int (value);
case PROP_COLOR_SPACE:
self->color_space = g_value_dup_object (value);
if (self->color_space == NULL)
self->color_space = g_object_ref (gdk_color_space_get_srgb ());
break;
case PROP_HEIGHT:
self->height = g_value_get_int (value);
break;
case PROP_WIDTH:
self->width = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -264,14 +278,18 @@ gdk_texture_get_property (GObject *gobject,
switch (prop_id)
{
case PROP_WIDTH:
g_value_set_int (value, self->width);
case PROP_COLOR_SPACE:
g_value_set_object (value, self->color_space);
break;
case PROP_HEIGHT:
g_value_set_int (value, self->height);
break;
case PROP_WIDTH:
g_value_set_int (value, self->width);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -284,6 +302,7 @@ gdk_texture_dispose (GObject *object)
GdkTexture *self = GDK_TEXTURE (object);
gdk_texture_clear_render_data (self);
g_clear_object (&self->color_space);
G_OBJECT_CLASS (gdk_texture_parent_class)->dispose (object);
}
@@ -300,14 +319,31 @@ gdk_texture_class_init (GdkTextureClass *klass)
gobject_class->dispose = gdk_texture_dispose;
/**
* GdkTexture:width: (attributes org.gtk.Property.get=gdk_texture_get_width)
* GdkTexture:color-space: (attributes org.gtk.Property.get=gdk_texture_get_color_space)
*
* The width of the texture, in pixels.
* The color space associated with texture.
*
* Since: 4.6
*/
properties[PROP_WIDTH] =
g_param_spec_int ("width",
"Width",
"The width of the texture",
properties[PROP_COLOR_SPACE] =
g_param_spec_object ("color-space",
P_("Color Space"),
P_("The associated color space"),
GDK_TYPE_COLOR_SPACE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GdkTexture:height: (attributes org.gtk.Property.get=gdk_texture_get_height)
*
* The height of the texture, in pixels.
*/
properties[PROP_HEIGHT] =
g_param_spec_int ("height",
P_("Height"),
P_("The height of the texture"),
1,
G_MAXINT,
1,
@@ -317,14 +353,14 @@ gdk_texture_class_init (GdkTextureClass *klass)
G_PARAM_EXPLICIT_NOTIFY);
/**
* GdkTexture:height: (attributes org.gtk.Property.get=gdk_texture_get_height)
* GdkTexture:width: (attributes org.gtk.Property.get=gdk_texture_get_width)
*
* The height of the texture, in pixels.
* The width of the texture, in pixels.
*/
properties[PROP_HEIGHT] =
g_param_spec_int ("height",
"Height",
"The height of the texture",
properties[PROP_WIDTH] =
g_param_spec_int ("width",
P_("Width"),
P_("The width of the texture"),
1,
G_MAXINT,
1,
@@ -378,6 +414,30 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
return texture;
}
static GdkColorSpace*
gdk_color_space_get_from_pixbuf (GdkPixbuf *pixbuf)
{
const char *icc_profile_base64;
GdkColorSpace *space = NULL;
icc_profile_base64 = gdk_pixbuf_get_option (pixbuf, "icc-profile");
if (icc_profile_base64)
{
guchar *icc_data;
gsize icc_len;
GBytes *bytes;
icc_data = g_base64_decode (icc_profile_base64, &icc_len);
bytes = g_bytes_new_take (icc_data, icc_len);
space = gdk_color_space_new_from_icc_profile (bytes, NULL);
g_bytes_unref (bytes);
}
if (!space)
space = g_object_ref (gdk_color_space_get_srgb ());
return space;
}
/**
* gdk_texture_new_for_pixbuf:
* @pixbuf: a `GdkPixbuf`
@@ -395,23 +455,28 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
{
GdkTexture *texture;
GBytes *bytes;
GdkColorSpace *space;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
space = gdk_color_space_get_from_pixbuf (pixbuf);
bytes = g_bytes_new_with_free_func (gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_height (pixbuf)
* gdk_pixbuf_get_rowstride (pixbuf),
g_object_unref,
g_object_ref (pixbuf));
texture = gdk_memory_texture_new (gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
bytes,
gdk_pixbuf_get_rowstride (pixbuf));
texture = gdk_memory_texture_new_with_color_space (gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
space,
bytes,
gdk_pixbuf_get_rowstride (pixbuf));
g_bytes_unref (bytes);
g_object_unref (space);
return texture;
}
@@ -670,13 +735,32 @@ gdk_texture_get_height (GdkTexture *texture)
return texture->height;
}
/**
* gdk_texture_get_color_space: (attributes org.gtk.Method.get_property=color-space)
* @texture: a `GdkTexture`
*
* Returns the color space associated with @texture.
*
* Returns: (transfer none): the color space of the `GdkTexture`
*
* Since: 4.6
*/
GdkColorSpace *
gdk_texture_get_color_space (GdkTexture *texture)
{
g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0);
return texture->color_space;
}
void
gdk_texture_do_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data,stride);
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, color_space, data, stride);
}
cairo_surface_t *
@@ -717,6 +801,9 @@ gdk_texture_download_surface (GdkTexture *texture)
* %CAIRO_FORMAT_ARGB32, so every downloaded pixel requires
* 4 bytes of memory.
*
* The downloaded data will be in the sRGB color space, no matter the
* color space of the texture.
*
* Downloading a texture into a Cairo image surface:
* ```c
* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
@@ -739,6 +826,7 @@ gdk_texture_download (GdkTexture *texture,
gdk_texture_do_download (texture,
GDK_MEMORY_DEFAULT,
gdk_color_space_get_srgb (),
data,
stride);
}
@@ -758,6 +846,9 @@ gdk_texture_download (GdkTexture *texture,
* may need to be upsampled if it was not already available in this
* format.
*
* The downloaded data will be in the sRGB color space, no matter the
* color space of the texture.
*
* You may want to use [method@Gdk.Texture.download] instead if you don't
* need high dynamic range support.
*
@@ -781,6 +872,7 @@ gdk_texture_download_float (GdkTexture *texture,
gdk_texture_do_download (texture,
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
gdk_color_space_get_srgb (),
(guchar *) data,
stride);
}

View File

@@ -84,6 +84,8 @@ GDK_AVAILABLE_IN_ALL
int gdk_texture_get_width (GdkTexture *texture) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
int gdk_texture_get_height (GdkTexture *texture) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_6
GdkColorSpace * gdk_texture_get_color_space (GdkTexture *texture) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
void gdk_texture_download (GdkTexture *texture,

View File

@@ -18,6 +18,7 @@ struct _GdkTexture
GdkMemoryFormat format;
int width;
int height;
GdkColorSpace *color_space;
gpointer render_key;
gpointer render_data;
@@ -30,6 +31,7 @@ struct _GdkTextureClass {
/* mandatory: Download in the given format into data */
void (* download) (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride);
};
@@ -41,6 +43,7 @@ cairo_surface_t * gdk_texture_download_surface (GdkTexture
void gdk_texture_do_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride);
GdkMemoryFormat gdk_texture_get_format (GdkTexture *self);

View File

@@ -73,6 +73,8 @@ typedef cairo_rectangle_int_t GdkRectangle;
/* Forward declarations of commonly used types */
typedef struct _GdkRGBA GdkRGBA;
typedef struct _GdkColor GdkColor;
typedef struct _GdkColorSpace GdkColorSpace;
typedef struct _GdkContentFormats GdkContentFormats;
typedef struct _GdkContentProvider GdkContentProvider;
typedef struct _GdkCursor GdkCursor;

View File

@@ -19,9 +19,10 @@
#include "gdkjpegprivate.h"
#include "gdkcolorspace.h"
#include "gdkintl.h"
#include "gdktexture.h"
#include "gdkmemorytextureprivate.h"
#include "gdktexture.h"
#include "gdkprofilerprivate.h"
@@ -141,9 +142,12 @@ gdk_load_jpeg (GBytes *input_bytes,
guint width, height, stride;
unsigned char *data;
unsigned char *row[1];
JOCTET *icc_data;
unsigned int icc_len;
GBytes *bytes;
GdkTexture *texture;
GdkMemoryFormat format;
GdkColorSpace *space;
G_GNUC_UNUSED guint64 before = GDK_PROFILER_CURRENT_TIME;
info.err = jpeg_std_error (&jerr.pub);
@@ -163,6 +167,9 @@ gdk_load_jpeg (GBytes *input_bytes,
g_bytes_get_data (input_bytes, NULL),
g_bytes_get_size (input_bytes));
/* save color profile */
jpeg_save_markers (&info, JPEG_APP0 + 2, 0xFFFF);
jpeg_read_header (&info, TRUE);
jpeg_start_decompress (&info);
@@ -220,14 +227,31 @@ gdk_load_jpeg (GBytes *input_bytes,
g_assert_not_reached ();
}
if (jpeg_read_icc_profile (&info, &icc_data, &icc_len))
{
GBytes *icc_bytes = g_bytes_new_with_free_func (icc_data, icc_len, free, icc_data);
space = gdk_color_space_new_from_icc_profile (icc_bytes, error);
g_bytes_unref (icc_bytes);
}
else
space = g_object_ref (gdk_color_space_get_srgb ());
jpeg_finish_decompress (&info);
jpeg_destroy_decompress (&info);
bytes = g_bytes_new_take (data, stride * height);
texture = gdk_memory_texture_new (width, height,
format,
bytes, stride);
if (space)
{
texture = gdk_memory_texture_new_with_color_space (width, height,
format,
space,
bytes,
stride);
g_object_unref (space);
}
else
texture = NULL;
g_bytes_unref (bytes);
@@ -250,9 +274,12 @@ gdk_save_jpeg (GdkTexture *texture)
gsize texstride;
guchar *row;
int width, height;
GdkColorSpace *space;
GBytes *bytes;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
space = gdk_texture_get_color_space (texture);
info.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = fatal_error_handler;
@@ -280,13 +307,27 @@ gdk_save_jpeg (GdkTexture *texture)
jpeg_mem_dest (&info, &data, &size);
jpeg_start_compress (&info, TRUE);
bytes = gdk_color_space_save_to_icc_profile (space, NULL);
if (bytes != NULL)
{
jpeg_write_icc_profile (&info,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
g_bytes_unref (bytes);
}
else
{
space = gdk_color_space_get_srgb ();
}
memtex = gdk_memory_texture_from_texture (texture,
GDK_MEMORY_R8G8B8);
GDK_MEMORY_R8G8B8,
space);
texdata = gdk_memory_texture_get_data (memtex);
texstride = gdk_memory_texture_get_stride (memtex);
jpeg_start_compress (&info, TRUE);
while (info.next_scanline < info.image_height)
{
row = (guchar *) texdata + info.next_scanline * texstride;

View File

@@ -19,13 +19,15 @@
#include "gdkpngprivate.h"
#include "gdkcolorspace.h"
#include "gdkintl.h"
#include "gdklcmscolorspaceprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
#include "gdktexture.h"
#include "gdktextureprivate.h"
#include "gsk/gl/fp16private.h"
#include <png.h>
#include <stdio.h>
@@ -127,6 +129,102 @@ png_simple_warning_callback (png_structp png,
{
}
static GdkColorSpace *
gdk_png_get_color_space (png_struct *png,
png_info *info,
GError **error)
{
GdkColorSpace *space;
guchar *icc_data;
png_uint_32 icc_len;
char *name;
double gamma;
cmsCIExyY whitepoint;
cmsCIExyYTRIPLE primaries;
cmsToneCurve *curve;
cmsHPROFILE lcms_profile;
int intent;
if (png_get_iCCP (png, info, &name, NULL, &icc_data, &icc_len))
{
GBytes *bytes = g_bytes_new (icc_data, icc_len);
space = gdk_color_space_new_from_icc_profile (bytes, error);
g_bytes_unref (bytes);
return space;
}
if (png_get_sRGB (png, info, &intent))
return g_object_ref (gdk_color_space_get_srgb ());
/* If neither of those is valid, the result is sRGB */
if (!png_get_valid (png, info, PNG_INFO_gAMA) &&
!png_get_valid (png, info, PNG_INFO_cHRM))
return g_object_ref (gdk_color_space_get_srgb ());
if (!png_get_gAMA (png, info, &gamma))
gamma = 2.4;
if (!png_get_cHRM (png, info,
&whitepoint.x, &whitepoint.y,
&primaries.Red.x, &primaries.Red.y,
&primaries.Green.x, &primaries.Green.y,
&primaries.Blue.x, &primaries.Blue.y))
{
if (gamma == 2.4)
return g_object_ref (gdk_color_space_get_srgb ());
whitepoint = (cmsCIExyY) { 0.3127, 0.3290, 1.0 };
primaries = (cmsCIExyYTRIPLE) {
{ 0.6400, 0.3300, 1.0 },
{ 0.3000, 0.6000, 1.0 },
{ 0.1500, 0.0600, 1.0 }
};
}
else
{
primaries.Red.Y = 1.0;
primaries.Green.Y = 1.0;
primaries.Blue.Y = 1.0;
}
curve = cmsBuildGamma (NULL, 1.0 / gamma);
lcms_profile = cmsCreateRGBProfile (&whitepoint,
&primaries,
(cmsToneCurve*[3]) { curve, curve, curve });
space = gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
cmsFreeToneCurve (curve);
return space;
}
static gboolean
gdk_png_set_color_space (png_struct *png,
png_info *info,
GdkColorSpace *space)
{
/* FIXME: allow deconstructing RGB color spaces into gAMA and cHRM instead of
* falling back to iCCP */
if (space == gdk_color_space_get_srgb ())
{
png_set_sRGB_gAMA_and_cHRM (png, info, /* FIXME */ PNG_sRGB_INTENT_PERCEPTUAL);
return TRUE;
}
else
{
GBytes *bytes = gdk_color_space_save_to_icc_profile (space, NULL);
if (bytes == NULL)
return FALSE;
png_set_iCCP (png, info,
"ICC profile",
0,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
g_bytes_unref (bytes);
return TRUE;
}
}
/* }}} */
/* {{{ Public API */
@@ -144,6 +242,7 @@ gdk_load_png (GBytes *bytes,
guchar *buffer = NULL;
guchar **row_pointers = NULL;
GBytes *out_bytes;
GdkColorSpace *color_space;
GdkTexture *texture;
int bpp;
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
@@ -255,6 +354,13 @@ gdk_load_png (GBytes *bytes,
return NULL;
}
color_space = gdk_png_get_color_space (png, info, error);
if (color_space == NULL)
{
png_destroy_read_struct (&png, &info, NULL);
return NULL;
}
bpp = gdk_memory_format_bytes_per_pixel (format);
stride = width * bpp;
if (stride % 8)
@@ -265,6 +371,7 @@ gdk_load_png (GBytes *bytes,
if (!buffer || !row_pointers)
{
g_object_unref (color_space);
g_free (buffer);
g_free (row_pointers);
png_destroy_read_struct (&png, &info, NULL);
@@ -281,8 +388,12 @@ gdk_load_png (GBytes *bytes,
png_read_end (png, info);
out_bytes = g_bytes_new_take (buffer, height * stride);
texture = gdk_memory_texture_new (width, height, format, out_bytes, stride);
texture = gdk_memory_texture_new_with_color_space (width, height,
format,
color_space,
out_bytes, stride);
g_bytes_unref (out_bytes);
g_object_unref (color_space);
g_free (row_pointers);
png_destroy_read_struct (&png, &info, NULL);
@@ -309,12 +420,14 @@ gdk_save_png (GdkTexture *texture)
int y;
GdkMemoryTexture *memtex;
GdkMemoryFormat format;
GdkColorSpace *color_space;
int png_format;
int depth;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
format = gdk_texture_get_format (texture);
color_space = gdk_texture_get_color_space (texture);
switch (format)
{
@@ -385,7 +498,7 @@ gdk_save_png (GdkTexture *texture)
return NULL;
}
memtex = gdk_memory_texture_from_texture (texture, format);
memtex = gdk_memory_texture_from_texture (texture, format, gdk_color_space_get_srgb ());
if (sigsetjmp (png_jmpbuf (png), 1))
{
@@ -403,8 +516,13 @@ gdk_save_png (GdkTexture *texture)
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
if (!gdk_png_set_color_space (png, info, color_space))
color_space = gdk_color_space_get_srgb ();
png_write_info (png, info);
memtex = gdk_memory_texture_from_texture (texture, format, color_space);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
png_set_swap (png);
#endif

View File

@@ -19,6 +19,7 @@
#include "gdktiffprivate.h"
#include "gdkcolorspace.h"
#include "gdkintl.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
@@ -220,6 +221,49 @@ tiff_open_write (GBytes **result)
NULL, NULL);
}
/* }}} */
/* {{{ Color profile handling */
static GdkColorSpace *
gdk_tiff_get_color_space (TIFF *tiff,
GError **error)
{
const char *icc_data;
guint icc_len;
if (TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_len, &icc_data))
{
GBytes *icc_bytes;
GdkColorSpace *space;
icc_bytes = g_bytes_new (icc_data, icc_len);
space = gdk_color_space_new_from_icc_profile (icc_bytes, error);
g_bytes_unref (icc_bytes);
return space;
}
return g_object_ref (gdk_color_space_get_srgb ());
}
static gboolean
gdk_tiff_set_color_space (TIFF *tiff,
GdkColorSpace *space)
{
GBytes *bytes = gdk_color_space_save_to_icc_profile (space, NULL);
if (bytes == NULL)
return FALSE;
TIFFSetField (tiff, TIFFTAG_ICCPROFILE,
g_bytes_get_size (bytes),
g_bytes_get_data (bytes, NULL));
g_bytes_unref (bytes);
return TRUE;
}
/* }}} */
/* {{{ Public API */
@@ -266,12 +310,14 @@ gdk_save_tiff (GdkTexture *texture)
GBytes *result = NULL;
GdkMemoryTexture *memtex;
GdkMemoryFormat format;
GdkColorSpace *space;
const FormatData *fdata = NULL;
tif = tiff_open_write (&result);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
space = gdk_texture_get_color_space (texture);
format = gdk_texture_get_format (texture);
fdata = &format_data[format];
@@ -289,10 +335,15 @@ gdk_save_tiff (GdkTexture *texture)
if (fdata->alpha_samples)
TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, &fdata->alpha_samples);
if (!gdk_tiff_set_color_space (tif, space))
space = gdk_color_space_get_srgb ();
TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
memtex = gdk_memory_texture_from_texture (texture, fdata->format);
memtex = gdk_memory_texture_from_texture (texture,
fdata->format,
space);
data = gdk_memory_texture_get_data (memtex);
stride = gdk_memory_texture_get_stride (memtex);
@@ -320,8 +371,9 @@ gdk_save_tiff (GdkTexture *texture)
}
static GdkTexture *
load_fallback (TIFF *tif,
GError **error)
load_fallback (TIFF *tif,
GdkColorSpace *space,
GError **error)
{
int width, height;
guchar *data;
@@ -331,25 +383,36 @@ load_fallback (TIFF *tif,
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height);
data = g_malloc (width * height * 4);
data = g_try_malloc_n (width * 4, height);
if (data == NULL)
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_TOO_LARGE,
_("Not enough memory for image size %ux%u"), width, height);
g_object_unref (space);
return NULL;
}
if (!TIFFReadRGBAImageOriented (tif, width, height, (guint32 *)data, ORIENTATION_TOPLEFT, 1))
{
g_set_error_literal (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
_("Failed to load RGB data from TIFF file"));
g_object_unref (space);
g_free (data);
return NULL;
}
bytes = g_bytes_new_take (data, width * height * 4);
texture = gdk_memory_texture_new (width, height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
bytes,
width * 4);
texture = gdk_memory_texture_new_with_color_space (width, height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
space,
bytes,
width * 4);
g_bytes_unref (bytes);
g_object_unref (space);
return texture;
}
@@ -372,6 +435,7 @@ gdk_load_tiff (GBytes *input_bytes,
gsize stride;
int bpp;
GBytes *bytes;
GdkColorSpace *space;
GdkTexture *texture;
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
@@ -388,6 +452,13 @@ gdk_load_tiff (GBytes *input_bytes,
TIFFGetFieldDefaulted (tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetFieldDefaulted (tif, TIFFTAG_IMAGELENGTH, &height);
space = gdk_tiff_get_color_space (tif, error);
if (space == NULL)
{
TIFFClose (tif);
return NULL;
}
if (samples_per_pixel == 4)
{
guint16 extra;
@@ -400,7 +471,7 @@ gdk_load_tiff (GBytes *input_bytes,
if (alpha_samples != 0 && alpha_samples != EXTRASAMPLE_ASSOCALPHA && alpha_samples != EXTRASAMPLE_UNASSALPHA)
{
texture = load_fallback (tif, error);
texture = load_fallback (tif, space, error);
TIFFClose (tif);
return texture;
}
@@ -429,7 +500,7 @@ gdk_load_tiff (GBytes *input_bytes,
TIFFIsTiled (tif) ||
orientation != ORIENTATION_TOPLEFT)
{
texture = load_fallback (tif, error);
texture = load_fallback (tif, space, error);
TIFFClose (tif);
return texture;
}
@@ -467,10 +538,11 @@ gdk_load_tiff (GBytes *input_bytes,
bpp = gdk_memory_format_bytes_per_pixel (format);
bytes = g_bytes_new_take (data, width * height * bpp);
texture = gdk_memory_texture_new (width, height,
format,
bytes, width * bpp);
texture = gdk_memory_texture_new_with_color_space (width, height,
format, space,
bytes, width * bpp);
g_bytes_unref (bytes);
g_object_unref (space);
TIFFClose (tif);

View File

@@ -4,6 +4,8 @@ gdk_public_sources = files([
'gdkcairo.c',
'gdkcairocontext.c',
'gdkclipboard.c',
'gdkcolor.c',
'gdkcolorspace.c',
'gdkcontentdeserializer.c',
'gdkcontentformats.c',
'gdkcontentprovider.c',
@@ -30,6 +32,7 @@ gdk_public_sources = files([
'gdkhsla.c',
'gdkkeys.c',
'gdkkeyuni.c',
'gdklcmscolorspace.c',
'gdkmemoryformat.c',
'gdkmemorytexture.c',
'gdkmonitor.c',
@@ -64,6 +67,8 @@ gdk_public_headers = files([
'gdkcairo.h',
'gdkcairocontext.h',
'gdkclipboard.h',
'gdkcolor.h',
'gdkcolorspace.h',
'gdkcontentdeserializer.h',
'gdkcontentformats.h',
'gdkcontentprovider.h',
@@ -205,6 +210,7 @@ gdk_deps = [
fontconfig_dep,
platform_gio_dep,
pangocairo_dep,
lcms2_dep,
vulkan_dep,
png_dep,
tiff_dep,

View File

@@ -1403,6 +1403,71 @@ gdk_x11_display_init_leader_surface (GdkX11Display *self)
self->leader_window_title_set = FALSE;
}
static void
voidXFree (gpointer data)
{
XFree (data);
}
static void
gdk_x11_display_check_color_space (GdkX11Display *self)
{
GdkDisplay *display = GDK_DISPLAY (self);
GdkX11Screen *screen;
char *atom_name;
Atom type;
int result;
int format;
gulong nitems;
gulong bytes_after;
guchar *data;
GBytes *bytes;
screen = self->screen;
if (screen->screen_num > 0)
atom_name = g_strdup_printf ("_ICC_PROFILE_%d", screen->screen_num);
else
atom_name = g_strdup ("_ICC_PROFILE");
g_clear_object (&self->color_space);
self->color_space = g_object_ref (gdk_color_space_get_srgb ());
gdk_x11_display_error_trap_push (display);
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
screen->xroot_window,
gdk_x11_get_xatom_by_name_for_display (display, atom_name),
0, G_MAXLONG, False, XA_CARDINAL, &type,
&format, &nitems,
&bytes_after, &data);
gdk_x11_display_error_trap_pop_ignored (display);
g_free (atom_name);
if (result != Success || type != XA_CARDINAL || nitems <= 0)
return;
switch (format)
{
case 8:
bytes = g_bytes_new_with_free_func (data, nitems, voidXFree, data);
break;
case 16:
bytes = g_bytes_new_with_free_func (data, sizeof (short) * nitems, voidXFree, data);
break;
case 32:
bytes = g_bytes_new_with_free_func (data, sizeof (long) * nitems, voidXFree, data);
break;
default:
XFree (data);
return;
}
g_clear_object (&self->color_space);
self->color_space = gdk_color_space_new_from_icc_profile (bytes, NULL);
if (!self->color_space)
self->color_space = g_object_ref (gdk_color_space_get_srgb ());
}
/**
* gdk_x11_display_open:
* @display_name: (nullable): name of the X display.
@@ -1470,6 +1535,9 @@ gdk_x11_display_open (const char *display_name)
/* initialize the display's screens */
display_x11->screen = _gdk_x11_screen_new (display, DefaultScreen (display_x11->xdisplay));
/* We want this for the leader surface already */
gdk_x11_display_check_color_space (display_x11);
/* If GL is available we want to pick better default/rgba visuals,
* as we care about GLX details such as alpha/depth/stencil depth,
* stereo and double buffering
@@ -1915,15 +1983,17 @@ gdk_x11_display_ungrab (GdkDisplay *display)
static void
gdk_x11_display_dispose (GObject *object)
{
GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
GdkX11Display *self = GDK_X11_DISPLAY (object);
if (display_x11->event_source)
if (self->event_source)
{
g_source_destroy (display_x11->event_source);
g_source_unref (display_x11->event_source);
display_x11->event_source = NULL;
g_source_destroy (self->event_source);
g_source_unref (self->event_source);
self->event_source = NULL;
}
g_clear_object (&self->color_space);
G_OBJECT_CLASS (gdk_x11_display_parent_class)->dispose (object);
}

View File

@@ -128,6 +128,9 @@ struct _GdkX11Display
guint have_damage;
#endif
/* Stored in the ICC_PROFILE rootwindow prop */
GdkColorSpace *color_space;
/* If GL is not supported, store the error here */
GError *gl_error;

View File

@@ -1011,6 +1011,8 @@ setup_toplevel_window (GdkSurface *surface,
/* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
gdk_surface_set_color_space (surface, GDK_X11_DISPLAY (display)->color_space);
if (!gdk_running_in_sandbox ())
{

View File

@@ -1381,7 +1381,7 @@ gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self,
}
}
memtex = gdk_memory_texture_from_texture (texture, data_format);
memtex = gdk_memory_texture_from_texture (texture, data_format, gdk_color_space_get_srgb ());
data = gdk_memory_texture_get_data (memtex);
stride = gdk_memory_texture_get_stride (memtex);
bpp = gdk_memory_format_bytes_per_pixel (data_format);

View File

@@ -774,10 +774,6 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
/* A GL texture from the same GL context is a simple task... */
return gdk_gl_texture_get_id (gl_texture);
}
else
{
downloaded_texture = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
}
}
else
{
@@ -786,10 +782,12 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
if (t->min_filter == min_filter && t->mag_filter == mag_filter)
return t->texture_id;
}
downloaded_texture = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
}
downloaded_texture = gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture),
gdk_texture_get_color_space (texture));
/* The download_texture() call may have switched the GL context. Make sure
* the right context is at work again. */
gdk_gl_context_make_current (context);
@@ -1251,7 +1249,8 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
n_slices = cols * rows;
slices = g_new0 (GskGLTextureSlice, n_slices);
memtex = gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture));
gdk_texture_get_format (texture),
gdk_texture_get_color_space (texture));
for (guint col = 0; col < cols; col ++)
{

View File

@@ -238,9 +238,11 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
gdk_memory_convert (pixel_data,
width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
gdk_color_space_get_srgb (),
cairo_image_surface_get_data (surface),
width * 4,
GDK_MEMORY_DEFAULT,
gdk_color_space_get_srgb (),
width, height);
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;

View File

@@ -20,6 +20,7 @@
#include "config.h"
#include <gdk/gdkcolorspace.h>
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkprofilerprivate.h>
@@ -116,8 +117,11 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
gdk_color_space_get_srgb (),
surface_data, cairo_image_surface_get_stride (surface),
GDK_MEMORY_DEFAULT, width, height);
GDK_MEMORY_DEFAULT,
gdk_color_space_get_srgb (),
width, height);
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
}

View File

@@ -16,6 +16,7 @@ fribidi_req = '>= 0.19.7'
cairo_req = '>= 1.14.0'
gdk_pixbuf_req = '>= 2.30.0'
introspection_req = '>= 1.39.0'
lcms2_req = '>= 2.8'
wayland_proto_req = '>= 1.21'
wayland_req = '>= 1.16.91'
graphene_req = '>= 1.9.1'
@@ -379,6 +380,8 @@ pango_dep = dependency('pango', version: pango_req,
fallback : ['pango', 'libpango_dep'])
fribidi_dep = dependency('fribidi', version: fribidi_req,
fallback : ['fribidi', 'libfribidi_dep'])
lcms2_dep = dependency('lcms2', version: lcms2_req,
fallback : ['lcms2', 'liblcms2_dep'])
# Require PangoFT2 if on X11 or wayland
require_pangoft2 = wayland_enabled or x11_enabled

6
subprojects/lcms2.wrap Normal file
View File

@@ -0,0 +1,6 @@
[wrap-git]
directory=lcms2
url=https://github.com/mm2/Little-CMS.git
revision=master
patch_directory=lcms2
depth=1

View File

@@ -0,0 +1,14 @@
project('lcms2', 'c',
version : '2.12',
meson_version : '>=0.56.0',
)
mod = import('unstable_external_project')
p = mod.add_project('configure',
configure_options : ['--prefix=@PREFIX@',
'--libdir=@PREFIX@/@LIBDIR@',
],
)
liblcms2_dep = p.dependency('lcms2')