Initial revision
[chise/kage.git] / kagecgi / kagetool.c
1 //kagetool.c\r
2 //\r
3 \r
4 #include "kage.h"\r
5 #include "kagecgi.h"\r
6 #include <stdlib.h>\r
7 #include <png.h>\r
8 \r
9 void DotsWidth(int *dlx, int *drx){\r
10         int i, j;\r
11         \r
12     *dlx = 0;\r
13     *drx = 0;\r
14     for(i = 0; i <= pngWidth && *dlx == 0; i++){\r
15                 for(j = 0; j <= pngHeight; j++){\r
16                         if(kageCanvas[j][i] == 0){\r
17                                 *dlx = i;\r
18                                 break;\r
19                         }\r
20                 }\r
21         }\r
22         \r
23         for(i = pngWidth; i >= 0 && *drx == 0; i--){\r
24                 for(j = 0; j <= pngHeight; j++){\r
25                         if(kageCanvas[j][i] == 0){\r
26                                 *drx = i;\r
27                                 break;\r
28                         }\r
29                 }\r
30         }\r
31 }\r
32 \r
33 void DotsHeight(int *dly, int *dry){\r
34     int i, j;\r
35         \r
36     *dly = 0;\r
37         *dry = 0;\r
38     for(j = 0; j <= pngHeight && *dly == 0; j++){\r
39         for(i = 0; i <= pngWidth; i++){\r
40             if(kageCanvas[j][i] == 0){\r
41                 *dly = j;\r
42                 break;\r
43             }\r
44         }\r
45     }\r
46         \r
47     for(j = pngHeight; j >= 0 && *dry == 0; j--){\r
48         for(i = 0; i <= pngWidth; i++){\r
49             if(kageCanvas[j][i] == 0){\r
50                 *dry = j;\r
51                 break;\r
52             }\r
53         }\r
54     }\r
55 }\r
56 \r
57 void PartsWidth(const GString *in, int *lx, int *rx){\r
58     int i;\r
59         int *buf, strokes;\r
60         \r
61         *lx = 1000; *rx = 0;\r
62         buf = convertStroke(in->str, buf, &strokes);\r
63         \r
64     for(i = 0; i < strokes; i++){\r
65         if(buf[i * 11 + 0] % 10 == 0) continue;\r
66                 \r
67         if(*lx > buf[i * 11 + 3]) *lx = buf[i * 11 + 3];\r
68                 if(*rx < buf[i * 11 + 3]) *rx = buf[i * 11 + 3];\r
69         if(*lx > buf[i * 11 + 5]) *lx = buf[i * 11 + 5];\r
70         if(*rx < buf[i * 11 + 5]) *rx = buf[i * 11 + 5];\r
71                 \r
72         if(buf[i * 11 + 0] % 10 == 2 || buf[i * 11 + 0] % 10 == 3 || buf[i * 11 + 0] % 10 == 8){\r
73                 if(*lx > buf[i * 11 + 7]) *lx = buf[i * 11 + 7];\r
74             if(*rx < buf[i * 11 + 7]) *rx = buf[i * 11 + 7];\r
75                 }\r
76         if(buf[i * 11 + 0] % 10 == 4 || buf[i * 11 + 0] % 10 == 6 || buf[i * 11 + 0] % 10 == 7){\r
77                 if(*lx > buf[i * 11 + 9]) *lx = buf[i * 11 + 9];\r
78                 if(*rx < buf[i * 11 + 9]) *rx = buf[i * 11 + 9];\r
79         }\r
80         }\r
81         free(buf);\r
82 }\r
83 \r
84 void PartsHeight(const GString *in, int *ly, int *ry){\r
85     int i;\r
86         int *buf, strokes;\r
87         \r
88         buf = convertStroke(in->str, buf, &strokes);\r
89         *ly = 1000; *ry = 0;\r
90         \r
91     for(i = 0; i < strokes; i++){\r
92         if(buf[i * 11 + 0] % 10 == 0) continue;\r
93                 \r
94         if(*ly > buf[i * 11 + 4]) *ly = buf[i * 11 + 4];\r
95                 if(*ry < buf[i * 11 + 4]) *ry = buf[i * 11 + 4];\r
96         if(*ly > buf[i * 11 + 6]) *ly = buf[i * 11 + 6];\r
97         if(*ry < buf[i * 11 + 6]) *ry = buf[i * 11 + 6];\r
98                 \r
99         if(buf[i * 11 + 0] % 10 == 2 || buf[i * 11 + 0] % 10 == 3 || buf[i * 11 + 0] % 10 == 8){\r
100                 if(*ly > buf[i * 11 + 8]) *ly = buf[i * 11 + 8];\r
101             if(*ry < buf[i * 11 + 8]) *ry = buf[i * 11 + 8];\r
102                 }\r
103         if(buf[i * 11 + 0] % 10 == 4 || buf[i * 11 + 0] % 10 == 6 || buf[i * 11 + 0] % 10 == 7){\r
104                 if(*ly > buf[i * 11 + 10]) *ly = buf[i * 11 + 10];\r
105                 if(*ry < buf[i * 11 + 10]) *ry = buf[i * 11 + 10];\r
106         }\r
107         }\r
108         free(buf);\r
109 }\r
110 \r
111 GString * CalcSizes(const GString *in, int mode){\r
112     int i, j, k, basewidth, one_lineX, one_lineY;\r
113     int dlx1, drx1, dly1, dry1;\r
114         int px1, py1;\r
115     double pr1, pry1;\r
116         \r
117     int mitsuT, flg_boxT, widthT, heightT;\r
118     double tateT, yokoT;\r
119     int cutx, cuty;\r
120         \r
121         int *buf, strokes;\r
122         int tf[12];\r
123         GString *out;\r
124         \r
125         out = g_string_new("");\r
126     basewidth = pngWidth * 0.9;\r
127         \r
128     if(mode == 0){\r
129         //temporary adjustment X-axis\r
130         PartsWidth(in, &dlx1, &drx1);\r
131         if(dlx1 == drx1){\r
132             pr1 = 1.0;\r
133             px1 = pngWidth / 2 - dlx1;\r
134             one_lineX = 1;\r
135         }\r
136         else{\r
137             pr1 = (double)basewidth/(drx1 - dlx1);\r
138             px1 = (pngWidth-basewidth)/2 - (double)(dlx1 * pr1);\r
139             one_lineX = 0;\r
140         }\r
141                 \r
142         //temporary adjustment Y-axis\r
143         PartsHeight(in, &dly1, &dry1);\r
144         if(dly1 == dry1){\r
145             pry1 = 1.0;\r
146             py1 = pngWidth / 2 - dly1;\r
147             one_lineY = 1;\r
148         }\r
149                 else{\r
150             pry1 = (double)basewidth/(dry1 - dly1);\r
151             py1 = (pngWidth-basewidth)/2 - (double)(dly1 * pry1);\r
152             one_lineY = 0;\r
153         }\r
154     }\r
155         else{\r
156         PartsWidth(in, &dlx1, &drx1);\r
157         PartsHeight(in, &dly1, &dry1);\r
158                 \r
159         cutx = 0;\r
160         cuty = 0;\r
161                 \r
162         CalcOptions(in, &mitsuT, &flg_boxT, &yokoT, &tateT);\r
163                 \r
164         widthT = basewidth;\r
165         heightT = basewidth;\r
166                 \r
167         if(flg_boxT % 2 / 1 != 0){\r
168             widthT = widthT - kWidth * 3;\r
169             cutx++;\r
170         }\r
171         if(flg_boxT % 4 / 2 != 0){\r
172             widthT = widthT - kWidth * 3;\r
173             cutx++;\r
174         }\r
175         if(flg_boxT % 8 / 4 != 0){\r
176             heightT = heightT - kWidth * 3;\r
177             cuty++;\r
178         }\r
179         if(flg_boxT % 16 / 8 != 0){\r
180             heightT = heightT - kWidth * 3;\r
181             cuty++;\r
182         }\r
183                 \r
184         //especially get small the 'mouse'\r
185         if(mode == 2 && flg_boxT % 16 == 15){\r
186             widthT = widthT - kWidth * (max(0, 16 - (int)yokoT * 4));\r
187             heightT = heightT - kWidth * (max(0, 16 - (int)tateT * 4));\r
188                 }\r
189         //'dot' as same as 'mouse'\r
190         if(mode == 2 && tateT == 1 && yokoT == 1){\r
191             widthT = pngWidth * 0.9 * 0.5;\r
192             heightT = pngWidth * 0.9 * 0.5;\r
193         }\r
194                 \r
195                 if(flg_boxT % 64 / 32 != 0){\r
196                         buf = convertStroke(in->str, buf, &strokes);\r
197                         for(i = 0; i < strokes; i++){\r
198                 if(buf[i * 11 + 0] == 0) j = buf[i * 11 + 4];// j : center line\r
199             }\r
200             free(buf);\r
201             k = max(j - dlx1, drx1 - j);// k : distance from center line\r
202             pr1 = (basewidth * 0.5) / k;\r
203                         \r
204             if(k == j - dlx1) px1 = 0;\r
205             else px1 = pngWidth * 0.5 - j * pr1;\r
206         }\r
207         else if(dlx1 == drx1){\r
208             pr1 = 1.0;\r
209             px1 = pngWidth / 2 - dlx1;\r
210         }\r
211         else{\r
212             pr1 = (double)widthT/(drx1 - dlx1);\r
213             px1 = pngWidth / 2 - (double)((dlx1 + drx1) / 2 * pr1);\r
214             if(flg_boxT % 2 / 1 != 0 && flg_boxT % 4 / 2 == 0) px1 = px1 + kWidth * 1.5;\r
215             if(flg_boxT % 2 / 1 == 0 && flg_boxT % 4 / 2 != 0) px1 = px1 - kWidth * 1.5;\r
216         }\r
217                 \r
218         if(dly1 == dry1){\r
219             pry1 = 1.0;\r
220             py1 = pngWidth / 2 - dly1;\r
221         }\r
222         else{\r
223             pry1 = (double)heightT/(dry1 - dly1);\r
224             py1 = pngWidth / 2 - (double)((dly1 + dry1) / 2 * pry1);\r
225             if(flg_boxT % 8 / 4 != 0 && flg_boxT % 16 / 8 == 0) py1 = py1 + kWidth * 1.5;\r
226             if(flg_boxT % 8 / 4 == 0 && flg_boxT % 16 / 8 != 0) py1 = py1 - kWidth * 1.5;\r
227         }\r
228         }\r
229         \r
230         //generate result\r
231         tf[0] = px1;\r
232         tf[1] = py1;\r
233         tf[2] = px1 + pr1 * 200;\r
234         tf[3] = py1 + pry1 * 200;\r
235         addStrokeWithTransform(in, 1, tf, out, 0);\r
236         return g_string_new(out->str);\r
237 }\r
238 \r
239 void DrawBox(){\r
240         int i, j;\r
241         \r
242         for(i = 0; i < canvasWidth; i++){\r
243                 for(j = 0; j < canvasHeight; j++){\r
244                         kageCanvas[j][i] = 0xFF;\r
245                 }\r
246         }\r
247 }\r
248 \r
249 void CalcOptions(const GString *in, int *mitsudo, int *flag, double *yoko, double *tate){\r
250     int i, j, k, l, flg;\r
251     int dlx1, drx1, dly1, dry1;\r
252     int kari, mode;\r
253         int tempShotai;\r
254         int *buf, strokes;\r
255         \r
256     *flag = 0;\r
257         \r
258     DrawBox();\r
259     tempShotai = kShotai;\r
260     kShotai = kGothic;\r
261     drawGlyph(in, 1);\r
262     kShotai = tempShotai;\r
263     DotsWidth(&dlx1, &drx1);\r
264     DotsHeight(&dly1, &dry1);\r
265         \r
266         //check left side\r
267     k = 0;\r
268     l = 0;\r
269     for(i = 0; i < pngWidth; i++){\r
270         flg = 0;\r
271         for(j = 0; j < kWidth; j++){\r
272             if(kageCanvas[i][dlx1 + j] == 0) flg = 1;\r
273         }\r
274         if(flg == 1){\r
275                 k++;\r
276         }\r
277         else{\r
278             if(k > l) l = k;\r
279             k = 0;\r
280         }\r
281     }\r
282     if(k > l) l = k;\r
283     \r
284     if(l > pngWidth * 0.9 / 4) *flag = *flag | 1;\r
285         \r
286     //check right side\r
287     k = 0;\r
288     l = 0;\r
289     for(i = 0; i < pngWidth; i++){\r
290         flg = 0;\r
291         for(j = 0; j < kWidth; j++){\r
292             if(kageCanvas[i][drx1 - j] == 0) flg = 1;\r
293         }\r
294         if(flg == 1) k++;\r
295         else{\r
296             if(k > l) l = k;\r
297             k = 0;\r
298         }\r
299     }\r
300     if(k > l) l = k;\r
301         \r
302     if(l > pngWidth * 0.9 / 4) *flag = *flag | 2;\r
303         \r
304     //check upper side\r
305     k = 0;\r
306     l = 0;\r
307     for(i = 0; i < pngWidth; i++){\r
308         flg = 0;\r
309                 for(j = 0; j < kWidth; j++){\r
310             if(kageCanvas[dly1 + j][i] == 0) flg = 1;\r
311         }\r
312         if(flg == 1) k++;\r
313         else{\r
314             if(k > l) l = k;\r
315             k = 0;\r
316         }\r
317     }\r
318     if(k > l) l = k;\r
319         \r
320     if(l > pngWidth * 0.9 / 4) *flag = *flag | 4;\r
321         \r
322     //check bottom side\r
323     k = 0;\r
324     l = 0;\r
325     for(i = 0; i < pngWidth; i++){\r
326         flg = 0;\r
327         for(j = 0; j < kWidth; j++){\r
328             if(kageCanvas[dry1 - j][i] == 0) flg = 1;\r
329         }\r
330         if(flg == 1) k++;\r
331         else{\r
332             if(k > l) l = k;\r
333             k = 0;\r
334         }\r
335     }\r
336     if(k > l) l = k;\r
337         \r
338     if(l > pngWidth * 0.9 / 4) *flag = *flag | 8;\r
339         \r
340     //count black dots\r
341     *mitsudo = 0;\r
342     for(i = 0; i < pngHeight; i++){\r
343         for(j = 0; j < pngWidth; j++){\r
344             if(kageCanvas[i][j] == 0) *mitsudo += 1;\r
345         }\r
346     }\r
347         \r
348     //calculate X-axis complexity\r
349     *yoko = 0;\r
350     for(i = dly1; i <= dry1; i++){\r
351         mode = 0;\r
352         kari = 0;\r
353         for(j = dlx1; j <= drx1; j++){\r
354                         if(kageCanvas[i][j] == 0 &&\r
355              kageCanvas[i][j+1] == 0 &&\r
356              kageCanvas[i][j+2] == 0){\r
357                 if(mode == 0){\r
358                     mode = 1;\r
359                     kari++;\r
360                 }\r
361             }\r
362             else if(mode == 1) mode = 0;\r
363         }\r
364         if(kari > *yoko) *yoko = kari;\r
365     }\r
366         \r
367     //calculate Y-axis complexity\r
368     *tate = 0;\r
369     for(i = dlx1; i <= drx1; i++){\r
370         mode = 0;\r
371         kari = 0;\r
372         for(j = dly1; j <= dry1; j++){\r
373             if(kageCanvas[j][i] == 0 &&\r
374              kageCanvas[j+1][i] == 0 &&\r
375              kageCanvas[j+2][i] == 0){\r
376                 if(mode == 0){\r
377                     mode = 1;\r
378                     kari++;\r
379                 }\r
380             }\r
381             else if(mode == 1) mode = 0;\r
382         }\r
383         if(kari > *tate) *tate = kari;\r
384     }\r
385         \r
386     //use user defined option if it exists\r
387         buf = convertStroke(in->str, buf, &strokes);\r
388         for(i = 0; i < strokes; i++){\r
389         if(buf[i * 11 + 0] % 10 == 0){\r
390             if(buf[i * 11 + 1] != 0){ *yoko = (double)(buf[i * 11 + 1]) * 0.1;fprintf(stderr,"@@@@@\r\n");}\r
391             if(buf[i * 11 + 2] != 0) *tate = (double)(buf[i * 11 + 2]) * 0.1;\r
392             if(buf[i * 11 + 3] != 0) *flag = *flag + buf[i * 11 + 3] * 16;\r
393         }\r
394     }\r
395     free(buf);\r
396 }\r
397 \r
398 void DoDrawParts(const GString *in, const int lx1, const double rf1, const int ly1, const double rfy1){\r
399     int i;\r
400         int *buf, strokes;\r
401         \r
402     DrawBox();\r
403         buf = convertStroke(in->str, buf, &strokes);\r
404         for(i = 0; i < strokes; i++){\r
405                 dfDrawFont(buf[i * 11 + 0],\r
406                  buf[i * 11 + 1],\r
407                  buf[i * 11 + 2],\r
408                  buf[i * 11 + 3] * rf1 + lx1,\r
409                  buf[i * 11 + 4] * rfy1 + ly1,\r
410                  buf[i * 11 + 5] * rf1 + lx1,\r
411                  buf[i * 11 + 6] * rfy1 + ly1,\r
412                  buf[i * 11 + 7] * rf1 + lx1,\r
413                  buf[i * 11 + 8] * rfy1 + ly1,\r
414                  buf[i * 11 + 9] * rf1 + lx1,\r
415                  buf[i * 11 + 10] * rfy1 + ly1);\r
416     }\r
417         free(buf);\r
418 }\r
419 \r
420 void DoDrawMixFont(const GString *in1,\r
421  const int lx1,\r
422  const double rf1,\r
423  const GString *in2,\r
424  const int lx2,\r
425  const double rf2,\r
426  const int ly1,\r
427  const double rfy1,\r
428  const int ly2,\r
429  const double rfy2){\r
430     int i;\r
431         int *buf, strokes;\r
432         \r
433         DrawBox();\r
434         buf = convertStroke(in1->str, buf, &strokes);\r
435         for(i = 0; i < strokes; i++){\r
436                 dfDrawFont(buf[i * 11 + 0],\r
437                  buf[i * 11 + 1],\r
438                  buf[i * 11 + 2],\r
439                  buf[i * 11 + 3] * rf1 + lx1,\r
440                  buf[i * 11 + 4] * rfy1 + ly1,\r
441                  buf[i * 11 + 5] * rf1 + lx1,\r
442                  buf[i * 11 + 6] * rfy1 + ly1,\r
443                  buf[i * 11 + 7] * rf1 + lx1,\r
444                  buf[i * 11 + 8] * rfy1 + ly1,\r
445                  buf[i * 11 + 9] * rf1 + lx1,\r
446                  buf[i * 11 + 10] * rfy1 + ly1);\r
447     }\r
448         free(buf);\r
449         \r
450         buf = convertStroke(in2->str, buf, &strokes);\r
451         for(i = 0; i < strokes; i++){\r
452                 dfDrawFont(buf[i * 11 + 0],\r
453                  buf[i * 11 + 1],\r
454                  buf[i * 11 + 2],\r
455                  buf[i * 11 + 3] * rf2 + lx2,\r
456                  buf[i * 11 + 4] * rfy2 + ly2,\r
457                  buf[i * 11 + 5] * rf2 + lx2,\r
458                  buf[i * 11 + 6] * rfy2 + ly2,\r
459                  buf[i * 11 + 7] * rf2 + lx2,\r
460                  buf[i * 11 + 8] * rfy2 + ly2,\r
461                  buf[i * 11 + 9] * rf2 + lx2,\r
462                  buf[i * 11 + 10] * rfy2 + ly2);\r
463     }\r
464         free(buf);\r
465 }\r
466 \r