1 #include <cups/cups.h>
2 #include <cups/ppd.h>
3 #include <string>
4 #include <stdio.h>
5 #include <map>
6 #include <cairo/cairo.h>
7 #include <exception>
8 #include <math.h>
9 #include "CairoUtils.h"
10 
11 using namespace std;
12 
13 
14 
15 class Error: public exception
16 {
17 public:
Error(const string & Message)18   Error(const string& Message): exception(), Message_(Message) {}
~Error()19   virtual ~Error() throw() {}
what() const20   virtual const char* what() const throw() { return Message_.c_str(); }
21 private:
22   string Message_;
23 };
24 
25 map <string, string> gPaperNames;
26 typedef pair<string, string> str_pair;
27 
28 static int
GetPrinterResolution(ppd_group_t * group,int num_groups)29 GetPrinterResolution(ppd_group_t* group, int num_groups)
30 {
31   for (int i = 0; i < num_groups; ++i)
32   {
33     ppd_group_t g = group[i];
34     for (int j = 0; j < g.num_options; ++j)
35     {
36       ppd_option_t o = g.options[j];
37 
38       if (!strcmp(o.keyword, "Resolution"))
39       {
40         ppd_choice_t c = o.choices[0];
41 
42         return atoi(c.choice);
43       }
44     }
45   }
46 
47   return 0;
48 }
49 
50 static void
FindPapersOptions(ppd_option_t & o)51 FindPapersOptions(ppd_option_t& o)
52 {
53   if (!strcmp(o.keyword, "PageSize"))
54   {
55     for (int i = 0; i < o.num_choices; ++i)
56     {
57       ppd_choice_t& c = o.choices[i];
58 
59       gPaperNames.insert(str_pair(c.choice, c.text));
60     }
61   }
62 }
63 
64 static void
FindPapersGroup(ppd_group_t & g)65 FindPapersGroup(ppd_group_t& g)
66 {
67   for (int i = 0; i < g.num_options; ++i)
68     FindPapersOptions(g.options[i]);
69 }
70 
71 static void
FindPapers(ppd_group_t * group,int num_groups)72 FindPapers(ppd_group_t* group, int num_groups)
73 {
74   for (int i = 0; i < num_groups; ++i)
75     FindPapersGroup(group[i]);
76 }
77 
78 
79 void
CreateBoundsImage(int Width,int Height,const string & Text,string & FileName,bool Landscape)80 CreateBoundsImage(int Width, int Height, const string& Text, string& FileName, bool Landscape)
81 {
82   FileName = "test.png";
83 
84   CairoSurfacePtr Surface(cairo_image_surface_create(CAIRO_FORMAT_RGB24, Width, Height));
85   if (!*Surface)
86     throw Error("Unable to create cairo surface");
87 
88 
89   CairoPtr c(cairo_create(Surface));
90   if (!*c)
91     throw Error("Unable to create cairo_t");
92 
93   //setup Cairo
94   cairo_set_antialias(c, CAIRO_ANTIALIAS_NONE);
95 
96 
97   // clear image
98   cairo_set_source_rgb(c, 1, 1, 1);
99   cairo_paint(c);
100 
101   // draw rect
102   cairo_set_source_rgb(c, 0, 0, 0);
103   cairo_set_line_width(c, 3);
104   cairo_rectangle(c, 3, 3, Width - 6, Height - 6);
105   cairo_move_to(c, 3, 3);
106   cairo_line_to(c, Width - 3, Height - 3);
107   cairo_move_to(c, 3, Height - 3);
108   cairo_line_to(c, Width - 3, 3);
109   cairo_stroke(c);
110 
111 
112   // draw text
113   cairo_select_font_face(c, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
114   cairo_set_source_rgb(c, 0, 0, 0);
115   cairo_set_line_width(c, 1);
116 
117   cairo_text_extents_t te;
118   for(int FontSize = 100; ;FontSize -= 10)
119   {
120     cairo_set_font_size(c, FontSize);
121 
122     cairo_text_extents(c, Text.c_str(), &te);
123 
124     if (Width > te.width)
125       break;
126   }
127 
128   //cairo_move_to(c, 10, 10);
129   //cairo_show_text(c, "Hello");
130   cairo_move_to(c, (Width - te.width) / 2, (Height + te.height) / 2);
131   cairo_text_path(c, Text.c_str());
132 
133   cairo_stroke(c);
134 
135   // rotate if in Landscape to output always in portrait mode
136   if (Landscape)
137   {
138       int w = Height;
139       int h = Width;
140       CairoSurfacePtr Surface2(cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h));
141       if (!*Surface2)
142           throw Error("Unable to create cairo surface");
143 
144 
145       CairoPtr c2(cairo_create(Surface2));
146       if (!*c2)
147           throw Error("Unable to create cairo_t");
148 
149       cairo_translate(c2, w * 0.5, h * 0.5);
150       cairo_rotate(c2, M_PI / 2.0);
151       cairo_translate(c2, -h * 0.5, -w * 0.5);
152       cairo_set_source_surface(c2, Surface, 0, 0);
153       cairo_set_operator(c2, CAIRO_OPERATOR_SOURCE);
154       cairo_paint(c2);
155 
156       if (cairo_surface_write_to_png(Surface2, FileName.c_str()) != CAIRO_STATUS_SUCCESS)
157           throw Error("Unable to write to PNG file");
158   }
159   else
160       // save to file
161       if (cairo_surface_write_to_png(Surface, FileName.c_str()) != CAIRO_STATUS_SUCCESS)
162           throw Error("Unable to write to PNG file");
163 }
164 
main(int argc,char ** argv)165 int main(int argc, char** argv)
166 {
167   try
168   {
169     if (argc < 2)
170       throw Error("Usage: paperlist <PrinterName> [LabelType]");
171 
172 
173   const char* ppdFileName = cupsGetPPD(argv[1]);
174   if (!ppdFileName)
175     throw Error(string("Unknown printer '") + argv[1] + "'");
176 
177   ppd_file_t* ppd = ppdOpenFile(ppdFileName);
178   if (!ppd)
179     throw Error(string("Unable to open ppd file '") + ppdFileName + "'");
180 
181   FindPapers(ppd->groups, ppd->num_groups);
182   int Resolution = GetPrinterResolution(ppd->groups, ppd->num_groups);
183 
184 
185   for (int i = 0; i < ppd->num_sizes; ++i)
186   {
187     int ch;
188     ppd_size_t size = ppd->sizes[i];
189     if (argc>=3)
190     //printf("%s\n", gPaperNames[size.name].substr(0,5).c_str());
191     if (argv[2]!=gPaperNames[size.name].substr(0,5))
192         continue;
193 
194     printf("Please Insert '%s' paper. Press 'c' to continue, 's' to skip: ", gPaperNames[size.name].c_str());
195     while((ch = getchar()) == '\n') {}
196     //printf("\n");
197 
198     if (ch == 's')
199       continue;
200     if (ch == 'a')
201       break;
202 
203 
204     int Width = int((size.right - size.left) * Resolution / 72);
205     int Height = int((size.top - size.bottom) * Resolution / 72);
206     bool Landscape = false;
207 
208     string FileName;
209     if (Height > Width)
210     {
211       Landscape = true;
212       int t = Width;
213       Width = Height;
214       Height = t;
215     }
216     CreateBoundsImage(Width, Height, gPaperNames[size.name], FileName, Landscape);
217 
218     int             num_options = 0;
219     cups_option_t*  options = NULL;
220 
221     num_options = cupsAddOption("PageSize", size.name, num_options, &options);
222     num_options = cupsAddOption("scaling", "100", num_options, &options);
223     if (Landscape)
224       num_options = cupsAddOption("landscape", "no", num_options, &options);
225       //num_options = cupsAddOption("orientation-requested", "4", num_options, &options);
226 
227 
228 
229     cupsPrintFile(argv[1], FileName.c_str(), "Test print with Cairo", num_options, options);
230 
231     cupsFreeOptions(num_options, options);
232   }
233 
234 
235   ppdClose(ppd);
236 
237   return 0;
238   }
239   catch(std::exception& e)
240   {
241     fprintf(stderr, e.what());
242     fprintf(stderr, "\n");
243     return 1;
244   }
245 }
246