OSDN Git Service

* update copyright date.
[modchxj/mod_chxj.git] / src / chxj_img_conv_format.c
1 /*
2  * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <libgen.h>
18 #include "mod_chxj.h"
19 #include "chxj_img_conv_format.h"
20 #include "chxj_specified_device.h"
21 #include "chxj_str_util.h"
22 #include "chxj_qr_code.h"
23 #include "chxj_apply_convrule.h"
24 #include "chxj_url_encode.h"
25 #include "qs_parse_string.h"
26
27 #include "http_core.h"
28
29 #include <wand/magick_wand.h>
30
31
32 #define EXIT_MAGICK_ERROR() \
33   do { \
34     char *description; ExceptionType severity; \
35     description=MagickGetException(magick_wand,&severity); \
36     ap_log_rerror(APLOG_MARK,APLOG_DEBUG, 0, r,"%s %s %d %s\n",__FILE__,(__func__),__LINE__,description); \
37     description=(char *) MagickRelinquishMemory(description); \
38     DestroyMagickWand(magick_wand); \
39   }while(1) 
40
41 typedef enum img_conv_mode_t {
42   IMG_CONV_MODE_NORMAL = 0,
43   IMG_CONV_MODE_THUMBNAIL,
44   IMG_CONV_MODE_WALLPAPER,
45   IMG_CONV_MODE_EZGET,
46 } img_conv_mode_t;
47
48 /*----------------------------------------------------------------------------*/
49 /* User-Agent use flag                                                        */
50 /*----------------------------------------------------------------------------*/
51 typedef enum _ua_use_flag_t {
52   UA_USE=0,               /* User-Agent is used.                              */
53   UA_IGN,                 /* User-Agent is disregarded.                       */
54 } ua_use_flag_t;
55
56 /*----------------------------------------------------------------------------*/
57 /* Request parameter maintenance structure                                    */
58 /*----------------------------------------------------------------------------*/
59 typedef struct query_string_param_t query_string_param_t;
60
61 struct query_string_param_t {
62   img_conv_mode_t   mode;
63   char*             user_agent;
64   ua_use_flag_t     ua_flag;
65
66   char*             name;      /* for EZGET */
67   long              offset;    /* for EZGET */
68   long              count;     /* for EZGET */
69   int               width;
70   int               height;
71 };
72
73 /*----------------------------------------------------------------------------*/
74 /* Device_spec when User-Agent is disregarded                                 */
75 /*----------------------------------------------------------------------------*/
76 static device_table v_ignore_spec = {
77   NULL,
78   "IGN",
79   "IGN",
80   CHXJ_SPEC_HTML,
81   640,
82   480,
83   640,
84   480,
85   1024*1024,
86   1,
87   1,
88   1,
89   0,
90   0,
91   96,
92   96,
93   65536,
94   NULL,
95 };
96
97 /*----------------------------------------------------------------------------*/
98 /* CRC calculation table for AU                                               */
99 /*----------------------------------------------------------------------------*/
100 static unsigned short  AU_CRC_TBL[256] = {
101   0x0000,0x1021,0x2042,0x3063,0x4084,0x50A5,0x60C6,0x70E7,
102   0x8108,0x9129,0xA14A,0xB16B,0xC18C,0xD1AD,0xE1CE,0xF1EF,
103   0x1231,0x0210,0x3273,0x2252,0x52B5,0x4294,0x72F7,0x62D6,
104   0x9339,0x8318,0xB37B,0xA35A,0xD3BD,0xC39C,0xF3FF,0xE3DE,
105   0x2462,0x3443,0x0420,0x1401,0x64E6,0x74C7,0x44A4,0x5485,
106   0xA56A,0xB54B,0x8528,0x9509,0xE5EE,0xF5CF,0xC5AC,0xD58D,
107   0x3653,0x2672,0x1611,0x0630,0x76D7,0x66F6,0x5695,0x46B4,
108   0xB75B,0xA77A,0x9719,0x8738,0xF7DF,0xE7FE,0xD79D,0xC7BC,
109   0x48C4,0x58E5,0x6886,0x78A7,0x0840,0x1861,0x2802,0x3823,
110   0xC9CC,0xD9ED,0xE98E,0xF9AF,0x8948,0x9969,0xA90A,0xB92B,
111   0x5AF5,0x4AD4,0x7AB7,0x6A96,0x1A71,0x0A50,0x3A33,0x2A12,
112   0xDBFD,0xCBDC,0xFBBF,0xEB9E,0x9B79,0x8B58,0xBB3B,0xAB1A,
113   0x6CA6,0x7C87,0x4CE4,0x5CC5,0x2C22,0x3C03,0x0C60,0x1C41,
114   0xEDAE,0xFD8F,0xCDEC,0xDDCD,0xAD2A,0xBD0B,0x8D68,0x9D49,
115   0x7E97,0x6EB6,0x5ED5,0x4EF4,0x3E13,0x2E32,0x1E51,0x0E70,
116   0xFF9F,0xEFBE,0xDFDD,0xCFFC,0xBF1B,0xAF3A,0x9F59,0x8F78,
117   0x9188,0x81A9,0xB1CA,0xA1EB,0xD10C,0xC12D,0xF14E,0xE16F,
118   0x1080,0x00A1,0x30C2,0x20E3,0x5004,0x4025,0x7046,0x6067,
119   0x83B9,0x9398,0xA3FB,0xB3DA,0xC33D,0xD31C,0xE37F,0xF35E,
120   0x02B1,0x1290,0x22F3,0x32D2,0x4235,0x5214,0x6277,0x7256,
121   0xB5EA,0xA5CB,0x95A8,0x8589,0xF56E,0xE54F,0xD52C,0xC50D,
122   0x34E2,0x24C3,0x14A0,0x0481,0x7466,0x6447,0x5424,0x4405,
123   0xA7DB,0xB7FA,0x8799,0x97B8,0xE75F,0xF77E,0xC71D,0xD73C,
124   0x26D3,0x36F2,0x0691,0x16B0,0x6657,0x7676,0x4615,0x5634,
125   0xD94C,0xC96D,0xF90E,0xE92F,0x99C8,0x89E9,0xB98A,0xA9AB,
126   0x5844,0x4865,0x7806,0x6827,0x18C0,0x08E1,0x3882,0x28A3,
127   0xCB7D,0xDB5C,0xEB3F,0xFB1E,0x8BF9,0x9BD8,0xABBB,0xBB9A,
128   0x4A75,0x5A54,0x6A37,0x7A16,0x0AF1,0x1AD0,0x2AB3,0x3A92,
129   0xFD2E,0xED0F,0xDD6C,0xCD4D,0xBDAA,0xAD8B,0x9DE8,0x8DC9,
130   0x7C26,0x6C07,0x5C64,0x4C45,0x3CA2,0x2C83,0x1CE0,0x0CC1,
131   0xEF1F,0xFF3E,0xCF5D,0xDF7C,0xAF9B,0xBFBA,0x8FD9,0x9FF8,
132   0x6E17,0x7E36,0x4E55,0x5E74,0x2E93,0x3EB2,0x0ED1,0x1EF0 
133 };
134
135 /*----------------------------------------------------------------------------*/
136 /* Download page for AU                                                       */
137 /*----------------------------------------------------------------------------*/
138 static const char* HDML_FIRST_PAGE = 
139   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
140   "  <NODISPLAY>\r\n"
141   "    <ACTION TYPE=ACCEPT TASK=GOSUB DEST=\"device:data/dnld?url=%s&name=%s%s&size=%ld&disposition=%s&title=%s\">\r\n"
142   "  </NODISPLAY>\r\n"
143   "</HDML>\r\n";
144
145 static const char* HDML_SUCCESS_PAGE =
146   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
147   "  <DISPLAY>\r\n"
148   "    <ACTION TYPE=ACCEPT TASK=RETURN>\r\n"
149   "    \x83\x5f\x83\x45\x83\x93\x83\x8d\x81\x5b\x83\x68\x82\xc9\x90\xac\x8c\xf7\x82\xb5\x82\xdc\x82\xb5\x82\xbd\r\n"
150   "  </DISPLAY>\r\n"
151   "<HDML>\r\n";
152
153 static const char* HDML_FAIL_PAGE =
154   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
155   "  <DISPLAY>\r\n"
156   "    <ACTION TYPE=ACCEPT TASK=RETURN>\r\n"
157   "    \x83\x5f\x83\x45\x83\x93\x83\x8d\x81\x5b\x83\x68\x82\xc9\x8e\xb8\x94\x73\x82\xb5\x82\xdc\x82\xb5\x82\xbd\r\n"
158   "  </DISPLAY>\r\n"
159   "<HDML>\r\n";
160
161 /*----------------------------------------------------------------------------*/
162 /* Prototype declaration                                                      */
163 /*----------------------------------------------------------------------------*/
164 static char*        s_create_workfile(  request_rec*, 
165                                         mod_chxj_config* , 
166                                         const char*, 
167                                         query_string_param_t*);
168
169 static apr_status_t s_create_cache_file(request_rec*          r, 
170                                         const char*           tmpfile, 
171                                         device_table*         spec,
172                                         apr_finfo_t*          st,
173                                         query_string_param_t* qsp);
174
175 static apr_status_t s_send_cache_file(  device_table*         spec,
176                                         query_string_param_t* query_string,
177                                         request_rec*          r,
178                                         const char*           tmpfile);
179
180 static apr_status_t s_header_only_cache_file(device_table*         spec, 
181                                              query_string_param_t* query_string, 
182                                              request_rec*          r, 
183                                              const char*           tmpfile);
184
185 static query_string_param_t* s_get_query_string_param(request_rec *r);
186
187 static unsigned short s_add_crc(        const char* writedata, 
188                                         apr_size_t witebyte);
189
190 static MagickWand* s_fixup_size(MagickWand* , 
191                                 request_rec* r, 
192                                 device_table* spec, 
193                                 query_string_param_t *qsp);
194
195 static MagickWand* s_fixup_color(MagickWand* magick_wand, 
196                                  request_rec* r, 
197                                  device_table* spec, 
198                                  img_conv_mode_t mode);
199 static MagickWand* s_fixup_depth(MagickWand* magick_wand, 
200                                  request_rec* r, device_table* spec);
201 static MagickWand* s_img_down_sizing(MagickWand* magick_wand, 
202                                 request_rec* r, device_table* spec);
203
204 static MagickWand* s_add_copyright(MagickWand*   magick_wand,
205                                    request_rec*  r,
206                                    device_table* spec);
207
208 static char* s_create_blob_data(request_rec*          r,
209                                 device_table*         spec,
210                                 query_string_param_t* qsp,
211                                 char*                 indata,
212                                 apr_size_t*           len);
213
214 static int s_img_conv_format_from_file(request_rec*          r, 
215                                        mod_chxj_config*      conf, 
216                                        const char*           user_agent,
217                                        query_string_param_t* qsp,
218                                        device_table*         spec);
219
220
221
222 int 
223 chxj_img_conv_format_handler(request_rec* r)
224 {
225   mod_chxj_config*      conf;
226   query_string_param_t* qsp;
227   char*                 user_agent;
228   device_table*         spec;
229   chxjconvrule_entry*   entryp;
230
231   DBG(r, "start chxj_img_conv_format_handler()");
232   
233   if ((*r->handler != 'c' && *r->handler != 'C') 
234   ||  (strcasecmp(r->handler, "chxj-picture")
235   &&  strcasecmp(r->handler, "chxj-qrcode"))) {
236     DBG(r, "end chxj_img_conv_format_handler()");
237     return DECLINED;
238   }
239
240   qsp = s_get_query_string_param(r);
241   conf = ap_get_module_config(r->per_dir_config, &chxj_module);
242   if (conf == NULL) {
243     DBG(r, "end chxj_img_conv_format_handler() conf is null");
244     return DECLINED;
245   }
246
247   if (strcasecmp(r->handler, "chxj-qrcode") == 0 &&  conf->image == CHXJ_IMG_OFF) {
248     return DECLINED;
249   }
250
251
252   /*------------------------------------------------------------------------*/
253   /* get UserAgent from http header                                         */
254   /*------------------------------------------------------------------------*/
255   /*--------------------------------------------------------------------------*/
256   /* User-Agent to spec                                                       */
257   /*--------------------------------------------------------------------------*/
258   if (qsp->user_agent) {
259     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
260   }
261   else {
262     entryp = chxj_apply_convrule(r, conf->convrules);
263     if (entryp && entryp->user_agent) {
264       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
265     }
266     else {
267       user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
268     }
269   }
270
271
272
273   if (qsp->ua_flag == UA_IGN)
274     spec = &v_ignore_spec;
275   else
276     spec = chxj_specified_device(r, user_agent);
277
278   DBG1(r,"found device_name=[%s]", spec->device_name);
279   DBG1(r,"User-Agent=[%s]", user_agent);
280
281 #if 0
282   if (spec->width == 0 || spec->heigh == 0)
283     return DECLINED;
284 #endif
285
286   return s_img_conv_format_from_file(r, conf, user_agent, qsp, spec);
287 }
288
289
290
291 /**
292  * It converts it from ImageData corresponding to each model.
293  *
294  * @param r   [i]
295  * @param src [i]   It is former image binary data.
296  * @param len [i/o] It is length of former image binary data.
297  */
298 char*
299 chxj_exchange_image(request_rec *r, const char** src, apr_size_t* len)
300 {
301   mod_chxj_config*      conf;
302   query_string_param_t* qsp;
303   char*                 user_agent;
304   device_table*         spec;
305   char*                 dst;
306   char*                 conv_check;
307   chxjconvrule_entry* entryp;
308
309   DBG(r, "start chxj_exchange_image()");
310
311   conv_check = (char*)apr_table_get(r->headers_in, "CHXJ_IMG_CONV");
312   if (conv_check) {
313     DBG(r, "end chxj_exchnage_image() already convert.");
314     return NULL;
315   }
316
317
318   qsp = s_get_query_string_param(r);
319   conf = ap_get_module_config(r->per_dir_config, &chxj_module);
320   if (conf == NULL) {
321     DBG(r, "end chxj_exchange_image()");
322     return NULL;
323   }
324
325   /*--------------------------------------------------------------------------*/
326   /* User-Agent to spec                                                       */
327   /*--------------------------------------------------------------------------*/
328   if (qsp->user_agent) {
329     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
330   }
331   else {
332     entryp = chxj_apply_convrule(r, conf->convrules);
333     if (entryp && entryp->user_agent) {
334       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
335     }
336     else {
337       user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
338     }
339   }
340
341   if (qsp->ua_flag == UA_IGN)
342     spec = &v_ignore_spec;
343   else
344     spec = chxj_specified_device(r, user_agent);
345
346   DBG1(r,"found device_name=[%s]", spec->device_name);
347   DBG1(r, "User-Agent=[%s]", user_agent);
348
349   if (spec->width == 0 || spec->heigh == 0) 
350     return NULL;
351
352   dst = s_create_blob_data(r, spec, qsp, (char*)*src, len);
353   if (dst == NULL) 
354     *len = 0;
355
356   DBG(r, "end chxj_exchange_image()");
357
358   return dst;
359 }
360
361 static int
362 s_img_conv_format_from_file(
363                 request_rec*          r, 
364                 mod_chxj_config*    conf, 
365                 const char*           user_agent,
366                 query_string_param_t* qsp,
367                 device_table*       spec)
368 {
369   apr_status_t   rv;
370   apr_finfo_t    st;
371   apr_finfo_t    cache_st;
372   char*          tmpfile;
373
374   /*--------------------------------------------------------------------------*/
375   /* Create Workfile Name                                                     */
376   /*--------------------------------------------------------------------------*/
377   tmpfile = s_create_workfile(r, conf, user_agent, qsp);
378   DBG1(r,"workfile=[%s]", tmpfile);
379
380   rv = apr_stat(&st, r->filename, APR_FINFO_MIN, r->pool);
381   if (rv != APR_SUCCESS)
382     return HTTP_NOT_FOUND;
383
384
385   DBG1(r,"found [%s]", r->filename);
386   rv = apr_stat(&cache_st, tmpfile, APR_FINFO_MIN, r->pool);
387   DBG1(r,"found [%s]", r->filename);
388
389   if (rv != APR_SUCCESS || cache_st.ctime < st.mtime) {
390     /*------------------------------------------------------------------------*/
391     /* It tries to make the cash file when it doesn't exist or there is       */
392     /* change time later since the making time of the cash file.              */
393     /*------------------------------------------------------------------------*/
394     rv = s_create_cache_file(r,tmpfile, spec, &st, qsp);
395     if (rv != OK)
396       return rv;
397   }
398
399   DBG1(r,"color=[%d]", spec->color);
400   if (! r->header_only)  {
401     rv = s_send_cache_file(spec, qsp,r, tmpfile);
402     if (rv != OK) 
403       return rv;
404   }
405   else {
406     rv = s_header_only_cache_file(spec, qsp, r, tmpfile);
407     if (rv != OK) 
408       return rv;
409   }
410   apr_table_setn(r->headers_in, "CHXJ_IMG_CONV", "done");
411
412   DBG(r,"end chxj_img_conv_format");
413
414   return OK;
415 }
416
417
418 static apr_status_t
419 s_create_cache_file(request_rec*       r, 
420                        const char*     tmpfile, 
421                        device_table* spec, 
422                        apr_finfo_t*    st, 
423                        query_string_param_t *qsp)
424 {
425   apr_status_t       rv;
426   apr_size_t         readbyte;
427   apr_size_t         writebyte;
428   unsigned short     crc;
429   img_conv_mode_t    mode = qsp->mode;
430
431   char*              writedata = NULL;
432   char*              readdata  = NULL;
433
434   apr_file_t*        fout;
435   apr_file_t*        fin;
436
437   MagickWand*        magick_wand;
438
439   if ((*r->handler == 'c' || *r->handler == 'C') 
440   &&  strcasecmp(r->handler, "chxj-qrcode") == 0) {
441     /*------------------------------------------------------------------------*/
442     /* QRCODEÍѤΥե¡¥¤¥ë¤Î¾ì¹ç                                               */
443     /*------------------------------------------------------------------------*/
444     Doc       doc;
445     Node*     root;
446     qr_code_t qrcode;
447     int       sts;
448
449     memset(&doc,    0, sizeof(Doc));
450     memset(&qrcode, 0, sizeof(qr_code_t));
451     doc.r = r;
452     doc.parse_mode  = PARSE_MODE_CHTML;
453     qrcode.doc      = &doc;
454     qrcode.r        = r;
455
456     qs_init_malloc(&doc);
457
458     root = qs_parse_file(&doc, r->filename);
459
460     chxj_qrcode_node_to_qrcode(&qrcode, root);
461
462     qs_all_free(&doc,QX_LOGMARK);
463
464     sts = chxj_qrcode_create_image_data(&qrcode, &readdata, &readbyte);
465     if (sts != OK) {
466       ERR(r, "qrcode create failed.");
467       return sts;
468     }
469   }
470   else {
471     /*------------------------------------------------------------------------*/
472     /* Ä̾ï¤Î¥¤¥á¡¼¥¸¥Õ¥¡¥¤¥ë¤Î¾ì¹ç                                           */
473     /*------------------------------------------------------------------------*/
474     rv = apr_file_open(&fin, 
475                     r->filename, 
476                     APR_READ|APR_BINARY ,
477                     APR_OS_DEFAULT, 
478                     r->pool);
479     if (rv != APR_SUCCESS) {
480       DBG1(r,"file open failed.[%s]", r->filename);
481       return HTTP_NOT_FOUND;
482     }
483   
484     readdata = apr_palloc(r->pool, st->size);
485     rv = apr_file_read_full(fin, (void*)readdata, st->size, &readbyte);
486     if (rv != APR_SUCCESS || readbyte != st->size) {
487       DBG1(r,"file read failed.[%s]", r->filename);
488       apr_file_close(fin);
489   
490       return HTTP_NOT_FOUND;
491     }
492   }
493   DBG(r,"start img convert");
494
495
496   magick_wand = NewMagickWand();
497   if (MagickReadImageBlob(magick_wand,readdata, readbyte) == MagickFalse) {
498     EXIT_MAGICK_ERROR();
499     return HTTP_NOT_FOUND;
500   }
501
502   if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
503     /*
504      * The size of the image is changed.
505      */
506     DBG(r,"call s_fixup_size()");
507   
508     if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) 
509       return HTTP_NOT_FOUND;
510   
511     /*
512      * The colors of the image is changed.
513      */
514     DBG(r,"call s_fixup_color()");
515   
516     if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) 
517       return HTTP_NOT_FOUND;
518   
519     /*
520      * DEPTH of the image is changed.
521      */
522     DBG(r,"call s_fixup_depth()");
523   
524     if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) 
525       return HTTP_NOT_FOUND;
526   
527   
528   
529     DBG(r,"start convert and compression");
530   
531     if (spec->available_jpeg) {
532       if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
533         EXIT_MAGICK_ERROR();
534         return HTTP_NOT_FOUND;
535       }
536   
537       if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
538         EXIT_MAGICK_ERROR();
539         return HTTP_NOT_FOUND;
540       }
541   
542       if (MagickStripImage(magick_wand) == MagickFalse) {
543         EXIT_MAGICK_ERROR();
544         return HTTP_NOT_FOUND;
545       }
546   
547       if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
548         return HTTP_NOT_FOUND;
549   
550       r->content_type = apr_psprintf(r->pool, "image/jpeg");
551       DBG(r,"convert to jpg");
552     }
553     else
554     if (spec->available_png) {
555   
556       if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
557         EXIT_MAGICK_ERROR();
558         return HTTP_NOT_FOUND;
559       }
560   
561       if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
562         EXIT_MAGICK_ERROR();
563         return HTTP_NOT_FOUND;
564       }
565   
566       if (MagickStripImage(magick_wand) == MagickFalse) {
567         EXIT_MAGICK_ERROR();
568         return HTTP_NOT_FOUND;
569       }
570   
571       if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
572         return HTTP_NOT_FOUND;
573   
574       r->content_type = apr_psprintf(r->pool, "image/png");
575       DBG(r, "convert to png");
576     }
577     else
578     if (spec->available_gif) {
579   
580       if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
581         EXIT_MAGICK_ERROR();
582         return HTTP_NOT_FOUND;
583       }
584   
585       if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
586         EXIT_MAGICK_ERROR();
587         return HTTP_NOT_FOUND;
588       }
589   
590       if (MagickStripImage(magick_wand) == MagickFalse) {
591         EXIT_MAGICK_ERROR();
592         return HTTP_NOT_FOUND;
593       }
594   
595       if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
596         return HTTP_NOT_FOUND;
597   
598       r->content_type = apr_psprintf(r->pool, "image/gif");
599   
600       DBG(r,"convert to gif");
601     }
602     else
603     if (spec->available_bmp2 || spec->available_bmp4) {
604   
605       if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
606         EXIT_MAGICK_ERROR();
607         return HTTP_NOT_FOUND;
608       }
609   
610       if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
611         EXIT_MAGICK_ERROR();
612         return HTTP_NOT_FOUND;
613       }
614   
615       if (MagickStripImage(magick_wand) == MagickFalse) {
616         EXIT_MAGICK_ERROR();
617         return HTTP_NOT_FOUND;
618       }
619   
620       if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
621         return HTTP_NOT_FOUND;
622   
623       r->content_type = apr_psprintf(r->pool, "image/bmp");
624   
625       DBG(r, "convert to bmp(unsupported)");
626     }
627   
628     /*
629      * Add Comment (Copyright and so on.)
630      */
631     DBG(r, "call s_add_copyright()");
632   
633     if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL) 
634       return HTTP_NOT_FOUND;
635   }
636   else {
637     char* fmt;
638     fmt = MagickGetImageFormat(magick_wand);
639     if (fmt == NULL) {
640       if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
641         EXIT_MAGICK_ERROR();
642         return HTTP_NOT_FOUND;
643       }
644   
645       r->content_type = apr_psprintf(r->pool, "image/jpeg");
646     }
647     else {
648       if (strcasecmp(fmt, "jpg") == 0) {
649         r->content_type = apr_psprintf(r->pool, "image/jpeg");
650       }
651       else
652       if (strcasecmp(fmt, "jpeg") == 0) {
653         r->content_type = apr_psprintf(r->pool, "image/jpeg");
654       }
655       else
656       if (strcasecmp(fmt, "gif") == 0) {
657         r->content_type = apr_psprintf(r->pool, "image/gif");
658       }
659       else
660       if (strcasecmp(fmt, "png") == 0) {
661         r->content_type = apr_psprintf(r->pool, "image/png");
662       }
663     }
664   }
665
666   writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
667
668   if (! writebyte) {
669     DestroyMagickWand(magick_wand);
670     ERR1(r,"convert failure to Jpeg [%s]", tmpfile);
671
672     return HTTP_INTERNAL_SERVER_ERROR;
673   }
674
675   DBG(r, "end convert and compression");
676   
677   /* to cache */
678   rv = apr_file_open(&fout, tmpfile,
679                   APR_WRITE| APR_CREATE | APR_BINARY | APR_SHARELOCK ,APR_OS_DEFAULT,
680                   r->pool);
681   if (rv != APR_SUCCESS) {
682     DestroyMagickWand(magick_wand);
683     ERR1(r,"file open error.[%s]", tmpfile);
684     return HTTP_INTERNAL_SERVER_ERROR;
685   }
686
687   rv = apr_file_write(fout, (void*)writedata, &writebyte);
688   if (rv != APR_SUCCESS) {
689     DestroyMagickWand(magick_wand);
690     apr_file_close(fout);
691     return HTTP_INTERNAL_SERVER_ERROR;
692   }
693
694   /*
695    * CRC is added for AU for EzGET.
696    */
697   if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
698   ||  spec->html_spec_type == CHXJ_SPEC_Hdml            ) {
699
700     crc = s_add_crc(writedata, writebyte);
701
702     rv = apr_file_putc((crc >> 8)  & 0xff, fout);
703     if (rv != APR_SUCCESS) {
704       DestroyMagickWand(magick_wand);
705       return HTTP_INTERNAL_SERVER_ERROR;
706     }
707
708     rv = apr_file_putc( crc        & 0xff, fout);
709     if (rv != APR_SUCCESS) {
710       DestroyMagickWand(magick_wand);
711       return HTTP_INTERNAL_SERVER_ERROR;
712     }
713   }
714
715   DestroyMagickWand(magick_wand);
716
717   rv = apr_file_close(fout);
718   if (rv != APR_SUCCESS) {
719     DBG1(r,"file write error.[%s]", tmpfile);
720     return HTTP_INTERNAL_SERVER_ERROR;
721   }
722
723   return OK;
724 }
725
726
727 static char*
728 s_create_blob_data(request_rec* r, 
729                    device_table* spec, 
730                    query_string_param_t *qsp,
731                    char* indata,
732                    apr_size_t* len)
733 {
734   apr_size_t         writebyte;
735   unsigned short     crc;
736   img_conv_mode_t    mode = qsp->mode;
737
738   char*              writedata = NULL;
739   char*              dst       = NULL;
740
741   MagickWand*        magick_wand;
742
743   magick_wand = NewMagickWand();
744
745   if (MagickReadImageBlob(magick_wand,indata, *len) == MagickFalse) {
746     EXIT_MAGICK_ERROR();
747     return NULL;
748   }
749
750   /*
751    * The size of the image is changed.
752    */
753   DBG(r, "call s_fixup_size()");
754
755   if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL)
756     return NULL;
757
758   /*
759    * The colors of the image is changed.
760    */
761   DBG(r, "call s_fixup_color()");
762
763   if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL)
764     return NULL;
765
766   /*
767    * DEPTH of the image is changed.
768    */
769
770   DBG(r,"call s_fixup_depth()");
771
772   if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL)
773     return NULL;
774
775
776
777   DBG(r,"start convert and compression");
778
779   if (spec->available_jpeg) {
780     if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
781       EXIT_MAGICK_ERROR();
782       return NULL;
783     }
784
785     if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
786       EXIT_MAGICK_ERROR();
787       return NULL;
788     }
789
790     if (MagickStripImage(magick_wand) == MagickFalse) {
791       EXIT_MAGICK_ERROR();
792       return NULL;
793     }
794
795     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
796       return NULL;
797
798     r->content_type = apr_psprintf(r->pool, "image/jpeg");
799
800     DBG(r, "convert to jpg");
801   }
802   else
803   if (spec->available_png) {
804     if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
805       EXIT_MAGICK_ERROR();
806       return NULL;
807     }
808
809     if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
810       EXIT_MAGICK_ERROR();
811       return NULL;
812     }
813
814     if (MagickStripImage(magick_wand) == MagickFalse) {
815       EXIT_MAGICK_ERROR();
816       return NULL;
817     }
818
819     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
820       return NULL;
821
822     r->content_type = apr_psprintf(r->pool, "image/png");
823
824     DBG(r,"convert to png");
825   }
826   else
827   if (spec->available_gif) {
828
829     if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
830       EXIT_MAGICK_ERROR();
831       return NULL;
832     }
833
834     if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
835       EXIT_MAGICK_ERROR();
836       return NULL;
837     }
838
839     if (MagickStripImage(magick_wand) == MagickFalse) {
840       EXIT_MAGICK_ERROR();
841       return NULL;
842     }
843
844     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
845       return NULL;
846
847     r->content_type = apr_psprintf(r->pool, "image/gif");
848
849     DBG(r,"convert to gif");
850   }
851   else
852   if (spec->available_bmp2 || spec->available_bmp4) {
853     if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
854       EXIT_MAGICK_ERROR();
855       return NULL;
856     }
857
858     if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
859       EXIT_MAGICK_ERROR();
860       return NULL;
861     }
862
863     if (MagickStripImage(magick_wand) == MagickFalse) {
864       EXIT_MAGICK_ERROR();
865       return NULL;
866     }
867
868     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
869       return NULL;
870
871     r->content_type = apr_psprintf(r->pool, "image/bmp");
872
873     DBG(r,"convert to bmp(unsupported)");
874   }
875   /*--------------------------------------------------------------------------*/
876   /* Add Comment (Copyright and so on.)                                       */
877   /*--------------------------------------------------------------------------*/
878   DBG(r,"call s_add_copyright()");
879
880   if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL)
881     return NULL;
882
883   writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
884
885   if (! writebyte) {
886     DestroyMagickWand(magick_wand);
887     DBG(r,"convert failure to Jpeg ");
888     return NULL;
889   }
890
891   DBG(r,"end convert and compression");
892
893
894   
895   dst = apr_palloc(r->pool, writebyte+2);
896
897   memcpy(dst, writedata, writebyte);
898   /*--------------------------------------------------------------------------*/
899   /* CRC is added for AU for EzGET.                                           */
900   /*--------------------------------------------------------------------------*/
901   if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
902   ||  spec->html_spec_type == CHXJ_SPEC_Hdml) {
903     crc = s_add_crc(writedata, writebyte);
904     dst[writebyte + 0] = (crc >> 8) & 0xff;
905     dst[writebyte + 1] = (crc     ) & 0xff;
906     writebyte += 2;
907   }
908
909   DestroyMagickWand(magick_wand);
910
911   *len = writebyte;
912   return dst;
913 }
914
915 static MagickWand* 
916 s_fixup_size(MagickWand* magick_wand, 
917                 request_rec* r, 
918                 device_table* spec, 
919                 query_string_param_t *qsp)
920 {
921   img_conv_mode_t mode = qsp->mode;
922   int oldw;
923   int oldh;
924   int neww;
925   int newh;
926   int c_width;
927   int c_heigh;
928
929   oldw = MagickGetImageWidth(magick_wand);
930   oldh = MagickGetImageHeight(magick_wand);
931
932   DBG1(r,"detect width=[%d]", oldw);
933   DBG1(r,"detect heigh=[%d]", oldh);
934
935   neww = oldw;
936   newh = oldh;
937
938   DBG1(r,"detect spec width=[%d]", spec->width);
939   DBG1(r,"detect spec heigh=[%d]", spec->heigh);
940
941   c_width = spec->width;
942   c_heigh = spec->heigh;
943
944   switch(mode) {
945   case IMG_CONV_MODE_THUMBNAIL:
946
947     DBG(r,"**** detect thumbnail mode ****");
948
949     if (neww > c_width) {
950       newh = (int)((double)newh * (double)((double)c_width / (double)neww));
951       neww = (int)((double)neww * (double)((double)c_width / (double)neww));
952     }
953     if (newh > c_heigh) {
954       neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
955       newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
956     }
957
958     neww = (int)((double)(neww / 3) * 0.8);
959     newh = (int)((double)(newh / 3) * 0.8);
960     break;
961
962   case IMG_CONV_MODE_WALLPAPER:
963   case IMG_CONV_MODE_EZGET:
964
965     DBG(r,"**** detect wallpaper mode ****");
966
967     if (spec->wp_width && spec->wp_heigh) {
968       c_width = spec->wp_width;
969       c_heigh = spec->wp_heigh;
970     }
971
972     DBG(r,"calc new width and height");
973
974     neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
975     newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
976
977     DBG2(r,"newh = [%d] neww = [%d]", newh, neww);
978     break;
979
980   default:
981
982     DBG(r,"**** detect normal mode ****");
983
984     if (qsp->ua_flag != UA_IGN && spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
985       if (neww > c_width) {
986         newh = (int)((double)newh * (double)((double)c_width / (double)neww));
987         neww = (int)((double)neww * (double)((double)c_width / (double)neww));
988       }
989
990       if (newh > c_heigh) {
991         neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
992         newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
993       }
994     }
995     break;
996   }
997
998   if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
999     DBG2(r,"convert width=[%d --> %d]", oldw, neww);
1000     DBG2(r,"convert heigh=[%d --> %d]", oldh, newh);
1001   
1002     MagickResetIterator(magick_wand);
1003   
1004     while (MagickNextImage(magick_wand) != MagickFalse) {
1005       switch (mode) {
1006       case IMG_CONV_MODE_WALLPAPER:
1007       case IMG_CONV_MODE_EZGET:
1008   
1009         if (MagickResizeImage(magick_wand,neww,newh,LanczosFilter,1.0) == MagickFalse) {
1010           EXIT_MAGICK_ERROR();
1011           return NULL;
1012         }
1013   
1014         if (MagickCropImage(magick_wand, 
1015                         (unsigned long)c_width, 
1016                         (unsigned long)c_heigh,
1017                         (long)((neww - c_width) / 2),
1018                         (long)((newh - c_heigh) / 2)) == MagickFalse) {
1019           EXIT_MAGICK_ERROR();
1020           return NULL;
1021         }
1022         break;
1023   
1024       case IMG_CONV_MODE_NORMAL:
1025         if (qsp->width) {
1026           DBG2(r,"convert width=[%d --> %d]", neww, qsp->width);
1027           neww = qsp->width;
1028         }
1029         if (qsp->height) {
1030           DBG2(r,"convert heigh=[%d --> %d]", newh, qsp->height);
1031           newh = qsp->height;
1032         }
1033   
1034       default:
1035         if (MagickResizeImage(magick_wand,neww,newh,LanczosFilter,1.0) == MagickFalse) {
1036           EXIT_MAGICK_ERROR();
1037           return NULL;
1038         }
1039         break;
1040       }
1041   
1042       if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
1043         if (MagickSetImageUnits(magick_wand, PixelsPerInchResolution) == MagickFalse) {
1044           EXIT_MAGICK_ERROR();
1045           return NULL;
1046         }
1047     
1048         if (MagickSetImageResolution(magick_wand,
1049                                      (double)spec->dpi_width,
1050                                      (double)spec->dpi_heigh) == MagickFalse) {
1051           EXIT_MAGICK_ERROR();
1052           return NULL;
1053         }
1054     
1055         if (MagickSetImageDispose(magick_wand, BackgroundDispose) == MagickFalse) {
1056           EXIT_MAGICK_ERROR();
1057           return NULL;
1058         }
1059       }
1060     }
1061   }
1062   return magick_wand;
1063 }
1064
1065 static MagickWand*
1066 s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_conv_mode_t UNUSED(mode))
1067 {
1068   DBG(r,"start chxj_fixup_clor()");
1069
1070   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
1071     DBG(r, "Pass s_fixup_color proc");
1072     return magick_wand;
1073   }
1074
1075   if (spec->color >= 256) {
1076
1077     DBG1(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color);
1078
1079     if (MagickQuantizeImage(magick_wand,
1080                            spec->color,
1081                            RGBColorspace,
1082                            0,
1083                            1,
1084                            0) == MagickFalse) {
1085       EXIT_MAGICK_ERROR();
1086       return NULL;
1087     }
1088
1089     DBG1(r,"call end MagickQuantizeImage() spec->color=[%d]",spec->color);
1090
1091   }
1092   else {
1093     DBG1(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color);
1094
1095     if (MagickQuantizeImage(magick_wand,
1096                            spec->color,
1097                            GRAYColorspace,
1098                            0,
1099                            1,
1100                            0) == MagickFalse) {
1101       EXIT_MAGICK_ERROR();
1102       return NULL;
1103     }
1104
1105     DBG1(r,"call end MagickQuantizeImage() spec->color=[%d]",spec->color);
1106   }
1107
1108
1109   DBG(r,"end chxj_fixup_clor()");
1110
1111   return magick_wand;
1112 }
1113
1114
1115
1116 static MagickWand*
1117 s_fixup_depth(MagickWand* magick_wand, request_rec* r, device_table* spec)
1118 {
1119   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
1120     DBG(r, "Pass s_fixup_depth proc");
1121     return magick_wand;
1122   }
1123
1124   if (spec->color == 15680000) {
1125     if (MagickSetImageDepth(magick_wand, 24) == MagickFalse) {
1126       EXIT_MAGICK_ERROR();
1127       return NULL;
1128     }
1129   }
1130   else 
1131   if (spec->color == 262144) {
1132     if (MagickSetImageDepth(magick_wand, 18) == MagickFalse) {
1133       EXIT_MAGICK_ERROR();
1134       return NULL;
1135     }
1136   }
1137   else
1138   if (spec->color == 65536) {
1139     if (MagickSetImageDepth(magick_wand, 16) == MagickFalse) {
1140       EXIT_MAGICK_ERROR();
1141       return NULL;
1142     }
1143   }
1144   else
1145   if (spec->color == 4096) {
1146     if (MagickSetImageDepth(magick_wand, 12) == MagickFalse) {
1147       EXIT_MAGICK_ERROR();
1148       return NULL;
1149     }
1150   }
1151   else
1152   if (spec->color == 256) {
1153     if (MagickSetImageDepth(magick_wand, 8) == MagickFalse) {
1154       EXIT_MAGICK_ERROR();
1155       return NULL;
1156     }
1157   }
1158   else
1159   if (spec->color == 4) {
1160     if (MagickSetImageDepth(magick_wand, 2) == MagickFalse) {
1161       EXIT_MAGICK_ERROR();
1162       return NULL;
1163     }
1164   }
1165   else
1166   if (spec->color == 2) {
1167     if (MagickSetImageDepth(magick_wand, 1) == MagickFalse) {
1168       EXIT_MAGICK_ERROR();
1169       return NULL;
1170     }
1171   }
1172
1173   return magick_wand;
1174 }
1175
1176
1177 static MagickWand*
1178 s_add_copyright(MagickWand* magick_wand, request_rec* r, device_table* spec)
1179 {
1180   mod_chxj_config* conf = ap_get_module_config(r->per_dir_config, &chxj_module);
1181
1182   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
1183     DBG(r, "Pass add_copiright proc");
1184     return magick_wand;
1185   }
1186
1187   if (conf->image_copyright) {
1188
1189     DBG1(r, "Add COPYRIGHT [%s]", conf->image_copyright);
1190
1191     if (spec->html_spec_type == CHXJ_SPEC_Jhtml) {
1192       apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
1193       if (MagickCommentImage(magick_wand, 
1194                              apr_psprintf(r->pool, 
1195                                           "Copyright(C) %s", 
1196                                           conf->image_copyright)) == MagickFalse) 
1197         goto on_error;
1198     }
1199     else
1200     if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
1201     ||  spec->html_spec_type == CHXJ_SPEC_Hdml) {
1202       if (MagickCommentImage(magick_wand, 
1203                              apr_psprintf(r->pool, 
1204                                          "kddi_copyright=on,%s", 
1205                                           conf->image_copyright)) == MagickFalse) 
1206         goto on_error;
1207     }
1208     else {
1209       if (MagickCommentImage(magick_wand, 
1210                             apr_psprintf(r->pool, 
1211                                          "copy=\"NO\",%s",
1212                                          conf->image_copyright)) == MagickFalse)
1213         goto on_error;
1214     }
1215   }
1216   else {
1217     if (MagickCommentImage(magick_wand, "mod_chxj") == MagickFalse)
1218       goto on_error;
1219   }
1220   return magick_wand;
1221
1222 on_error:
1223   EXIT_MAGICK_ERROR();
1224   return NULL;
1225 }
1226
1227 static MagickWand*
1228 s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec)
1229 {
1230   MagickBooleanType  status;
1231   unsigned long quality = 70;
1232   apr_size_t    writebyte = 0;
1233   char*         writedata;
1234   apr_size_t    prev_size = 0;
1235   int           revers_flag = 0;
1236
1237   writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1238   prev_size = writebyte;
1239
1240   do {
1241     if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
1242       EXIT_MAGICK_ERROR();
1243       return NULL;
1244     }
1245
1246     writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1247     if (writebyte >= prev_size || revers_flag) {
1248       DBG2(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte);
1249       revers_flag = 1;
1250       quality += 10;
1251       if (quality > 100) {
1252         if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
1253           EXIT_MAGICK_ERROR();
1254           return NULL;
1255         }
1256         break;
1257       }
1258       prev_size = writebyte;
1259       continue;
1260     }
1261
1262     DBG2(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte);
1263
1264     if (spec->cache == 0)
1265       break;
1266
1267     if (writebyte <= (unsigned int)spec->cache)
1268       break;
1269
1270     quality -= 10;
1271
1272     if (quality == 0 || quality > 100)
1273       break;
1274
1275   }
1276   while (1);
1277
1278
1279   if (spec->cache > 0 
1280   &&  writebyte   > (unsigned int)spec->cache) {
1281     unsigned long now_color = spec->color;
1282     unsigned long depth     = 0;
1283     do {
1284       switch(now_color) {
1285       case 2:      depth = 1; break;
1286       case 4:      now_color = 2;        depth = 1;  break;
1287       case 8:      now_color = 4;        depth = 2;  break;
1288       case 16:     now_color = 8;        depth = 3;  break;
1289       case 256:    now_color = 16;       depth = 4;  break;
1290       case 4096:   now_color = 256;      depth = 8;  break;
1291       case 65536:  now_color = 4096;     depth = 12; break;
1292       case 262144: now_color = 65536;    depth = 16; break;
1293       case 15680000: now_color = 262144; depth = 18; break;
1294       default:
1295         now_color = 2;
1296         break;
1297       }
1298
1299       if (now_color <= 2) break;
1300
1301       if (now_color >= 8) {
1302         status = MagickQuantizeImage(magick_wand,
1303                              now_color,
1304                              RGBColorspace,
1305                              0,
1306                              1,
1307                              0);
1308       }
1309       else {
1310         status = MagickQuantizeImage(magick_wand,
1311                              now_color,
1312                              GRAYColorspace,
1313                              0,
1314                              1,
1315                              0);
1316         MagickSetImageType(magick_wand, GrayscaleType);
1317       }
1318       if (status == MagickFalse) {
1319         EXIT_MAGICK_ERROR();
1320         return NULL;
1321       }
1322
1323       if (MagickSetImageDepth(magick_wand, depth) == MagickFalse) {
1324         EXIT_MAGICK_ERROR();
1325         return NULL;
1326       }
1327
1328       writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1329
1330       DBG2(r,"now_color=[%ld] size=[%d]", (long)now_color, (int)writebyte);
1331
1332       /* Once per request */
1333       break;
1334     }
1335     while(now_color > 2);
1336   }
1337
1338   return magick_wand;
1339 }
1340
1341 static apr_status_t 
1342 s_send_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile)
1343 {
1344   apr_status_t rv;
1345   apr_finfo_t  st;
1346   apr_file_t*  fout;
1347   apr_size_t   sendbyte;
1348   char*        contentLength;
1349
1350   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
1351   if (rv != APR_SUCCESS)
1352     return HTTP_NOT_FOUND;
1353
1354   DBG1(r, "mode:[%d]",    query_string->mode);
1355   DBG1(r, "name:[%s]",    query_string->name);
1356   DBG1(r, "offset:[%ld]", query_string->offset);
1357   DBG1(r, "count:[%ld]",  query_string->count);
1358
1359   if (spec->available_jpeg) {
1360     r->content_type = apr_psprintf(r->pool, "image/jpeg");
1361   }
1362   else
1363   if (spec->available_png) {
1364     r->content_type = apr_psprintf(r->pool, "image/png");
1365   }
1366   else
1367   if (spec->available_gif) {
1368     r->content_type = apr_psprintf(r->pool, "image/gif");
1369   }
1370   else
1371   if (spec->available_bmp2 || spec->available_bmp4) {
1372     r->content_type = apr_psprintf(r->pool, "image/bmp");
1373   }
1374
1375   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
1376     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
1377     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1378   
1379     DBG1(r,"Content-Length:[%d]", (int)st.size);
1380
1381     rv = apr_file_open(&fout, tmpfile, 
1382       APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
1383     if (rv != APR_SUCCESS) {
1384       DBG1(r, "tmpfile open failed[%s]", tmpfile);
1385       return HTTP_NOT_FOUND;
1386     }
1387
1388     ap_send_fd(fout, r, 0, st.size, &sendbyte);
1389     apr_file_close(fout);
1390     ap_rflush(r);
1391     DBG1(r, "send file data[%d]byte", (int)sendbyte);
1392   }
1393   else
1394   if (query_string->mode == IMG_CONV_MODE_EZGET) {
1395     char* name = apr_pstrdup(r->pool, basename(r->filename));
1396     name[strlen(name)-4] = 0;
1397     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
1398
1399       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1400       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".jpg", (long)st.size, "devjaww", name);
1401     }
1402     else
1403     if (strcasecmp(r->content_type, "image/bmp") == 0) {
1404       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1405       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".bmp", (long)st.size, "devabm", name);
1406     }
1407     else
1408     if (strcasecmp(r->content_type, "image/png") == 0) {
1409       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1410       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".png", (long)st.size, "dev8aww", name);
1411     }
1412     else
1413     if (strcasecmp(r->content_type, "image/gif") == 0) {
1414       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1415       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".gif", (long)st.size, "devgi0z", name);
1416     }
1417   }
1418   else
1419   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
1420     if (query_string->count == -1 && query_string->offset == -1) {
1421       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1422       ap_rprintf(r, HDML_SUCCESS_PAGE);
1423       ap_rflush(r);
1424     }
1425     else
1426     if (query_string->count == -2 && query_string->offset == -1) {
1427       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1428       ap_rprintf(r, HDML_FAIL_PAGE);
1429       ap_rflush(r);
1430     }
1431     else { 
1432       ap_set_content_type(r, "application/x-up-download");
1433       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
1434       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1435   
1436       DBG1(r, "Content-Length:[%d]", (int)st.size);
1437
1438       rv = apr_file_open(&fout, tmpfile, 
1439         APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
1440
1441       if (rv != APR_SUCCESS) {
1442         DBG1(r,"tmpfile open failed[%s]", tmpfile);
1443         return HTTP_NOT_FOUND;
1444       }
1445
1446       ap_send_fd(fout, r, query_string->offset, query_string->count, &sendbyte);
1447       apr_file_close(fout);
1448       ap_rflush(r);
1449       DBG1(r, "send file data[%d]byte", (int)sendbyte);
1450     }
1451   }
1452   
1453   return OK;
1454 }
1455
1456 static apr_status_t 
1457 s_header_only_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile)
1458 {
1459   apr_status_t rv;
1460   apr_finfo_t  st;
1461   char*        contentLength;
1462
1463   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
1464   if (rv != APR_SUCCESS)
1465     return HTTP_NOT_FOUND;
1466
1467   DBG1(r, "mode:[%d]",    query_string->mode);
1468   DBG1(r, "name:[%s]",    query_string->name);
1469   DBG1(r, "offset:[%ld]", query_string->offset);
1470   DBG1(r, "count:[%ld]",  query_string->count);
1471
1472   if (spec->available_jpeg) {
1473     r->content_type = apr_psprintf(r->pool, "image/jpeg");
1474   }
1475   else
1476   if (spec->available_png) {
1477     r->content_type = apr_psprintf(r->pool, "image/png");
1478   }
1479   else
1480   if (spec->available_gif) {
1481     r->content_type = apr_psprintf(r->pool, "image/gif");
1482   }
1483   else
1484   if (spec->available_bmp2 || spec->available_bmp4) {
1485     r->content_type = apr_psprintf(r->pool, "image/bmp");
1486   }
1487
1488   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
1489     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
1490     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1491   
1492     DBG1(r,"Content-Length:[%d]", (int)st.size);
1493   }
1494   else
1495   if (query_string->mode == IMG_CONV_MODE_EZGET) {
1496     char* name = apr_pstrdup(r->pool, basename(r->filename));
1497     name[strlen(name)-4] = 0;
1498     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
1499
1500       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1501     }
1502     else
1503     if (strcasecmp(r->content_type, "image/bmp") == 0) {
1504       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1505     }
1506     else
1507     if (strcasecmp(r->content_type, "image/png") == 0) {
1508       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1509     }
1510     else
1511     if (strcasecmp(r->content_type, "image/gif") == 0) {
1512       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1513     }
1514   }
1515   else
1516   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
1517     if (query_string->count == -1 && query_string->offset == -1) {
1518       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1519     }
1520     else
1521     if (query_string->count == -2 && query_string->offset == -1) {
1522       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1523     }
1524     else { 
1525       ap_set_content_type(r, "application/x-up-download");
1526       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
1527       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1528   
1529       DBG1(r, "Content-Length:[%d]", (int)st.size);
1530     }
1531   }
1532   
1533   return OK;
1534 }
1535
1536
1537
1538 static char*
1539 s_create_workfile(
1540                 request_rec*          r, 
1541                 mod_chxj_config*      conf, 
1542                 const char*           user_agent, 
1543                 query_string_param_t *qsp)
1544 {
1545   int ii;
1546   int jj;
1547   int len;
1548   char* w = apr_palloc(r->pool, 256);
1549   char* fname;
1550
1551   memset(w, 0, 256);
1552   switch (qsp->mode) {
1553   case IMG_CONV_MODE_THUMBNAIL:
1554     fname = apr_psprintf(r->pool, "%s.%s.thumbnail", r->filename, user_agent);
1555     DBG1(r, "mode=thumbnail [%s]", fname);
1556     break;
1557   case IMG_CONV_MODE_WALLPAPER:
1558   case IMG_CONV_MODE_EZGET:
1559     fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, user_agent);
1560     DBG1(r, "mode=WallPaper [%s]", fname);
1561     break;
1562   case IMG_CONV_MODE_NORMAL:
1563   default:
1564
1565     fname = apr_psprintf(r->pool, "%s.%s", r->filename, user_agent);
1566
1567     if (qsp->width)
1568       fname = apr_psprintf(r->pool, "%s.w%d", fname, qsp->width);
1569
1570     if (qsp->height)
1571       fname = apr_psprintf(r->pool, "%s.h%d", fname, qsp->height);
1572
1573     DBG1(r,"mode=normal [%s]", fname);
1574     break;
1575   }
1576   if (qsp->ua_flag == UA_IGN) {
1577     fname = apr_psprintf(r->pool, "%s.IGN", fname);
1578   }
1579
1580   len = strlen(fname);
1581   jj=0;
1582   for  (ii=0; ii<len; ii++) {
1583     if (fname[ii] == '/' 
1584     ||  fname[ii] == ' ' 
1585     ||  fname[ii] == '-' 
1586     ||  fname[ii] == '(' 
1587     ||  fname[ii] == ')') {
1588       w[jj++] = '_';
1589     }
1590     else {
1591       w[jj++] = fname[ii];
1592     }
1593   }
1594
1595   return apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir,w);
1596 }
1597
1598 static unsigned short
1599 s_add_crc(const char* writedata, apr_size_t writebyte)
1600 {
1601   unsigned short crc = 0xffff;
1602   apr_size_t     ii;
1603   unsigned char  ch;
1604
1605   for(ii=0;ii<writebyte;ii++) {
1606     ch  = writedata[ii];
1607     crc = AU_CRC_TBL[(crc>>8^ch)&0xff]^(crc<<8);
1608   }
1609   return crc;
1610 }
1611
1612 int
1613 chxj_trans_name(request_rec *r)
1614 {
1615   const char* ccp;
1616   char* docroot;
1617   int len;
1618   apr_finfo_t st;
1619   apr_status_t rv;
1620   mod_chxj_config* conf;
1621   int ii;
1622   char*      ext[] = {
1623           "jpg",
1624           "jpeg",
1625           "png",
1626           "bmp",
1627           "gif",
1628           "qrc",    /* QRCode½ÐÎÏÍÑ¥Õ¥¡¥¤¥ë¤Î³ÈÄ¥»Ò */
1629           "",
1630   };
1631   char*    fname;
1632   char*    idx;
1633   char*    filename_sv;
1634   int      do_ext_check = TRUE;
1635   int      next_ok      = FALSE;
1636
1637   DBG(r, "start chxj_trans_name()");
1638
1639   conf = ap_get_module_config(r->per_dir_config, &chxj_module);
1640
1641   if (conf == NULL) {
1642     DBG1(r, "end chxj_trans_name() conf is null[%s]", r->uri);
1643     return DECLINED;
1644   }
1645
1646   if (conf->image != CHXJ_IMG_ON) {
1647     DBG(r, "end chxj_trans_name() conf not found");
1648     return DECLINED;
1649   }
1650
1651
1652   DBG1(r,"Match URI[%s]", r->uri);
1653
1654
1655   if (r->filename == NULL) 
1656     r->filename = apr_pstrdup(r->pool, r->uri);
1657
1658   filename_sv = NULL;
1659   if ((idx = strchr(r->filename, ':')) != NULL) 
1660     filename_sv = idx+1;
1661   else 
1662     filename_sv = r->filename;
1663
1664   DBG1(r,"r->filename[%s]", filename_sv);
1665
1666   ccp = ap_document_root(r);
1667   if (ccp == NULL)
1668     return HTTP_INTERNAL_SERVER_ERROR;
1669
1670   docroot = apr_pstrdup(r->pool, ccp);
1671   len = strlen(docroot);
1672
1673   if (docroot[len-1] == '/') 
1674     docroot[len-1] = '\0';
1675
1676
1677   if (r->server->path 
1678   &&  *filename_sv == *r->server->path 
1679   &&  strncmp(filename_sv, r->server->path, r->server->pathlen) == 0)
1680     filename_sv = apr_pstrcat(r->pool, docroot, (filename_sv + r->server->pathlen), NULL);
1681   else
1682     filename_sv = apr_pstrcat(r->pool, docroot, filename_sv, NULL);
1683
1684   DBG1(r,"URI[%s]", filename_sv);
1685
1686   do_ext_check = TRUE;
1687   for (ii=0; ii<7-1; ii++) {
1688     char* pos = strrchr(filename_sv, '.');
1689     if (pos && pos++) {
1690       if (strcasecmp(pos, ext[ii]) == 0) {
1691         do_ext_check = FALSE;
1692         fname = apr_psprintf(r->pool, "%s", filename_sv);
1693         break;
1694       }
1695     }
1696   }
1697
1698   if (do_ext_check) {
1699     for (ii=0; ii<7; ii++) {
1700       if (strlen(ext[ii]) == 0) {
1701         fname = apr_psprintf(r->pool, "%s", filename_sv);
1702       }
1703       else 
1704         fname = apr_psprintf(r->pool, "%s.%s", filename_sv, ext[ii]);
1705   
1706       DBG1(r,"search [%s]", fname);
1707   
1708       rv = apr_stat(&st, fname, APR_FINFO_MIN, r->pool);
1709       if (rv == APR_SUCCESS) {
1710         if (st.filetype != APR_DIR)
1711           break;
1712       }
1713   
1714       fname = NULL;
1715     }
1716   }
1717   if (fname == NULL) {
1718     DBG1(r,"NotFound [%s]", r->filename);
1719     return DECLINED;
1720   }
1721   for (ii=0; ii<7-1; ii++) {
1722     char* pos = strrchr(fname, '.');
1723     if (pos && pos++) {
1724       if (strcasecmp(pos, ext[ii]) == 0) {
1725         next_ok = TRUE;
1726         break;
1727       }
1728     }
1729   }
1730
1731   if (! next_ok)  {
1732     DBG1(r,"NotFound [%s]", r->filename);
1733     return DECLINED;
1734   }
1735
1736   if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) {
1737     DBG1(r,"Found [%s]", fname);
1738
1739     r->filename = apr_psprintf(r->pool, "%s", fname);
1740   
1741     if (strcasecmp("qrc", ext[ii]) == 0)
1742       r->handler = apr_psprintf(r->pool, "chxj-qrcode");
1743     else
1744       r->handler = apr_psprintf(r->pool, "chxj-picture");
1745   }
1746   DBG(r, "end chxj_trans_name()");
1747   return OK;
1748 }
1749
1750
1751
1752 /**
1753  * It converts it from QUERYSTRING.
1754  *
1755  * @param r   [i]
1756  */
1757 static query_string_param_t*
1758 s_get_query_string_param(request_rec *r)
1759 {
1760   char* pair;
1761   char* name;
1762   char* value;
1763   char* pstate;
1764   char* vstate;
1765   char* s;
1766   query_string_param_t* param;
1767
1768   s = apr_pstrdup(r->pool, r->parsed_uri.query);
1769   param = apr_palloc(r->pool, sizeof(query_string_param_t));
1770   param->mode       = IMG_CONV_MODE_NORMAL;
1771   param->user_agent = NULL;
1772   param->ua_flag    = UA_USE;
1773   param->name       = NULL;
1774   param->offset     = 0;
1775   param->count      = 0;
1776   param->width      = 0;
1777   param->height     = 0;
1778
1779   if (s == NULL) return param;
1780
1781   for (;;) {
1782     if ((pair = apr_strtok(s, "&", &pstate)) == NULL) break;
1783     s = NULL;
1784
1785     name  = apr_strtok(pair, "=", &vstate);
1786     value = apr_strtok(NULL, "=", &vstate);
1787
1788     switch (*name) {
1789     case 'm':
1790     case 'M':
1791       if (value && (strcasecmp(name, "mode") == 0 || strcasecmp(name, "m") == 0)) {
1792
1793         switch (*value) {
1794         case 't':
1795         case 'T':
1796           if (strcasecmp(value, "thumbnail") == 0 || strcasecmp(value, "tb") == 0)
1797             param->mode = IMG_CONV_MODE_THUMBNAIL;
1798           break;
1799   
1800         case 'w':
1801         case 'W':
1802           if (strcasecmp(value, "WP") == 0 || strcasecmp(value, "WallPaper") == 0)
1803             param->mode = IMG_CONV_MODE_WALLPAPER;
1804           break;
1805   
1806         case 'e':
1807         case 'E':
1808           if (strcasecmp(value, "EZGET") == 0)
1809             param->mode = IMG_CONV_MODE_EZGET;
1810           break;
1811         default:
1812           break;
1813         }
1814       }
1815       break;
1816
1817     case 'u':
1818     case 'U':
1819       if (value && (strcasecmp(name, "ua") == 0 || strcasecmp(name, "user-agent") == 0)) {
1820         ap_unescape_url(value);
1821
1822         if ((*value == 'i' || *value == 'I') && strcasecmp(value, "IGN") == 0)
1823           param->ua_flag = UA_IGN;
1824
1825         param->user_agent = apr_pstrdup(r->pool, value);
1826       }
1827       break;
1828
1829     case 'n':
1830     case 'N':
1831       if (value && strcasecmp(name, "name") == 0)
1832         param->name = apr_pstrdup(r->pool, value);
1833       break;
1834
1835     case 'o':
1836     case 'O':
1837       if (value && strcasecmp(name, "offset") == 0 && (! chxj_chk_numeric(value)))
1838         param->offset = chxj_atoi(value);
1839
1840       break;
1841
1842     case 'c':
1843     case 'C':
1844       if (value && strcasecmp(name, "count") == 0 && (! chxj_chk_numeric(value)))
1845         param->count = chxj_atoi(value);
1846       break;
1847
1848     case 'w':
1849     case 'W':
1850       if (value && strcasecmp(name, "w") == 0 && (! chxj_chk_numeric(value)))
1851         param->width = chxj_atoi(value);
1852       break;
1853
1854     case 'h':
1855     case 'H':
1856       if (value && strcasecmp(name, "h") == 0 && (! chxj_chk_numeric(value)))
1857         param->height = chxj_atoi(value);
1858       break;
1859
1860     default:
1861       break;
1862     }
1863   }
1864
1865   if (param->mode == IMG_CONV_MODE_NORMAL && param->name)
1866     param->mode = IMG_CONV_MODE_WALLPAPER;
1867
1868   return param;
1869 }
1870 /*
1871  * vim:ts=2 et
1872  */