removed CUPS printer name handling in the XCPD CM API
[google-summer-of-code-2011:xcpd.git] / src / components / library / xcpdcm.c
1 /*
2  * Copyright (C) 2011 Joseph Simon <jsimon383@gmail.com.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include <string.h>
22
23 #include "xcpdcm.h"
24
25 #include "xcpdcm_selector.h"
26 #include "xcpdcm_renderer.h"
27
28 #define EMPTY_PROFILE "none"
29
30 #define PROFILE_FOUND 1
31
32
33 /*  Return an initialized XCPD CM object.  */
34 xcpd_cm_t* 
35 xcpdCM_initialize(void)
36 {
37   
38     xcpd_cm_t* cm_object;    
39     cm_object = (xcpd_cm_t*)malloc(sizeof(xcpd_cm_t));  
40     
41     if(cm_object) {        
42       cm_object->profile_path = 0;
43       cm_object->pdf_filename = 0;
44     }
45     else {
46       return 0; 
47     }           
48      
49     cm_object->spoolfile_ready = 0;
50     cm_object->profile_set = 0;
51       
52     return cm_object;     
53 }
54
55
56 /*   Sets the PDF for the XCPD CM object.  */
57 int   
58 xcpdCM_setPdfFile(const char* pdf_filename, xcpd_cm_t* cm_obj)
59 {    
60   
61     int error = 0;
62     
63     if (pdf_filename == 0 ||
64         cm_obj == NULL)
65       error = 1;
66     
67     if (!cm_obj->pdf_filename)
68       cm_obj->pdf_filename = (char*)malloc(XCPD_FILENAME_MAX);
69     
70     strncpy(cm_obj->pdf_filename, pdf_filename, XCPD_FILENAME_MAX);  
71     cm_obj->pdf_filename[XCPD_FILENAME_MAX-1] = '\0';
72     
73     /* If a PDF has previously been rendered, 
74        we reset the 'spool flag'.            */
75     if (cm_obj->spoolfile_ready && !error) {      
76       cm_obj->spoolfile_ready = 0;              
77     }
78     
79     return error;
80 }
81
82 /*   Set the profile path and mark the 'profile set' flag.  */
83 int 
84 xcpdCM_setProfile(const char* profile_filename, xcpd_cm_t* cm_obj)
85 {
86   
87     if (profile_filename == 0 ||
88         cm_obj == NULL)      
89       return 1;
90     
91     if(cm_obj->profile_path == 0)
92       cm_obj->profile_path = (char*)malloc(XCPD_FILENAME_MAX);
93     
94     strncpy(cm_obj->profile_path, profile_filename, XCPD_FILENAME_MAX);
95     cm_obj->profile_path[XCPD_FILENAME_MAX-1] = '\0';
96     
97     cm_obj->profile_set = 1;
98 }
99
100
101 /*   Get the PDF file path.  */
102 char* 
103 xcpdCM_getPdfFile(xcpd_cm_t* cm_obj)
104 {
105   
106     char* pdf_path = 0;
107     
108     if(cm_obj->pdf_filename)
109       pdf_path = malloc(XCPD_FILENAME_MAX);  
110     
111     if(!pdf_path || cm_obj->pdf_filename == 0)
112       return 0;
113     
114     strncpy(pdf_path, cm_obj->pdf_filename, XCPD_FILENAME_MAX);
115     pdf_path[XCPD_FILENAME_MAX-1] = '\0';
116   
117     return pdf_path;
118 }
119
120 /*   Get the profile name as a path.  */
121 char* 
122 xcpdCM_getProfile(xcpd_cm_t* cm_obj)
123 {
124   
125     char* profile_string = 0;
126     
127     if(cm_obj->profile_path)
128       profile_string = malloc(XCPD_FILENAME_MAX);  
129         
130     if(!profile_string || cm_obj->profile_path == 0)
131       return 0;
132     
133     strncpy(profile_string, cm_obj->profile_path, XCPD_FILENAME_MAX);
134     profile_string[XCPD_FILENAME_MAX-1] = '\0';
135
136     return profile_string; 
137 }
138
139
140
141     /* NOTE The following code will be used if ICC Selection
142             Options are included in the PPD itself. It is 
143             commented out for now.*/
144     
145 /* ***********************************************************************
146  *       xcpdCM_setProfileFromPPD      (For ICC profile selection.)      *   
147  *************************************************************************
148
149      AUTHOR: Joseph Simon
150      INPUT:  xcpd_cm_t* (XCPD CM object)
151      OUTPUT: xcpdcm_sstatus_t (Selector result)
152              ppd_file_t* (Modified PPD)
153
154      PRE-CONDITION: The user must specify an ICC selection option in the 
155                     print dialog's GUI, which is marked in an internal
156                     
157      POST-CONDITION: Profile path saved in the XCPD CM object and the 
158                      PPD option choices stripped to highlight a 
159                      recommended choice.
160                                               
161      DESCRIPTION:
162      
163          This function handles the profile-selection/calibration part of 
164      the XCPD.  It requires the user specify an 'ICC selection mode' option 
165      in the GUI, which are stored internally inside a static PPD.  The options 
166      are thus marked from the GUI and brought into XCPD CM Selector Module using
167      the following 'get' functions in this sequence*:
168      
169          getUserProfile(&profile, ppd)
170          getSystemProfile(...)
171          getPPDAutoProfile(...)
172          getCUPSFallbackProfile(...)
173          getDefaultProfile(...)
174          
175          If an appropriate PPD option is found in one of the functions, or if a 
176      fallback profile is found, the XCPD CM Selector 'get' functions will 
177      process the calibration algorithms appropriate to the user's selection in 
178      the UI. Upon success of one of the 'get' functions, a profile path will be 
179      stored in an XCPD CM object, which can then be used to process a spool-ready
180      PDF file (see xcpdCM_setSpoolPdf()).
181          An adjusted PPD configuration will be returned to the calling program 
182      for all options except "Automatic Selection".  This adjusted PPD will only 
183      contain a single choice for an option, matching the parameters for the 
184      calibrated profile,
185          Finally, an XCPD CM Selector status value is also returned to inform
186      the calling program of the function's result.
187      
188      
189      *Oyranos/CUPS Profile Selection Reference:
190      www.oyranos.org/wiki/index.php?title=Device_Settings#Profile_Selection
191      
192      
193 */    
194 #if 0
195 xcpdcm_sstatus_t    
196 xcpdCM_setProfileFromPPD (xcpd_cm_t* cm_obj, ppd_file_t* ppd)
197 {
198   
199     xcpdcm_sstatus_t result;
200
201     char* profile = 0;
202
203     if(!ppd)
204       return XCPDCM_SELECTOR_INVALID_PPD;   
205
206     if (getUserProfile(&profile, ppd)) {
207         result = XCPDCM_SELECTOR_USERPROFILE_SET;
208
209     } else if (getSystemProfile(&profile, ppd)) {
210         result = XCPDCM_SELECTOR_SYSTEMPROFILE_SET;
211
212     } else if (getPPDAutoProfile(&profile,  ppd)) {
213         result = XCPDCM_SELECTOR_AUTOPROFILE_SET;
214
215     } else if (getCUPSFallbackProfile(&profile, ppd)) {
216         result = XCPDCM_SELECTOR_CUPSFALLBACK_SET;
217
218     } else if (getDefaultProfile(&profile, ppd)) {
219         result = XCPDCM_SELECTOR_OYDEFAULT_SET;
220
221     } else {        
222         return XCPDCM_SELECTOR_NOPROFILE;
223     }
224
225     strncpy(cm_obj->profile_path, profile, XCPD_FILENAME_MAX);
226     cm_obj->profile_path[XCPD_FILENAME_MAX-1] = '\0';
227     
228     cm_obj->profile_set = 1;
229
230     free(profile);
231         
232     return result;      
233 }
234
235 #endif
236
237
238
239 /*  This code is similiar to the above xcpdCM_setProfileFromPPD() function,
240     but requires an extra 'selector mode' argument that will explicitly set
241     the appropriate XCPD CM Selector calls.                               
242     */
243 xcpdcm_sstatus_t    
244 xcpdCM_setProfileFromPPD2 (xcpd_cm_t* cm_obj, 
245                           ppd_file_t* ppd, 
246                           xcpdcm_selectormode_t mode) 
247                           /* 'mode' is used in place of PPD ICC Options */
248 {
249     
250     xcpdcm_sstatus_t result;
251
252     char* profile = 0;
253
254     if(!ppd)
255       return XCPDCM_SELECTOR_INVALID_PPD;    
256     
257     if(cm_obj->profile_path == 0)
258       cm_obj->profile_path = (char*)malloc(XCPD_FILENAME_MAX);
259
260     /* Begin profile-selection workflow */
261     
262     switch(mode)
263     {
264       case XCPDCM_USERSELECT_MODE:
265          profile = xcpdCM_getProfile(cm_obj);
266          cm_obj->profile_set = 1; 
267
268          if(getUserProfile2(profile, ppd))
269             result = XCPDCM_SELECTOR_USERPROFILE_SET;
270          break;
271       case XCPDCM_SYSTEMSELECT_MODE:
272          puts("**XCPD API** -- SYSTEM/APPLICATION SETTINGS NOT AVAILABLE");
273          /*if(getSystemProfile(&profile, ppd))*/
274             result = XCPDCM_SELECTOR_SYSTEMPROFILE_SET;
275          break;
276       case XCPDCM_AUTOSELECT_MODE:
277          if(getPPDAutoProfile(&profile, ppd))
278             result = XCPDCM_SELECTOR_AUTOPROFILE_SET;
279          break;
280     }
281     
282     if(!profile){
283        if (getCUPSFallbackProfile(&profile, ppd)) 
284          result = XCPDCM_SELECTOR_CUPSFALLBACK_SET;
285        else if (getDefaultProfile(&profile, ppd)) 
286          result = XCPDCM_SELECTOR_OYDEFAULT_SET;
287        else 
288         result = XCPDCM_SELECTOR_NOPROFILE;  
289     }
290     
291     if (result != XCPDCM_SELECTOR_NOPROFILE ||
292         result != XCPDCM_SELECTOR_USERPROFILE_SET){
293        cm_obj->profile_set = 1; 
294     
295        strncpy(cm_obj->profile_path, profile, XCPD_FILENAME_MAX);
296        cm_obj->profile_path[XCPD_FILENAME_MAX-1] = '\0';
297     }
298
299     if(profile) free(profile);
300         
301     return result;      
302 }
303
304
305
306 /* ***********************************************************************
307  *       xcpdCM_setSpoolPdf            (For local PDF spool file prep.)  *   
308  *************************************************************************
309
310      AUTHOR: Joseph Simon
311      INPUT:  xcpd_cm_t* (XCPD CM object)
312      OUTPUT: xcpdcm_rstatus_t  (Rendering result)             
313
314      PRE-CONDITION: A PDF file must be specified in the XCPD CM object
315                     prior to using this function.
316      POST-CONDITION: Spool-ready PDF file set.
317                                               
318      DESCRIPTION           
319      
320         This function will prepare a spool-ready, color-managed PDF file.  
321      It requires the user to have a PDF file - as well as a CPD-designated 
322      profile - setup within the XCPD CM object.  The object's "spool file set"
323      flag will be raised if the function can successfully check/generate
324      a PDF based on the color management workflow.
325         The XCPD Renderer Module provides the necessary functions for
326      'setSpoolPdf' to check if a PDF has an output intent, tag the PDF's
327      colorspace, and generate a PDF-X file to embed a user-selected 
328      ICC profile.  
329         An 'xcpdcm_rstatus_t enumeration value will be returned to inform the 
330      caller of the result of the spool file generation.  The values are 
331      as follows:
332      
333           XCPDCM_PDF_NEWPROFILE_EMBEDDED = Generated PDF/X File with 
334                                            embedded profile.
335                  XCPDCM_PDF_INVALID_FILE = Error - Invalid PDF file.
336           XCPDCM_PDF_OUTPUTINTENT_EXISTS = OutputIntent already exists.
337                XCPDCM_PDF_COLORSPACE_SET = Tagged assumed profile colorspace.
338         
339         If an output intent is not available, and an ICC profile was specified
340      by the user, 'setSpoolPdf' will generate a PDF/X file which will include 
341      that profile as its output intent.  The XCPD CM object will thus be 
342      updated to point to the new PDF file and returned to the user.
343      
344 */
345 xcpdcm_rstatus_t   
346 xcpdCM_setSpoolPdf(xcpd_cm_t* cm_obj, int rendermode)
347 {
348     
349     int error = 0;
350     int output_intent_flag = 0;    
351     char *pdf_file = 0, 
352          *profile = 0, 
353          *pdfx_skeleton = 0;  
354     
355     pdf_file = malloc(XCPD_FILENAME_MAX);    
356     strncpy(pdf_file, cm_obj->pdf_filename, XCPD_FILENAME_MAX);    
357     pdf_file[XCPD_FILENAME_MAX-1] = '\0';
358     
359     /**** 1. CHECK FOR VALID OUTPUT INTENT  *****/    
360     output_intent_flag = checkOutputIntent( pdf_file );
361     
362     if (output_intent_flag < 0) {
363       return XCPDCM_PDF_INVALID_FILE;
364     }
365     else if (output_intent_flag) {
366       cm_obj->spoolfile_ready = 1;      
367       return XCPDCM_PDF_OUTPUTINTENT_EXISTS;       
368     }    
369
370     /* FIXME Internal DefaultRGB tagging needs some fixing. */
371     /**** 2.  TAG PDF WITH DEFAULT COLORSPACE *****/           
372     /*error = tagPdfColorspace( pdf_file );  */
373     
374     profile = malloc(XCPD_FILENAME_MAX);    
375     strncpy(profile, cm_obj->profile_path, XCPD_FILENAME_MAX);     
376     profile[XCPD_FILENAME_MAX-1] = '\0';
377
378     /**** 3.  CHECK FOR VALID ICC PROFILE  *****/    
379     /* We leave gracefully if a user-profile is not found.*/
380     if (strcmp(profile, EMPTY_PROFILE) == 0 ||
381         strcmp(profile, "") == 0 || 
382         profile == 0)  {      
383       cm_obj->spoolfile_ready = 1;
384     
385       return XCPDCM_PDF_COLORSPACE_SET;      
386     }    
387     
388     
389     /**** 4.  STORE PROFILE IN PDFX OUTPUT INTENT  *****/    
390     pdfx_skeleton = malloc(30);
391     error = createPdfxSkeleton( profile, &pdfx_skeleton, 0, 0);
392  
393     if(!error) {  
394       const char* new_pdf = createOutputIntentPdf( pdfx_skeleton, 
395                                                    pdf_file, 
396                                                    profile );
397       if (new_pdf) {
398         strncpy(cm_obj->pdf_filename, new_pdf, XCPD_FILENAME_MAX);
399         cm_obj->pdf_filename[XCPD_FILENAME_MAX-1] = '\0';
400       }
401     }
402     else {      
403        remove(pdfx_skeleton);            
404        free(pdfx_skeleton);
405       
406        cm_obj->spoolfile_ready = 1;
407       
408        return XCPDCM_PDF_INVALID_FILE;
409     }
410     
411     remove(pdfx_skeleton);
412     free(pdfx_skeleton);
413
414     return XCPDCM_PDF_NEWPROFILE_EMBEDDED;
415 }
416
417
418 /* Ask for status of the spool file.*/
419 int   
420 xcpdCM_isPDFReady (xcpd_cm_t* cm_obj)
421 {
422     return cm_obj->spoolfile_ready;
423 }
424
425
426 /* Deallocates an XCPD CM object.*/
427 void  
428 xcpdCM_close (xcpd_cm_t* cm_object)
429 {
430   
431     if(cm_object->profile_path)
432       free(cm_object->profile_path);
433     
434     if(cm_object->pdf_filename)
435       free(cm_object->pdf_filename);    
436     
437     if(cm_object->ppd_filename)
438       free(cm_object->ppd_filename);  
439     
440     cm_object->profile_path = 0;
441     cm_object->pdf_filename = 0;
442     cm_object->ppd_filename = 0;
443     
444     free(cm_object);  
445 }
446