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