1 /* Load profiles as blobs.
2 *
3 * 10/1/19
4 * - from CMYK2XYZ.c
5 */
6
7 /*
8
9 This file is part of VIPS.
10
11 VIPS is free software; you can redistribute it and/or modify
12 it under the terms of the GNU Lesser General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301 USA
25
26 */
27
28 /*
29
30 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
31
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif /*HAVE_CONFIG_H*/
37 #include <vips/intl.h>
38
39 #include <vips/vips.h>
40
41 #include <stdio.h>
42 #include <math.h>
43
44 #include <vips/internal.h>
45
46 #include "profiles.h"
47 #include "pcolour.h"
48
49 typedef struct _VipsProfileLoad {
50 VipsOperation parent_instance;
51
52 const char *name;
53 VipsBlob *profile;
54
55 } VipsProfileLoad;
56
57 typedef VipsOperationClass VipsProfileLoadClass;
58
59 G_DEFINE_TYPE( VipsProfileLoad, vips_profile_load, VIPS_TYPE_OPERATION );
60
61 static const void *
vips_profile_fallback_get(const char * name,size_t * length)62 vips_profile_fallback_get( const char *name, size_t *length )
63 {
64 int i;
65 VipsProfileFallback *fallback;
66
67 for( i = 0; (fallback = vips__profile_fallback_table[i]); i++ )
68 if( g_ascii_strcasecmp( fallback->name, name ) == 0 ) {
69 void *data;
70 GConverter *converter;
71 GConverterResult res;
72 gsize bytes_read;
73 gsize bytes_written;
74
75 data = g_malloc0( fallback->length );
76 converter = G_CONVERTER( g_zlib_decompressor_new(
77 G_ZLIB_COMPRESSOR_FORMAT_ZLIB ) );
78
79 res = g_converter_convert( converter,
80 fallback->data, fallback->length,
81 data, fallback->length,
82 G_CONVERTER_INPUT_AT_END,
83 &bytes_read, &bytes_written, NULL );
84 g_object_unref( converter );
85
86 if( res == G_CONVERTER_FINISHED ) {
87 *length = fallback->length;
88 return( data );
89 } else {
90 g_free( data );
91 g_warning( "fallback profile "
92 "decompression failed" );
93 }
94 }
95
96 return( NULL );
97 }
98
99 static int
vips_profile_load_build(VipsObject * object)100 vips_profile_load_build( VipsObject *object )
101 {
102 VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
103 VipsProfileLoad *load = (VipsProfileLoad *) object;
104
105 size_t length;
106 const void *data;
107 VipsBlob *profile;
108
109 if( VIPS_OBJECT_CLASS( vips_profile_load_parent_class )->
110 build( object ) )
111 return( -1 );
112
113 if( g_ascii_strcasecmp( load->name, "none" ) == 0 )
114 profile = NULL;
115 else if( (data = vips_profile_fallback_get( load->name, &length )) )
116 profile = vips_blob_new(
117 (VipsCallbackFn) vips_area_free_cb, data, length );
118 else if( (data = vips__file_read_name( load->name,
119 vips__icc_dir(), &length )) )
120 profile = vips_blob_new(
121 (VipsCallbackFn) vips_area_free_cb, data, length );
122 else {
123 vips_error( class->nickname,
124 _( "unable to load profile \"%s\"" ), load->name );
125 return( -1 );
126 }
127
128 g_object_set( object, "profile", profile, NULL );
129
130 if( profile ) {
131 vips_area_unref( (VipsArea *) profile );
132 profile = NULL;
133 }
134
135 return( 0 );
136 }
137
138 static void
vips_profile_load_class_init(VipsProfileLoadClass * class)139 vips_profile_load_class_init( VipsProfileLoadClass *class )
140 {
141 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
142 VipsObjectClass *object_class = (VipsObjectClass *) class;
143
144 gobject_class->set_property = vips_object_set_property;
145 gobject_class->get_property = vips_object_get_property;
146
147 object_class->nickname = "profile_load";
148 object_class->description = _( "load named ICC profile" );
149 object_class->build = vips_profile_load_build;
150
151 VIPS_ARG_STRING( class, "name", 1,
152 _( "Name" ),
153 _( "Profile name" ),
154 VIPS_ARGUMENT_REQUIRED_INPUT,
155 G_STRUCT_OFFSET( VipsProfileLoad, name ),
156 NULL );
157
158 VIPS_ARG_BOXED( class, "profile", 2,
159 _( "Profile" ),
160 _( "Loaded profile" ),
161 VIPS_ARGUMENT_REQUIRED_OUTPUT,
162 G_STRUCT_OFFSET( VipsProfileLoad, profile ),
163 VIPS_TYPE_BLOB );
164
165 }
166
167 static void
vips_profile_load_init(VipsProfileLoad * load)168 vips_profile_load_init( VipsProfileLoad *load )
169 {
170 }
171
172 /**
173 * vips_profile_load:
174 * @name: name of profile to load
175 * @profile: (out): loaded profile
176 * @...: %NULL-terminated list of optional named arguments
177 *
178 * Load a named profile.
179 *
180 * Profiles are loaded from four sources:
181 *
182 * - The special name `"none"` means no profile. @profile will be %NULL in this
183 * case.
184 *
185 * - @name can be the name of one of the ICC profiles embedded in libvips.
186 * These names can be at least `"cmyk"`, `"p3"` and `"srgb"`.
187 *
188 * - @name can be the full path to a file.
189 *
190 * - @name can be the name of an ICC profile in the system profile directory
191 * for your platform.
192 *
193 * Returns: 0 on success, -1 on error
194 */
195 int
vips_profile_load(const char * name,VipsBlob ** profile,...)196 vips_profile_load( const char *name, VipsBlob **profile, ... )
197 {
198 va_list ap;
199 int result;
200
201 va_start( ap, profile );
202 result = vips_call_split( "profile_load", ap, name, profile );
203 va_end( ap );
204
205 return( result );
206 }
207
208 /* Set (or remove) a named profile on an image.
209 */
210 int
vips__profile_set(VipsImage * image,const char * name)211 vips__profile_set( VipsImage *image, const char *name )
212 {
213 VipsBlob *profile;
214
215 if( vips_profile_load( name, &profile, NULL ) )
216 return( -1 );
217
218 if( profile ) {
219 GValue value = { 0 };
220
221 g_value_init( &value, VIPS_TYPE_BLOB );
222 g_value_set_boxed( &value, profile );
223 vips_image_set( image, VIPS_META_ICC_NAME, &value );
224 g_value_unset( &value );
225 }
226 else
227 vips_image_remove( image, VIPS_META_ICC_NAME );
228
229 if( profile ) {
230 vips_area_unref( (VipsArea *) profile );
231 profile = NULL;
232 }
233
234 return( 0 );
235 }
236