OSDN Git Service

* Fixed bug
[modchxj/mod_chxj.git] / src / chxj_img_conv_format.c
index 3c757d8..a39d96a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
+ * Copyright (C) 2005-2009 Atsushi Konno All rights reserved.
  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
 #include "chxj_apply_convrule.h"
 #include "chxj_url_encode.h"
 #include "qs_parse_string.h"
+#include "chxj_preg_replace.h"
 
 #include "http_core.h"
 
 #include <wand/magick_wand.h>
 
+#if !defined(LONG_LONG_MAX) && defined(LLONG_MAX)
+#  define LONG_LONG_MAX LLONG_MAX
+#endif
+
 
 #define EXIT_MAGICK_ERROR() \
   do { \
     char *description; ExceptionType severity; \
     description=MagickGetException(magick_wand,&severity); \
-    ap_log_rerror(APLOG_MARK,APLOG_DEBUG, 0, r,"%s %s %d %s\n",__FILE__,(__func__),__LINE__,description); \
+    ap_log_rerror(APLOG_MARK,APLOG_ERR, 0, r,"%s %s %d %s\n",__FILE__,(__func__),__LINE__,description); \
     description=(char *) MagickRelinquishMemory(description); \
     DestroyMagickWand(magick_wand); \
-  }while(1
+  } while(0
 
 typedef enum img_conv_mode_t {
   IMG_CONV_MODE_NORMAL = 0,
@@ -61,10 +66,10 @@ typedef struct query_string_param_t query_string_param_t;
 
 struct query_string_param_t {
   img_conv_mode_t   mode;
-  char*             user_agent;
+  char              *user_agent;
   ua_use_flag_t     ua_flag;
 
-  char*             name;      /* for EZGET */
+  char              *name;      /* for EZGET */
   long              offset;    /* for EZGET */
   long              count;     /* for EZGET */
   int               width;
@@ -76,6 +81,7 @@ struct query_string_param_t {
 /*----------------------------------------------------------------------------*/
 static device_table v_ignore_spec = {
   NULL,
+  0,
   "IGN",
   "IGN",
   CHXJ_SPEC_HTML,
@@ -93,6 +99,7 @@ static device_table v_ignore_spec = {
   96,
   65536,
   NULL,
+  "Shift_JIS"
 };
 
 /*----------------------------------------------------------------------------*/
@@ -136,14 +143,14 @@ static unsigned short  AU_CRC_TBL[256] = {
 /*----------------------------------------------------------------------------*/
 /* Download page for AU                                                       */
 /*----------------------------------------------------------------------------*/
-static const charHDML_FIRST_PAGE = 
+static const char *HDML_FIRST_PAGE = 
   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
   "  <NODISPLAY>\r\n"
   "    <ACTION TYPE=ACCEPT TASK=GOSUB DEST=\"device:data/dnld?url=%s&name=%s%s&size=%ld&disposition=%s&title=%s\">\r\n"
   "  </NODISPLAY>\r\n"
   "</HDML>\r\n";
 
-static const charHDML_SUCCESS_PAGE =
+static const char *HDML_SUCCESS_PAGE =
   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
   "  <DISPLAY>\r\n"
   "    <ACTION TYPE=ACCEPT TASK=RETURN>\r\n"
@@ -151,7 +158,7 @@ static const char* HDML_SUCCESS_PAGE =
   "  </DISPLAY>\r\n"
   "<HDML>\r\n";
 
-static const charHDML_FAIL_PAGE =
+static const char *HDML_FAIL_PAGE =
   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
   "  <DISPLAY>\r\n"
   "    <ACTION TYPE=ACCEPT TASK=RETURN>\r\n"
@@ -159,101 +166,115 @@ static const char* HDML_FAIL_PAGE =
   "  </DISPLAY>\r\n"
   "<HDML>\r\n";
 
+static ap_regex_t *v_docomo_serial_pattern1 = NULL;
+static ap_regex_t *v_docomo_serial_pattern2 = NULL;
+static ap_regex_t *v_docomo_serial_pattern3 = NULL;
+static ap_regex_t *v_softbank_serial_pattern1 = NULL;
+
 /*----------------------------------------------------------------------------*/
 /* Prototype declaration                                                      */
 /*----------------------------------------------------------------------------*/
-static char*        s_create_workfile(  request_rec*, 
-                                        mod_chxj_config* 
-                                        const char*, 
-                                        query_string_param_t*);
-
-static apr_status_t s_create_cache_file(request_rec*          r, 
-                                        const char*           tmpfile, 
-                                        device_table*         spec,
-                                        apr_finfo_t*          st,
-                                        query_string_param_tqsp,
-                                        mod_chxj_config       *conf);
-
-static apr_status_t s_send_cache_file(  device_table*         spec,
-                                        query_string_param_t* query_string,
-                                        request_rec*          r,
-                                        const char*           tmpfile);
-
-static apr_status_t s_send_original_file(request_rec* r, 
-                                         const char* originalfile);
-
-static apr_status_t s_header_only_cache_file(device_table*         spec, 
-                                             query_string_param_t* query_string
-                                             request_rec*          r
-                                             const char*           tmpfile);
-
-static query_string_param_t* s_get_query_string_param(request_rec *r);
-
-static unsigned short s_add_crc(        const char* writedata, 
-                                        apr_size_t witebyte);
-
-static MagickWand* s_fixup_size(MagickWand* 
-                                request_recr, 
-                                device_tablespec, 
+static char *s_create_workfile_name(request_rec *, 
+                                    mod_chxj_config *
+                                    const char *,
+                                    query_string_param_t *);
+
+static apr_status_t s_create_cache_file(request_rec          *r, 
+                                        const char           *tmpfile, 
+                                        device_table         *spec,
+                                        apr_finfo_t          *st,
+                                        query_string_param_t *qsp,
+                                        mod_chxj_config      *conf);
+
+static apr_status_t s_send_cache_file(mod_chxj_config       *conf,
+                                      device_table          *spec,
+                                      query_string_param_t  *query_string,
+                                      request_rec           *r,
+                                      const char            *tmpfile);
+
+static apr_status_t s_send_original_file(request_rec *r, 
+                                         const char  *originalfile);
+
+static apr_status_t s_header_only_cache_file(device_table         *spec
+                                             query_string_param_t *query_string
+                                             request_rec          *r, 
+                                             const char           *tmpfile);
+
+static query_string_param_t *s_get_query_string_param(request_rec *r);
+
+static unsigned short s_add_crc(const char *writedata, apr_size_t witebyte);
+
+static MagickWand *s_fixup_size(MagickWand   *
+                                request_rec  *r, 
+                                device_table *spec, 
                                 query_string_param_t *qsp);
 
-static MagickWand* s_fixup_color(MagickWand* magick_wand, 
-                                 request_recr, 
-                                 device_tablespec, 
+static MagickWand *s_fixup_color(MagickWand *magick_wand, 
+                                 request_rec *r, 
+                                 device_table *spec, 
                                  img_conv_mode_t mode);
-static MagickWands_fixup_depth(MagickWand* magick_wand, 
+static MagickWand *s_fixup_depth(MagickWand* magick_wand, 
                                  request_rec* r, device_table* spec);
-static MagickWand* s_img_down_sizing(MagickWand* magick_wand, 
-                                request_rec* r, device_table* spec);
+static MagickWand *s_img_down_sizing(MagickWand *magick_wand, 
+                                request_rec *r, device_table *spec);
 
-static MagickWand* s_add_copyright(MagickWand*   magick_wand,
-                                   request_rec*  r,
-                                   device_tablespec);
+static MagickWand *s_add_copyright(MagickWand *magick_wand,
+                                   request_rec *r,
+                                   device_table *spec);
 
-static char* s_create_blob_data(request_rec*          r,
-                                device_table*         spec,
-                                query_string_param_tqsp,
-                                char*                 indata,
-                                apr_size_t*           len);
+static char *s_create_blob_data(request_rec *r,
+                                device_table *spec,
+                                query_string_param_t *qsp,
+                                char *indata,
+                                apr_size_t *len);
 
-static int s_img_conv_format_from_file(request_rec*          r, 
-                                       mod_chxj_config*      conf, 
-                                       const char*           user_agent,
-                                       query_string_param_t* qsp,
-                                       device_table*         spec);
+static int s_img_conv_format_from_file(request_rec          *r, 
+                                       mod_chxj_config      *conf, 
+                                       const char           *user_agent,
+                                       query_string_param_t *qsp,
+                                       device_table         *spec);
+static int s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_table *spec);
+static int s_convert_to_png(MagickWand *maigck_wand, request_rec *r, device_table *spec);
+static int s_convert_to_gif(MagickWand *magick_wand, request_rec *r, device_table *spec);
+static int s_convert_to_bmp(MagickWand *magick_wand, request_rec *r, device_table *spec);
+static int s_chxj_trans_name2(request_rec *r);
+static char *s_add_comment_to_png(request_rec *r, char *data, apr_size_t *len);
 
 
 
 int 
-chxj_img_conv_format_handler(request_recr)
+chxj_img_conv_format_handler(request_rec *r)
 {
-  mod_chxj_config*      conf;
-  query_string_param_t* qsp;
-  char*                 user_agent;
-  device_table*         spec;
-  chxjconvrule_entry*   entryp;
-
-  DBG(r, "start chxj_img_conv_format_handler()");
-  
-  if ((*r->handler != 'c' && *r->handler != 'C') 
-  ||  (strcasecmp(r->handler, "chxj-picture")
-  &&  strcasecmp(r->handler, "chxj-qrcode"))) {
-    DBG(r, "end chxj_img_conv_format_handler()");
+  mod_chxj_config       *conf;
+  query_string_param_t  *qsp;
+  char                  *user_agent;
+  device_table          *spec;
+  chxjconvrule_entry    *entryp;
+  int                   rtn;
+
+  DBG(r, "REQ[%X] start chxj_img_conv_format_handler()", (unsigned int)(apr_size_t)r);
+
+  s_chxj_trans_name2(r);
+  
+  if (! r->handler || 
+      (r->handler && !STRCASEEQ('c','C',"chxj-picture",r->handler) && !STRCASEEQ('c','C',"chxj-qrcode",r->handler))) {
+    DBG(r, "REQ[%X] Response Code:[%d]", (unsigned int)(apr_size_t)r, r->status);
+    DBG(r, "REQ[%X] end chxj_img_conv_format_handler() r->handler is[%s]", TO_ADDR(r), r->handler);
     return DECLINED;
   }
 
   qsp = s_get_query_string_param(r);
-  conf = ap_get_module_config(r->per_dir_config, &chxj_module);
+  conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
   if (conf == NULL) {
-    DBG(r, "end chxj_img_conv_format_handler() conf is null");
+    DBG(r, "REQ[%X] end chxj_img_conv_format_handler() conf is null",TO_ADDR(r));
     return DECLINED;
   }
 
-  if (strcasecmp(r->handler, "chxj-qrcode") == 0 &&  conf->image == CHXJ_IMG_OFF) {
+  if (STRCASEEQ('c','C',"chxj-qrcode",r->handler) && conf->image == CHXJ_IMG_OFF) {
+    DBG(r, "REQ[%X] end chxj_img_conv_format_handler() chxj-qrcode and ImageEngineOff", (unsigned int)(apr_size_t)r);
     return DECLINED;
   }
 
-
   /*------------------------------------------------------------------------*/
   /* get UserAgent from http header                                         */
   /*------------------------------------------------------------------------*/
@@ -280,11 +301,13 @@ chxj_img_conv_format_handler(request_rec* r)
   else
     spec = chxj_specified_device(r, user_agent);
 
-  DBG(r,"found device_name=[%s]", spec->device_name);
-  DBG(r,"User-Agent=[%s]", user_agent);
+  DBG(r,"REQ[%X] found device_name=[%s]", (unsigned int)(apr_size_t)r, spec->device_name);
+  DBG(r,"REQ[%X] User-Agent=[%s]", (unsigned int)(apr_size_t)r, user_agent);
 
 
-  return s_img_conv_format_from_file(r, conf, user_agent, qsp, spec);
+  rtn = s_img_conv_format_from_file(r, conf, user_agent, qsp, spec);
+  DBG(r, "REQ[%X] end chxj_img_conv_format_handler()", (unsigned int)(apr_size_t)r);
+  return rtn;
 }
 
 
@@ -296,30 +319,30 @@ chxj_img_conv_format_handler(request_rec* r)
  * @param src [i]   It is former image binary data.
  * @param len [i/o] It is length of former image binary data.
  */
-char*
-chxj_exchange_image(request_rec *r, const char** src, apr_size_t* len)
+char *
+chxj_convert_image(request_rec *r, const char **src, apr_size_t *len)
 {
-  mod_chxj_config*      conf;
-  query_string_param_tqsp;
-  char*                 user_agent;
-  device_table*         spec;
-  char*                 dst;
-  char*                 conv_check;
-  chxjconvrule_entryentryp;
+  mod_chxj_config       *conf;
+  query_string_param_t  *qsp;
+  char                  *user_agent;
+  device_table          *spec;
+  char                  *dst;
+  char                  *conv_check;
+  chxjconvrule_entry    *entryp;
 
-  DBG(r, "start chxj_exchange_image()");
+  DBG(r, "REQ[%X] start chxj_convert_image()",(unsigned int)(apr_size_t)r);
 
   conv_check = (char*)apr_table_get(r->headers_in, "CHXJ_IMG_CONV");
   if (conv_check) {
-    DBG(r, "end chxj_exchnage_image() already convert.");
+    DBG(r, "REQ[%X] end chxj_convert_image() already convert.", (unsigned int)(apr_size_t)r);
     return NULL;
   }
 
 
   qsp = s_get_query_string_param(r);
-  conf = ap_get_module_config(r->per_dir_config, &chxj_module);
+  conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
   if (conf == NULL) {
-    DBG(r, "end chxj_exchange_image()");
+    DBG(r, "REQ[%X] end chxj_convert_image()", (unsigned int)(apr_size_t)r);
     return NULL;
   }
 
@@ -347,30 +370,33 @@ chxj_exchange_image(request_rec *r, const char** src, apr_size_t* len)
   DBG(r,"found device_name=[%s]", spec->device_name);
   DBG(r, "User-Agent=[%s]", user_agent);
 
-  if (spec->width == 0 || spec->heigh == 0) 
+  if (spec->width == 0 || spec->heigh == 0) {
+    DBG(r, "REQ[%X] end chxj_convert_image() not convert (width or height is 0)", (unsigned int)(apr_size_t)r);
     return NULL;
+  }
 
   dst = s_create_blob_data(r, spec, qsp, (char*)*src, len);
   if (dst == NULL) 
     *len = 0;
 
-  DBG(r, "end chxj_exchange_image()");
+  DBG(r, "REQ[%X] end chxj_convert_image()", (unsigned int)(apr_size_t)r);
 
   return dst;
 }
 
+
 static int
 s_img_conv_format_from_file(
-                request_rec*          r, 
-                mod_chxj_config*    conf, 
-                const char*           user_agent,
-                query_string_param_tqsp,
-                device_table*       spec)
+                request_rec          *r, 
+                mod_chxj_config      *conf, 
+                const char           *user_agent,
+                query_string_param_t *qsp,
+                device_table         *spec)
 {
   apr_status_t   rv;
   apr_finfo_t    st;
   apr_finfo_t    cache_st;
-  char*          tmpfile;
+  char           *tmpfile;
   int            try_count;
 
   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
@@ -383,13 +409,14 @@ s_img_conv_format_from_file(
   /*--------------------------------------------------------------------------*/
   /* Create Workfile Name                                                     */
   /*--------------------------------------------------------------------------*/
-  tmpfile = s_create_workfile(r, conf, user_agent, qsp);
-  DBG(r,"workfile=[%s]", tmpfile);
+  tmpfile = s_create_workfile_name(r, conf, user_agent, qsp);
+  DBG(r,"REQ[%X] workfile=[%s]", TO_ADDR(r), tmpfile);
 
   rv = apr_stat(&st, r->filename, APR_FINFO_MIN, r->pool);
   if (rv != APR_SUCCESS)
     return HTTP_NOT_FOUND;
 
+  apr_table_setn(r->headers_in, "CHXJ_IMG_CONV", "done");
   try_count = CACHE_RETRY_COUNT;
   do {
     rv = apr_stat(&cache_st, tmpfile, APR_FINFO_MIN, r->pool);
@@ -404,9 +431,9 @@ s_img_conv_format_from_file(
         return rv;
     }
   
-    DBG(r,"color=[%d]", spec->color);
+    DBG(r,"REQ[%X] color=[%d]", TO_ADDR(r), spec->color);
     if (! r->header_only)  {
-      rv = s_send_cache_file(spec, qsp,r, tmpfile);
+      rv = s_send_cache_file(conf, spec, qsp,r, tmpfile);
     }
     else {
       rv = s_header_only_cache_file(spec, qsp, r, tmpfile);
@@ -421,7 +448,6 @@ s_img_conv_format_from_file(
     WRN(r, "cache retry failure....");
     WRN(r, "cache file was deleted...");
   }
-  apr_table_setn(r->headers_in, "CHXJ_IMG_CONV", "done");
 
   DBG(r,"end chxj_img_conv_format");
 
@@ -430,10 +456,10 @@ s_img_conv_format_from_file(
 
 
 static apr_status_t
-s_create_cache_file(request_rec*       r, 
-                    const char*     tmpfile, 
-                    device_tablespec, 
-                    apr_finfo_t*    st, 
+s_create_cache_file(request_rec          *r, 
+                    const char           *tmpfile, 
+                    device_table         *spec, 
+                    apr_finfo_t          *st, 
                     query_string_param_t *qsp,
                     mod_chxj_config      *conf)
 {
@@ -443,22 +469,22 @@ s_create_cache_file(request_rec*       r,
   unsigned short     crc;
   img_conv_mode_t    mode = qsp->mode;
 
-  char*              writedata = NULL;
-  char*              readdata  = NULL;
+  char *writedata = NULL;
+  char *readdata  = NULL;
 
-  apr_file_t*        fout;
-  apr_file_t*        fin;
-  apr_finfo_t        cache_dir_st;
+  apr_file_t  *fout;
+  apr_file_t  *fin;
+  apr_finfo_t cache_dir_st;
 
-  MagickWand*        magick_wand;
+  MagickWand *magick_wand;
+  int        img_count;
 
-  if ((*r->handler == 'c' || *r->handler == 'C') 
-  &&  strcasecmp(r->handler, "chxj-qrcode") == 0) {
+  if (STRCASEEQ('c','C',"chxj-qrcode",r->handler)) {
     /*------------------------------------------------------------------------*/
-    /* QRCODEÍѤΥե¡¥¤¥ë¤Î¾ì¹ç                                               */
+    /* QRCODE用のファイルの場合                                               */
     /*------------------------------------------------------------------------*/
     Doc       doc;
-    Node*     root;
+    Node      *root;
     qr_code_t qrcode;
     int       sts;
 
@@ -485,11 +511,11 @@ s_create_cache_file(request_rec*       r,
   }
   else {
     /*------------------------------------------------------------------------*/
-    /* Ä̾ï¤Î¥¤¥á¡¼¥¸¥Õ¥¡¥¤¥ë¤Î¾ì¹ç                                           */
+    /* 通常のイメージファイルの場合                                           */
     /*------------------------------------------------------------------------*/
     rv = apr_file_open(&fin, 
                     r->filename, 
-                    APR_READ|APR_BINARY ,
+                    APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED,
                     APR_OS_DEFAULT, 
                     r->pool);
     if (rv != APR_SUCCESS) {
@@ -500,13 +526,13 @@ s_create_cache_file(request_rec*       r,
     readdata = apr_palloc(r->pool, st->size);
     rv = apr_file_read_full(fin, (void*)readdata, st->size, &readbyte);
     if (rv != APR_SUCCESS || readbyte != st->size) {
-      DBG(r,"file read failed.[%s]", r->filename);
+      DBG(r,"REQ[%X] file read failed.[%s]", TO_ADDR(r), r->filename);
       apr_file_close(fin);
   
       return HTTP_NOT_FOUND;
     }
   }
-  DBG(r,"start img convert");
+  DBG(r,"REQ[%X] start img convert", TO_ADDR(r));
 
 
   magick_wand = NewMagickWand();
@@ -515,19 +541,53 @@ s_create_cache_file(request_rec*       r,
     return HTTP_NOT_FOUND;
   }
 
-  if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
-    /*
-     * The size of the image is changed.
-     */
-    DBG(r,"call s_fixup_size()");
-  
-    if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) 
+  /*------------------*/
+  /* for AnimationGIF */
+  /*------------------*/
+  img_count = MagickGetNumberImages(magick_wand);
+  DBG(r, "REQ[%X] img_count is [%d]", (unsigned int)(apr_size_t)r, img_count);
+  if (img_count > 1) {
+    MagickSetImageIndex(magick_wand, 0);
+    MagickWand *magick_wand2 = MagickGetImage(magick_wand);
+    DestroyMagickWand(magick_wand);
+    magick_wand = magick_wand2;
+  }
+
+  if (MagickStripImage(magick_wand) == MagickFalse) {
+    ERR(r, "mod_chxj: strip image failure.");
+    EXIT_MAGICK_ERROR();
+    return HTTP_NOT_FOUND;
+  }
+  {
+    MagickWand *magick_wand2;
+    if ((magick_wand2 = MagickCoalesceImages(magick_wand)) == NULL) {
+      EXIT_MAGICK_ERROR();
       return HTTP_NOT_FOUND;
+    }
+    DestroyMagickWand(magick_wand);
+    magick_wand = magick_wand2;
+  }
+
+  if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
+    int oldw = MagickGetImageWidth(magick_wand);
+    int oldh = MagickGetImageHeight(magick_wand);
+    int done_fixup_size = 0;
+    if ((qsp->mode == IMG_CONV_MODE_WALLPAPER && spec->wp_width < oldw && spec->wp_heigh < oldh)
+      || (qsp->mode != IMG_CONV_MODE_WALLPAPER && spec->width < oldw && spec->heigh < oldh)) {
+      /*
+       * The size of the image is changed.
+       */
+      DBG(r,"REQ[%X] call s_fixup_size()", TO_ADDR(r));
   
+      if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) 
+        return HTTP_NOT_FOUND;
+
+      done_fixup_size = 1;
+    }
     /*
      * The colors of the image is changed.
      */
-    DBG(r,"call s_fixup_color()");
+    DBG(r,"REQ[%X] call s_fixup_color()", TO_ADDR(r));
   
     if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) 
       return HTTP_NOT_FOUND;
@@ -535,110 +595,83 @@ s_create_cache_file(request_rec*       r,
     /*
      * DEPTH of the image is changed.
      */
-    DBG(r,"call s_fixup_depth()");
+    DBG(r,"REQ[%X] call s_fixup_depth()", TO_ADDR(r));
   
     if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) 
       return HTTP_NOT_FOUND;
   
   
-  
-    DBG(r,"start convert and compression");
-  
-    if (spec->available_jpeg) {
-      if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
-      }
-  
-      if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
-      }
-  
-      if (MagickStripImage(magick_wand) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
-      }
-  
-      if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
+    if (! done_fixup_size) {
+      /*
+       * The size of the image is changed.
+       */
+      DBG(r,"REQ[%X] call s_fixup_size()", TO_ADDR(r));
+      if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) 
         return HTTP_NOT_FOUND;
-  
-      r->content_type = apr_psprintf(r->pool, "image/jpeg");
-      DBG(r,"convert to jpg");
     }
-    else
-    if (spec->available_png) {
-  
-      if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
-      }
-  
-      if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
-      }
-  
-      if (MagickStripImage(magick_wand) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
+
+    char *nowFormat = MagickGetImageFormat(magick_wand);
+    int fixFormatFlag = 0;
+    if (nowFormat) {
+      if (STRCASEEQ('g','G',"gif",nowFormat)) {
+        if (spec->available_gif) {
+          if (s_convert_to_gif(magick_wand, r, spec)) {
+            return HTTP_NOT_FOUND;
+          }
+          fixFormatFlag = 1;
+        }
       }
-  
-      if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
-        return HTTP_NOT_FOUND;
-  
-      r->content_type = apr_psprintf(r->pool, "image/png");
-      DBG(r, "convert to png");
-    }
-    else
-    if (spec->available_gif) {
-  
-      if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
+      else if (STRCASEEQ('j','J',"jpg",nowFormat)||STRCASEEQ('j','J',"jpeg",nowFormat)) {
+        if (spec->available_jpeg) {
+          if (s_convert_to_jpeg(magick_wand, r, spec)) {
+            return HTTP_NOT_FOUND;
+          }
+          fixFormatFlag = 1;
+        }
       }
-  
-      if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
+      else if (STRCASEEQ('p','P',"png",nowFormat)) {
+        if (spec->available_png) {
+          if (s_convert_to_png(magick_wand, r, spec)) {
+            return HTTP_NOT_FOUND;
+          }
+          fixFormatFlag = 1;
+        }
       }
-  
-      if (MagickStripImage(magick_wand) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
+      else if (STRCASEEQ('b','B',"bmp",nowFormat)) {
+        if (spec->available_bmp4 || spec->available_bmp2) {
+          if (s_convert_to_bmp(magick_wand, r, spec)) {
+            return HTTP_NOT_FOUND;
+          }
+          fixFormatFlag = 1;
+        }
       }
-  
-      if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
-        return HTTP_NOT_FOUND;
-  
-      r->content_type = apr_psprintf(r->pool, "image/gif");
-  
-      DBG(r,"convert to gif");
     }
-    else
-    if (spec->available_bmp2 || spec->available_bmp4) {
+
+    DBG(r,"REQ[%X] start convert and compression", TO_ADDR(r));
   
-      if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
+    if (! fixFormatFlag) {
+      if (spec->available_jpeg) {
+        if (s_convert_to_jpeg(magick_wand, r, spec)) {
+          return HTTP_NOT_FOUND;
+        }
       }
-  
-      if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
+      else if (spec->available_gif) {
+        if (s_convert_to_gif(magick_wand, r, spec)) {
+          return HTTP_NOT_FOUND;
+        }  
       }
+      else if (spec->available_png) {
+        if (s_convert_to_png(magick_wand, r, spec)) {
+          return HTTP_NOT_FOUND;
+        }  
   
-      if (MagickStripImage(magick_wand) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return HTTP_NOT_FOUND;
       }
-  
-      if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
-        return HTTP_NOT_FOUND;
-  
-      r->content_type = apr_psprintf(r->pool, "image/bmp");
-  
-      DBG(r, "convert to bmp(unsupported)");
+      else
+      if (spec->available_bmp2 || spec->available_bmp4) { 
+        if (s_convert_to_bmp(magick_wand, r, spec)) {
+          return HTTP_NOT_FOUND;
+        }
+      }
     }
   
     /*
@@ -679,7 +712,8 @@ s_create_cache_file(request_rec*       r,
     }
   }
 
-  writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
+  char *sv_writedata;
+  sv_writedata = writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
 
   if (! writebyte) {
     DestroyMagickWand(magick_wand);
@@ -687,14 +721,27 @@ s_create_cache_file(request_rec*       r,
 
     return HTTP_INTERNAL_SERVER_ERROR;
   }
+  writedata = apr_palloc(r->pool, writebyte);
+  memcpy(writedata, sv_writedata, writebyte);
 
   DBG(r, "end convert and compression");
+
+  /* Added PNG Comment if type is image/png. */
+  if (r->content_type && strcmp(r->content_type, "image/png") == 0) {
+    if ((writedata = s_add_comment_to_png(r, writedata, &writebyte)) == NULL) {
+      DBG(r, "REQ[%X] Add comment to PNG failure.",(unsigned int)(apr_size_t)r);
+      DestroyMagickWand(magick_wand);
+      if (sv_writedata) free(sv_writedata);
+      return HTTP_INTERNAL_SERVER_ERROR;
+    }
+  }
   
   /* check limit */
   rv = apr_stat(&cache_dir_st, conf->image_cache_dir, APR_FINFO_MIN, r->pool);
   if (rv != APR_SUCCESS) {
     DestroyMagickWand(magick_wand);
     ERR(r,"dir stat error.[%s]", conf->image_cache_dir);
+    if (sv_writedata) free(sv_writedata);
     return HTTP_INTERNAL_SERVER_ERROR;
   }
   
@@ -712,6 +759,7 @@ s_create_cache_file(request_rec*       r,
     if (rv != APR_SUCCESS) { 
       DestroyMagickWand(magick_wand);
       ERR(r,"dir open error.[%s]", conf->image_cache_dir);
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
     memset(&dcf, 0, sizeof(apr_finfo_t));
@@ -742,15 +790,17 @@ s_create_cache_file(request_rec*       r,
       ERR(r, "At least the same size as %luByte is necessary for me.", (unsigned long)writebyte); 
       ERR(r, "Please specify the ChxjImageCacheLimit that is larger than now value. ");
       ERR(r, "==========================================");
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
     DBG(r, "Image Cache dir is full. total_size:[%lu] max_size:[%lu]", total_size + writebyte, max_size);
     /* search delete candidate */
     delete_file_name = apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir, dcf.name);
-    DBG(r, "delete image cache target:[%s] atime:[%lld]", delete_file_name, dcf.atime);
+    DBG(r, "delete image cache target:[%s] atime:[%lld]", delete_file_name, (long long int)dcf.atime);
     rv = apr_file_remove(delete_file_name, r->pool);
     if (rv != APR_SUCCESS) {
       ERR(r, "cache file delete failure.[%s]", delete_file_name);
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
     DBG(r, "deleted image cache target:[%s]", delete_file_name);
@@ -762,11 +812,13 @@ s_create_cache_file(request_rec*       r,
 
   /* to cache */
   rv = apr_file_open(&fout, tmpfile,
-                  APR_WRITE| APR_CREATE | APR_BINARY | APR_SHARELOCK ,APR_OS_DEFAULT,
+                  APR_FOPEN_WRITE| APR_FOPEN_CREATE | APR_FOPEN_BINARY | APR_SHARELOCK ,
+                  APR_OS_DEFAULT,
                   r->pool);
   if (rv != APR_SUCCESS) {
     DestroyMagickWand(magick_wand);
-    ERR(r,"file open error.[%s]", tmpfile);
+    ERR(r,"REQ[%X] file open error.[%s]", TO_ADDR(r), tmpfile);
+    if (sv_writedata) free(sv_writedata);
     return HTTP_INTERNAL_SERVER_ERROR;
   }
 
@@ -774,6 +826,7 @@ s_create_cache_file(request_rec*       r,
   if (rv != APR_SUCCESS) {
     DestroyMagickWand(magick_wand);
     apr_file_close(fout);
+    if (sv_writedata) free(sv_writedata);
     return HTTP_INTERNAL_SERVER_ERROR;
   }
 
@@ -788,17 +841,20 @@ s_create_cache_file(request_rec*       r,
     rv = apr_file_putc((crc >> 8)  & 0xff, fout);
     if (rv != APR_SUCCESS) {
       DestroyMagickWand(magick_wand);
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
 
     rv = apr_file_putc( crc        & 0xff, fout);
     if (rv != APR_SUCCESS) {
       DestroyMagickWand(magick_wand);
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
   }
 
   DestroyMagickWand(magick_wand);
+  if (sv_writedata) free(sv_writedata);
 
   rv = apr_file_close(fout);
   if (rv != APR_SUCCESS) {
@@ -810,153 +866,251 @@ s_create_cache_file(request_rec*       r,
 }
 
 
-static char*
-s_create_blob_data(request_rec* r, 
-                   device_table* spec, 
-                   query_string_param_t *qsp,
-                   char* indata,
-                   apr_size_t* len)
+static int
+s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_table *spec) 
 {
-  apr_size_t         writebyte;
-  unsigned short     crc;
-  img_conv_mode_t    mode = qsp->mode;
+  if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if (MagickStripImage(magick_wand) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
+    return -1;
+  
+  r->content_type = apr_psprintf(r->pool, "image/jpeg");
+  ap_set_content_type(r, "image/jpeg");
+  DBG(r,"convert to jpg");
+  return 0;
+}
 
-  char*              writedata = NULL;
-  char*              dst       = NULL;
 
-  MagickWand*        magick_wand;
+static int
+s_convert_to_png(MagickWand *magick_wand, request_rec *r, device_table *spec)
+{
+  if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if (MagickStripImage(magick_wand) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
+    return -1;
+  
+  r->content_type = apr_psprintf(r->pool, "image/png");
+  ap_set_content_type(r, "image/png");
+  DBG(r, "convert to png");
+  return 0;
+}
 
-  magick_wand = NewMagickWand();
 
-  if (MagickReadImageBlob(magick_wand,indata, *len) == MagickFalse) {
+static int
+s_convert_to_gif(MagickWand *magick_wand, request_rec *r, device_table *spec)
+{
+  if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
     EXIT_MAGICK_ERROR();
-    return NULL;
+    return -1;
   }
+  
+  if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if (MagickStripImage(magick_wand) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
+    return -1;
+  
+  r->content_type = apr_psprintf(r->pool, "image/gif");
+  ap_set_content_type(r, "image/gif");
+  
+  DBG(r,"convert to gif");
+  return 0;
+}
 
-  /*
-   * The size of the image is changed.
-   */
-  DBG(r, "call s_fixup_size()");
 
-  if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL)
-    return NULL;
+static int
+s_convert_to_bmp(MagickWand *magick_wand, request_rec *r, device_table *spec)
+{
+  if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if (MagickStripImage(magick_wand) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
+    return -1;
+  }
+  
+  if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
+    return -1;
+  
+  r->content_type = apr_psprintf(r->pool, "image/bmp");
+  ap_set_content_type(r, "image/bmp");
+  
+  DBG(r, "convert to bmp(unsupported)");
+  return 0;
+}
 
-  /*
-   * The colors of the image is changed.
-   */
-  DBG(r, "call s_fixup_color()");
 
-  if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL)
-    return NULL;
+static char *
+s_create_blob_data(request_rec          *r, 
+                   device_table         *spec, 
+                   query_string_param_t *qsp,
+                   char                 *indata,
+                   apr_size_t           *len)
+{
+  apr_size_t         writebyte;
+  unsigned short     crc;
+  img_conv_mode_t    mode = qsp->mode;
 
-  /*
-   * DEPTH of the image is changed.
-   */
+  char *writedata = NULL;
+  char *dst       = NULL;
+  MagickWand *magick_wand;
 
-  DBG(r,"call s_fixup_depth()");
+  magick_wand = NewMagickWand();
 
-  if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL)
+  if (MagickReadImageBlob(magick_wand,indata, *len) == MagickFalse) {
+    EXIT_MAGICK_ERROR();
     return NULL;
+  }
 
+  if (MagickStripImage(magick_wand) == MagickFalse) {
+    ERR(r, "mod_chxj: strip image failure.");
+    EXIT_MAGICK_ERROR();
+    return NULL;
+  }
 
+  {
+    int oldw = MagickGetImageWidth(magick_wand);
+    int oldh = MagickGetImageHeight(magick_wand);
+    int done_fixup_size = 0;
+    if ((qsp->mode == IMG_CONV_MODE_WALLPAPER && spec->wp_width < oldw && spec->wp_heigh < oldh)
+      || (qsp->mode != IMG_CONV_MODE_WALLPAPER && spec->width < oldw && spec->heigh < oldh)) {
+      /*
+       * The size of the image is changed.
+       */
+      DBG(r,"call s_fixup_size()");
 
-  DBG(r,"start convert and compression");
-
-  if (spec->available_jpeg) {
-    if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
-    }
+      if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) {
+        EXIT_MAGICK_ERROR();
+        return NULL;
+      }
 
-    if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+      done_fixup_size = 1;
     }
+    /*
+     * The colors of the image is changed.
+     */
+    DBG(r,"call s_fixup_color()");
 
-    if (MagickStripImage(magick_wand) == MagickFalse) {
+    if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) {
       EXIT_MAGICK_ERROR();
       return NULL;
     }
 
-    if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
-      return NULL;
-
-    r->content_type = apr_psprintf(r->pool, "image/jpeg");
+    /*
+     * DEPTH of the image is changed.
+     */
+    DBG(r,"call s_fixup_depth()");
 
-    DBG(r, "convert to jpg");
-  }
-  else
-  if (spec->available_png) {
-    if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
+    if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) {
       EXIT_MAGICK_ERROR();
       return NULL;
     }
 
-    if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
-    }
 
-    if (MagickStripImage(magick_wand) == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+    if (! done_fixup_size) {
+      /*
+       * The size of the image is changed.
+       */
+      DBG(r,"call s_fixup_size()");
+      if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) {
+        EXIT_MAGICK_ERROR();
+        return NULL;
+      }
     }
-
-    if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
-      return NULL;
-
-    r->content_type = apr_psprintf(r->pool, "image/png");
-
-    DBG(r,"convert to png");
   }
-  else
-  if (spec->available_gif) {
 
-    if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+  char *nowFormat = MagickGetImageFormat(magick_wand);
+  int fixFormatFlag = 0;
+  if (nowFormat) {
+    if (STRCASEEQ('g','G',"gif",nowFormat)) {
+      if (spec->available_gif) {
+        if (s_convert_to_gif(magick_wand, r, spec)) {
+          return NULL;
+        }
+        fixFormatFlag = 1;
+      }
     }
-
-    if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+    else if (STRCASEEQ('j','J',"jpg",nowFormat)||STRCASEEQ('j','J',"jpeg",nowFormat)) {
+      if (spec->available_jpeg) {
+        if (s_convert_to_jpeg(magick_wand, r, spec)) {
+          return NULL;
+        }
+        fixFormatFlag = 1;
+      }
     }
-
-    if (MagickStripImage(magick_wand) == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+    else if (STRCASEEQ('p','P',"png",nowFormat)) {
+      if (spec->available_png) {
+        if (s_convert_to_png(magick_wand, r, spec)) {
+          return NULL;
+        }
+        fixFormatFlag = 1;
+      }
     }
+  }
 
-    if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
-      return NULL;
-
-    r->content_type = apr_psprintf(r->pool, "image/gif");
+  DBG(r,"start convert and compression");
 
-    DBG(r,"convert to gif");
-  }
-  else
-  if (spec->available_bmp2 || spec->available_bmp4) {
-    if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+  if (!fixFormatFlag) {
+    if (spec->available_jpeg) {
+      if (s_convert_to_jpeg(magick_wand, r, spec)) {
+        return NULL;
+      }
     }
-
-    if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+    else if (spec->available_png) {
+      if (s_convert_to_png(magick_wand, r, spec)) {
+        return NULL;
+      }
     }
-
-    if (MagickStripImage(magick_wand) == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
+    else if (spec->available_gif) {
+      if (s_convert_to_gif(magick_wand, r, spec)) {
+        return NULL;
+      }
+    }
+    else if (spec->available_bmp2 || spec->available_bmp4) {
+      if (s_convert_to_bmp(magick_wand, r, spec)) {
+        return NULL;
+      }
     }
-
-    if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
-      return NULL;
-
-    r->content_type = apr_psprintf(r->pool, "image/bmp");
-
-    DBG(r,"convert to bmp(unsupported)");
   }
   /*--------------------------------------------------------------------------*/
   /* Add Comment (Copyright and so on.)                                       */
@@ -998,11 +1152,12 @@ s_create_blob_data(request_rec* r,
   return dst;
 }
 
-static MagickWand* 
-s_fixup_size(MagickWand* magick_wand, 
-                request_rec* r, 
-                device_table* spec, 
-                query_string_param_t *qsp)
+
+static MagickWand *
+s_fixup_size(MagickWand           *magick_wand, 
+             request_rec          *r, 
+             device_table         *spec, 
+             query_string_param_t *qsp)
 {
   img_conv_mode_t mode = qsp->mode;
   int oldw;
@@ -1081,6 +1236,9 @@ s_fixup_size(MagickWand* magick_wand,
     break;
   }
 
+  if (neww == 0) neww = 1;
+  if (newh == 0) newh = 1;
+
   if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
     DBG(r,"convert width=[%d --> %d]", oldw, neww);
     DBG(r,"convert heigh=[%d --> %d]", oldh, newh);
@@ -1148,8 +1306,9 @@ s_fixup_size(MagickWand* magick_wand,
   return magick_wand;
 }
 
-static MagickWand*
-s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_conv_mode_t UNUSED(mode))
+
+static MagickWand *
+s_fixup_color(MagickWand *magick_wand, request_rec *r, device_table *spec, img_conv_mode_t UNUSED(mode))
 {
   DBG(r,"start chxj_fixup_clor()");
 
@@ -1158,6 +1317,13 @@ s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_c
     return magick_wand;
   }
 
+  unsigned long colors = MagickGetImageColors(magick_wand);
+  DBG(r, "now color:[%ld] spec->color:[%ld]", colors, (unsigned long)spec->color);
+  if (colors < (unsigned long)spec->color) {
+    DBG(r, "Pass s_fixup_color proc. color:[%ld] spec->color:[%d]", colors, spec->color);
+    return magick_wand;
+  }
+
   if (spec->color >= 256) {
 
     DBG(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color);
@@ -1199,8 +1365,8 @@ s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_c
 
 
 
-static MagickWand*
-s_fixup_depth(MagickWand* magick_wand, request_rec* r, device_table* spec)
+static MagickWand *
+s_fixup_depth(MagickWand *magick_wand, request_rec *r, device_table *spec)
 {
   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
     DBG(r, "Pass s_fixup_depth proc");
@@ -1260,10 +1426,10 @@ s_fixup_depth(MagickWand* magick_wand, request_rec* r, device_table* spec)
 }
 
 
-static MagickWand*
-s_add_copyright(MagickWand* magick_wand, request_rec* r, device_table* spec)
+static MagickWand *
+s_add_copyright(MagickWand *magick_wand, request_rec *r, device_table *spec)
 {
-  mod_chxj_config* conf = ap_get_module_config(r->per_dir_config, &chxj_module);
+  mod_chxj_config *conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
     DBG(r, "Pass add_copiright proc");
@@ -1274,7 +1440,8 @@ s_add_copyright(MagickWand* magick_wand, request_rec* r, device_table* spec)
 
     DBG(r, "Add COPYRIGHT [%s]", conf->image_copyright);
 
-    if (spec->html_spec_type == CHXJ_SPEC_Jhtml) {
+    if (spec->html_spec_type == CHXJ_SPEC_Jhtml
+    ||  spec->html_spec_type == CHXJ_SPEC_Jxhtml) {
       apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
       if (MagickCommentImage(magick_wand, 
                              apr_psprintf(r->pool, 
@@ -1310,56 +1477,69 @@ on_error:
   return NULL;
 }
 
-static MagickWand*
-s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec)
+static MagickWand *
+s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
 {
   MagickBooleanType  status;
-  unsigned long quality = 70;
-  apr_size_t    writebyte = 0;
-  char*         writedata;
-  apr_size_t    prev_size = 0;
-  int           revers_flag = 0;
-
-  writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
+  unsigned long      quality = 70;
+  apr_size_t         writebyte = 0;
+  char               *writedata;
+  apr_size_t         prev_size = 0;
+  char               *fmt;
+  int                fmt_type = 0;
+  
+  writedata = (char *)MagickGetImageBlob(magick_wand, &writebyte);
   prev_size = writebyte;
 
-  do {
-    if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
-      EXIT_MAGICK_ERROR();
-      return NULL;
-    }
-
-    writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
-    if (writebyte >= prev_size || revers_flag) {
-      DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte);
-      revers_flag = 1;
-      quality += 10;
-      if (quality > 100) {
-        if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
+  
+  fmt = MagickGetImageFormat(magick_wand);
+  if (fmt) {
+    if (STRCASEEQ('j','J',"jpg",fmt)) fmt_type = 1;
+    if (STRCASEEQ('p','P',"png",fmt)) fmt_type = 2;
+    if (STRCASEEQ('g','G',"gif",fmt)) fmt_type = 3;
+    if (STRCASEEQ('b','B',"bmp",fmt)) fmt_type = 4;
+  }
+  if (fmt_type == 1) {
+    do {
+      if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
+        EXIT_MAGICK_ERROR();
+        return NULL;
+      }
+  
+      writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
+      if (writebyte >= prev_size) {
+        DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte);
+        quality += 5;
+        if (quality > 100) {
+          if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
+            EXIT_MAGICK_ERROR();
+            return NULL;
+          }
+          break;
+        }
+        if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
           EXIT_MAGICK_ERROR();
           return NULL;
         }
         break;
       }
-      prev_size = writebyte;
-      continue;
+  
+      DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte);
+  
+      if (spec->cache == 0)
+        break;
+  
+      if (writebyte <= (unsigned int)spec->cache)
+        break;
+  
+      quality -= 5;
+  
+      if (quality == 0 || quality > 100)
+        break;
+  
     }
-
-    DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte);
-
-    if (spec->cache == 0)
-      break;
-
-    if (writebyte <= (unsigned int)spec->cache)
-      break;
-
-    quality -= 10;
-
-    if (quality == 0 || quality > 100)
-      break;
-
+    while (1);
   }
-  while (1);
 
 
   if (spec->cache > 0 
@@ -1384,6 +1564,7 @@ s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec)
 
       if (now_color <= 2) break;
 
+
       if (now_color >= 8) {
         status = MagickQuantizeImage(magick_wand,
                              now_color,
@@ -1405,12 +1586,12 @@ s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec)
         EXIT_MAGICK_ERROR();
         return NULL;
       }
-
-      if (MagickSetImageDepth(magick_wand, depth) == MagickFalse) {
-        EXIT_MAGICK_ERROR();
-        return NULL;
+      if (fmt_type != 2) {
+        if (MagickSetImageDepth(magick_wand, depth) == MagickFalse) {
+          EXIT_MAGICK_ERROR();
+          return NULL;
+        }
       }
-
       writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
 
       DBG(r,"now_color=[%ld] size=[%d]", (long)now_color, (int)writebyte);
@@ -1424,38 +1605,36 @@ s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec)
   return magick_wand;
 }
 
+
 static apr_status_t 
-s_send_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile)
+s_send_cache_file(
+  mod_chxj_config      *conf,
+  device_table         *spec, 
+  query_string_param_t *query_string, 
+  request_rec          *r, 
+  const char           *tmpfile)
 {
   apr_status_t rv;
   apr_finfo_t  st;
-  apr_file_t*  fout;
+  apr_file_t   *fout;
   apr_size_t   sendbyte;
-  char*        contentLength;
+  char         *contentLength;
 
   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
   if (rv != APR_SUCCESS)
     return HTTP_NOT_FOUND;
 
-  DBG(r, "mode:[%d]",    query_string->mode);
-  DBG(r, "name:[%s]",    query_string->name);
-  DBG(r, "offset:[%ld]", query_string->offset);
-  DBG(r, "count:[%ld]",  query_string->count);
+  DBG(r, "REQ[%X] mode:[%d]",    TO_ADDR(r), query_string->mode);
+  DBG(r, "REQ[%X] name:[%s]",    TO_ADDR(r), query_string->name);
+  DBG(r, "REQ[%X] offset:[%ld]", TO_ADDR(r), query_string->offset);
+  DBG(r, "REQ[%X] count:[%ld]",  TO_ADDR(r), query_string->count);
 
-  if (spec->available_jpeg) {
-    r->content_type = apr_psprintf(r->pool, "image/jpeg");
-  }
-  else
-  if (spec->available_png) {
-    r->content_type = apr_psprintf(r->pool, "image/png");
-  }
-  else
-  if (spec->available_gif) {
-    r->content_type = apr_psprintf(r->pool, "image/gif");
-  }
-  else
-  if (spec->available_bmp2 || spec->available_bmp4) {
-    r->content_type = apr_psprintf(r->pool, "image/bmp");
+  /* for mod_cache */
+  {
+    apr_table_setn(r->headers_out, "Vary", "User-Agent");
+    apr_table_setn(r->err_headers_out, "Vary", "User-Agent");
+    ap_update_mtime(r, st.mtime);
+    ap_set_last_modified(r);
   }
 
   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
@@ -1463,66 +1642,106 @@ s_send_cache_file(device_table* spec, query_string_param_t* query_string, reques
     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
   
     DBG(r,"Content-Length:[%d]", (int)st.size);
-
+    MagickWand *magick_wand = NewMagickWand();
+    if (MagickReadImage(magick_wand,tmpfile) == MagickFalse) {
+      EXIT_MAGICK_ERROR();
+      return HTTP_NOT_FOUND;
+    }
+    if (MagickStripImage(magick_wand) == MagickFalse) {
+      ERR(r, "mod_chxj: strip image failure.");
+      EXIT_MAGICK_ERROR();
+      return HTTP_NOT_FOUND;
+    }
+    char *nowFormat = MagickGetImageFormat(magick_wand);
+    DestroyMagickWand(magick_wand);
+    if (nowFormat) {
+      if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) {
+        DBG(r, "detect cache file => jpg.");
+        ap_set_content_type(r, "image/jpeg");
+      }
+      else if (STRCASEEQ('p','P',"png", nowFormat)) {
+        DBG(r, "detect cache file => png.");
+        ap_set_content_type(r, "image/png");
+      }
+      else if (STRCASEEQ('g','G',"gif", nowFormat)) {
+        DBG(r, "detect cache file => gif.");
+        ap_set_content_type(r, "image/gif");
+      }
+      else if (STRCASEEQ('b','B',"bmp", nowFormat)) {
+        DBG(r, "detect cache file => bmp.");
+        ap_set_content_type(r, "image/bmp");
+      }
+      else {
+        ERR(r, "detect unknown file");
+        return HTTP_NOT_FOUND;
+      }
+    }
+    if (conf->image_copyright) {
+      DBG(r, "REQ[%X] Add COPYRIGHT Header for SoftBank [%s]", TO_ADDR(r), conf->image_copyright);
+      if (spec->html_spec_type == CHXJ_SPEC_Jhtml ||  spec->html_spec_type == CHXJ_SPEC_Jxhtml) {
+        apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
+      }
+    }
     rv = apr_file_open(&fout, tmpfile, 
-      APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
+      APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, 
+      APR_OS_DEFAULT, r->pool);
     if (rv != APR_SUCCESS) {
       DBG(r, "cache file open failed[%s]", tmpfile);
       return HTTP_NOT_FOUND;
     }
-
     ap_send_fd(fout, r, 0, st.size, &sendbyte);
     apr_file_close(fout);
     ap_rflush(r);
-    DBG(r, "send file data[%d]byte", (int)sendbyte);
+    DBG(r, "REQ[%X] send file data[%d]byte", TO_ADDR(r), (int)sendbyte);
   }
   else
   if (query_string->mode == IMG_CONV_MODE_EZGET) {
-    charname = apr_pstrdup(r->pool, basename(r->filename));
+    char *name = apr_pstrdup(r->pool, basename(r->filename));
     name[strlen(name)-4] = 0;
     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
 
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".jpg", (long)st.size, "devjaww", name);
     }
     else
     if (strcasecmp(r->content_type, "image/bmp") == 0) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".bmp", (long)st.size, "devabm", name);
     }
     else
     if (strcasecmp(r->content_type, "image/png") == 0) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".png", (long)st.size, "dev8aww", name);
     }
     else
     if (strcasecmp(r->content_type, "image/gif") == 0) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".gif", (long)st.size, "devgi0z", name);
     }
   }
   else
   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
     if (query_string->count == -1 && query_string->offset == -1) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
       ap_rprintf(r, HDML_SUCCESS_PAGE);
       ap_rflush(r);
     }
     else
     if (query_string->count == -2 && query_string->offset == -1) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
       ap_rprintf(r, HDML_FAIL_PAGE);
       ap_rflush(r);
     }
     else { 
-      ap_set_content_type(r, "application/x-up-download");
+      chxj_set_content_type(r, "application/x-up-download");
       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
   
       DBG(r, "Content-Length:[%d]", (int)st.size);
 
       rv = apr_file_open(&fout, tmpfile, 
-        APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
+        APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, 
+        APR_OS_DEFAULT, r->pool);
 
       if (rv != APR_SUCCESS) {
         DBG(r,"tmpfile open failed[%s]", tmpfile);
@@ -1541,19 +1760,28 @@ s_send_cache_file(device_table* spec, query_string_param_t* query_string, reques
 
 
 static apr_status_t 
-s_send_original_file(request_rec* r, const char* originalfile)
+s_send_original_file(request_rec *r, const char *originalfile)
 {
   apr_status_t rv;
   apr_finfo_t  st;
-  apr_file_t*  fout;
+  apr_file_t   *fout;
   apr_size_t   sendbyte = 0;
 
   rv = apr_stat(&st, originalfile, APR_FINFO_MIN, r->pool);
   if (rv != APR_SUCCESS)
     return HTTP_NOT_FOUND;
 
+  /* for mod_cache */
+  {
+    apr_table_setn(r->headers_out, "Vary", "User-Agent");
+    apr_table_setn(r->err_headers_out, "Vary", "User-Agent");
+    ap_update_mtime(r, st.mtime);
+    ap_set_last_modified(r);
+  }
+
   rv = apr_file_open(&fout, originalfile, 
-    APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
+    APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED,
+    APR_OS_DEFAULT, r->pool);
   if (rv != APR_SUCCESS) {
     DBG(r, "originalfile open failed[%s]", originalfile);
     return HTTP_NOT_FOUND;
@@ -1567,116 +1795,181 @@ s_send_original_file(request_rec* r, const char* originalfile)
   return OK;
 }
 
+
 static apr_status_t 
-s_header_only_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile)
+s_header_only_cache_file(device_table *spec, query_string_param_t *query_string, request_rec *r, const char *tmpfile)
 {
   apr_status_t rv;
   apr_finfo_t  st;
-  char*        contentLength;
+  char         *contentLength;
+  mod_chxj_config *conf = ap_get_module_config(r->per_dir_config, &chxj_module);
+
+  DBG(r, "REQ[%X] start s_header_only_cache_file()", TO_ADDR(r));
 
   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
-  if (rv != APR_SUCCESS)
+  if (rv != APR_SUCCESS) {
+    DBG(r, "REQ[%X] end s_header_only_cache_file()", TO_ADDR(r));
     return HTTP_NOT_FOUND;
-
-  DBG(r, "mode:[%d]",    query_string->mode);
-  DBG(r, "name:[%s]",    query_string->name);
-  DBG(r, "offset:[%ld]", query_string->offset);
-  DBG(r, "count:[%ld]",  query_string->count);
-
-  if (spec->available_jpeg) {
-    r->content_type = apr_psprintf(r->pool, "image/jpeg");
-  }
-  else
-  if (spec->available_png) {
-    r->content_type = apr_psprintf(r->pool, "image/png");
-  }
-  else
-  if (spec->available_gif) {
-    r->content_type = apr_psprintf(r->pool, "image/gif");
-  }
-  else
-  if (spec->available_bmp2 || spec->available_bmp4) {
-    r->content_type = apr_psprintf(r->pool, "image/bmp");
   }
 
+  DBG(r, "REQ[%X] mode:[%d]",    TO_ADDR(r), query_string->mode);
+  DBG(r, "REQ[%X] name:[%s]",    TO_ADDR(r), query_string->name);
+  DBG(r, "REQ[%X] offset:[%ld]", TO_ADDR(r), query_string->offset);
+  DBG(r, "REQ[%X] count:[%ld]",  TO_ADDR(r), query_string->count);
+
   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
+
+    MagickWand *magick_wand = NewMagickWand();
+    if (MagickReadImage(magick_wand,tmpfile) == MagickFalse) {
+      EXIT_MAGICK_ERROR();
+      return HTTP_NOT_FOUND;
+    }
+    if (MagickStripImage(magick_wand) == MagickFalse) {
+      ERR(r, "mod_chxj: strip image failure.");
+      EXIT_MAGICK_ERROR();
+      return HTTP_NOT_FOUND;
+    }
+    char *nowFormat = MagickGetImageFormat(magick_wand);
+    DestroyMagickWand(magick_wand);
+    if (nowFormat) {
+      if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) {
+        DBG(r, "detect cache file => jpg.");
+        ap_set_content_type(r, "image/jpeg");
+      }
+      else if (STRCASEEQ('p','P',"png", nowFormat)) {
+        DBG(r, "detect cache file => png.");
+        ap_set_content_type(r, "image/png");
+      }
+      else if (STRCASEEQ('g','G',"gif", nowFormat)) {
+        DBG(r, "detect cache file => gif.");
+        ap_set_content_type(r, "image/gif");
+      }
+      else if (STRCASEEQ('b','B',"bmp", nowFormat)) {
+        DBG(r, "detect cache file => bmp.");
+        ap_set_content_type(r, "image/bmp");
+      }
+      else {
+        ERR(r, "REQ[%X] detect unknown file", TO_ADDR(r));
+        return HTTP_NOT_FOUND;
+      }
+    }
   
     DBG(r,"Content-Length:[%d]", (int)st.size);
   }
   else
   if (query_string->mode == IMG_CONV_MODE_EZGET) {
-    charname = apr_pstrdup(r->pool, basename(r->filename));
+    char *name = apr_pstrdup(r->pool, basename(r->filename));
     name[strlen(name)-4] = 0;
     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
 
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
     }
     else
     if (strcasecmp(r->content_type, "image/bmp") == 0) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
     }
     else
     if (strcasecmp(r->content_type, "image/png") == 0) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
     }
     else
     if (strcasecmp(r->content_type, "image/gif") == 0) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
     }
   }
   else
   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
     if (query_string->count == -1 && query_string->offset == -1) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
     }
     else
     if (query_string->count == -2 && query_string->offset == -1) {
-      ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
+      chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
     }
     else { 
-      ap_set_content_type(r, "application/x-up-download");
+      chxj_set_content_type(r, "application/x-up-download");
       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
   
-      DBG(r, "Content-Length:[%d]", (int)st.size);
+      DBG(r, "REQ[%X] Content-Length:[%d]", TO_ADDR(r), (int)st.size);
+    }
+  }
+  if (conf->image_copyright) {
+    DBG(r, "REQ[%X] Add COPYRIGHT Header for SoftBank [%s]", TO_ADDR(r), conf->image_copyright);
+    if (spec->html_spec_type == CHXJ_SPEC_Jhtml ||  spec->html_spec_type == CHXJ_SPEC_Jxhtml) {
+      apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
     }
   }
   
+  DBG(r, "REQ[%X] end s_header_only_cache_file()", TO_ADDR(r));
   return OK;
 }
 
 
+static void 
+s_init_serial_pattern(apr_pool_t *p)
+{
+  if (!v_docomo_serial_pattern1) {
+    v_docomo_serial_pattern1 = chxj_compile_for_preg_replace(p, "/ser[^;\\)]+");
+  }  
+  if (!v_docomo_serial_pattern2) {
+    v_docomo_serial_pattern2 = chxj_compile_for_preg_replace(p, ";ser[^;\\)]+");
+  }  
+  if (!v_docomo_serial_pattern3) {
+    v_docomo_serial_pattern3 = chxj_compile_for_preg_replace(p, ";icc[^;\\)]+");
+  }  
+  if (!v_softbank_serial_pattern1) {
+    v_softbank_serial_pattern1 = chxj_compile_for_preg_replace(p, "/SN[0-9a-zA-Z]+ ");
+  }  
+}
+
 
-static char*
-s_create_workfile(
-                request_rec*          r, 
-                mod_chxj_config*      conf, 
-                const char*           user_agent, 
+static char *
+s_create_workfile_name(
+                request_rec          *r, 
+                mod_chxj_config      *conf, 
+                const char           *user_agent, 
                 query_string_param_t *qsp)
 {
-  int ii;
-  int jj;
-  int len;
-  char* w = apr_palloc(r->pool, 256);
-  char* fname;
+  int  ii;
+  int  jj;
+  int  len;
+  char *w = apr_palloc(r->pool, 256);
+  char *fname;
+  char *new_user_agent;
+
+  s_init_serial_pattern(r->server->process->pool);
+
+  /* for DoCoMo */
+  new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern1, "", user_agent);
+  new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern2, "", new_user_agent);
+  new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern3, "", new_user_agent);
+
+  /* for SoftBank */
+  new_user_agent = chxj_preg_replace(r->pool, v_softbank_serial_pattern1, " ", new_user_agent);
+
+  DBG(r, "old user_agent:[%s] ==> new user_agent:[%s]", user_agent, new_user_agent);
+
 
   memset(w, 0, 256);
   switch (qsp->mode) {
   case IMG_CONV_MODE_THUMBNAIL:
-    fname = apr_psprintf(r->pool, "%s.%s.thumbnail", r->filename, user_agent);
+    fname = apr_psprintf(r->pool, "%s.%s.thumbnail", r->filename, new_user_agent);
     DBG(r, "mode=thumbnail [%s]", fname);
     break;
+
   case IMG_CONV_MODE_WALLPAPER:
   case IMG_CONV_MODE_EZGET:
-    fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, user_agent);
+    fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, new_user_agent);
     DBG(r, "mode=WallPaper [%s]", fname);
     break;
+
   case IMG_CONV_MODE_NORMAL:
   default:
 
-    fname = apr_psprintf(r->pool, "%s.%s", r->filename, user_agent);
+    fname = apr_psprintf(r->pool, "%s.%s", r->filename, new_user_agent);
 
     if (qsp->width)
       fname = apr_psprintf(r->pool, "%s.w%d", fname, qsp->width);
@@ -1709,8 +2002,9 @@ s_create_workfile(
   return apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir,w);
 }
 
+
 static unsigned short
-s_add_crc(const charwritedata, apr_size_t writebyte)
+s_add_crc(const char *writedata, apr_size_t writebyte)
 {
   unsigned short crc = 0xffff;
   apr_size_t     ii;
@@ -1723,34 +2017,40 @@ s_add_crc(const char* writedata, apr_size_t writebyte)
   return crc;
 }
 
+
 int
 chxj_trans_name(request_rec *r)
 {
-  const charccp;
-  chardocroot;
-  int len;
-  apr_finfo_t st;
-  apr_status_t rv;
-  mod_chxj_configconf;
-  int ii;
-  char*      ext[] = {
+  const char      *ccp;
+  char            *docroot;
+  int             len;
+  apr_finfo_t     st;
+  apr_status_t    rv;
+  mod_chxj_config *conf;
+  int             ii;
+  char            *ext[] = {
           "jpg",
+          "JPG",
           "jpeg",
+          "JPEG",
           "png",
+          "PNG",
           "bmp",
+          "BMP",
           "gif",
-          "qrc",    /* QRCode½ÐÎÏÍÑ¥Õ¥¡¥¤¥ë¤Î³ÈÄ¥»Ò */
+          "GIF",
+          "qrc",    /* QRCode出力用ファイルの拡張子 */
           "",
   };
-  char*    fname;
-  char*    idx;
-  char*    filename_sv;
+  char     *fname = NULL;
+  char     *idx;
+  char     *filename_sv;
   int      do_ext_check = TRUE;
   int      next_ok      = FALSE;
 
   DBG(r, "start chxj_trans_name()");
 
-  conf = ap_get_module_config(r->per_dir_config, &chxj_module);
+  conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
 
   if (conf == NULL) {
     DBG(r, "end chxj_trans_name() conf is null[%s]", r->uri);
@@ -1798,7 +2098,7 @@ chxj_trans_name(request_rec *r)
   DBG(r,"URI[%s]", filename_sv);
 
   do_ext_check = TRUE;
-  for (ii=0; ii<7-1; ii++) {
+  for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
     char* pos = strrchr(filename_sv, '.');
     if (pos && pos++) {
       if (strcasecmp(pos, ext[ii]) == 0) {
@@ -1810,7 +2110,7 @@ chxj_trans_name(request_rec *r)
   }
 
   if (do_ext_check) {
-    for (ii=0; ii<7; ii++) {
+    for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
       if (strlen(ext[ii]) == 0) {
         fname = apr_psprintf(r->pool, "%s", filename_sv);
       }
@@ -1832,7 +2132,7 @@ chxj_trans_name(request_rec *r)
     DBG(r,"NotFound [%s]", r->filename);
     return DECLINED;
   }
-  for (ii=0; ii<7-1; ii++) {
+  for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
     char* pos = strrchr(fname, '.');
     if (pos && pos++) {
       if (strcasecmp(pos, ext[ii]) == 0) {
@@ -1863,21 +2163,139 @@ chxj_trans_name(request_rec *r)
 
 
 
+static int
+s_chxj_trans_name2(request_rec *r)
+{
+  apr_finfo_t     st;
+  apr_status_t    rv;
+  mod_chxj_config *conf;
+  int             ii;
+  char            *ext[] = {
+          "jpg",
+          "JPG",
+          "jpeg",
+          "JPEG",
+          "png",
+          "PNG",
+          "bmp",
+          "BMP",
+          "gif",
+          "GIF",
+          "qrc",    /* QRCode出力用ファイルの拡張子 */
+          "",
+  };
+  char     *fname = NULL;
+  char     *filename_sv;
+  int      do_ext_check = TRUE;
+  int      next_ok      = FALSE;
+
+  DBG(r, "REQ[%X] start chxj_trans_name2()", (unsigned int)(apr_size_t)r);
+
+  conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
+
+  if (conf == NULL) {
+    DBG(r, "REQ[%X] end chxj_trans_name2() conf is null[%s]", (unsigned int)(apr_size_t)r, r->uri);
+    return DECLINED;
+  }
+
+  if (conf->image != CHXJ_IMG_ON) {
+    DBG(r, "REQ[%X] end chxj_trans_name2() ImageEngineOff", (unsigned int)(apr_size_t)r);
+    return DECLINED;
+  }
+
+
+  DBG(r,"Match URI[%s]", r->uri);
+
+  if (r->filename == NULL) {
+    DBG(r, "REQ[%X] end chxj_trans_name2() r->filename is null", (unsigned int)(apr_size_t)r);
+    return DECLINED;
+  }
+     
+  filename_sv = r->filename;
+
+  DBG(r,"REQ[%x] r->filename[%s]", (unsigned int)(apr_size_t)r, filename_sv);
+
+  do_ext_check = TRUE;
+  for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
+    char* pos = strrchr(filename_sv, '.');
+    if (pos && pos++) {
+      if (strcasecmp(pos, ext[ii]) == 0) {
+        do_ext_check = FALSE;
+        fname = apr_psprintf(r->pool, "%s", filename_sv);
+        break;
+      }
+    }
+  }
+
+  if (do_ext_check) {
+    for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
+      if (strlen(ext[ii]) == 0) {
+        fname = apr_psprintf(r->pool, "%s", filename_sv);
+      }
+      else 
+        fname = apr_psprintf(r->pool, "%s.%s", filename_sv, ext[ii]);
+  
+      DBG(r,"search [%s]", fname);
+  
+      rv = apr_stat(&st, fname, APR_FINFO_MIN, r->pool);
+      if (rv == APR_SUCCESS) {
+        if (st.filetype != APR_DIR)
+          break;
+      }
+  
+      fname = NULL;
+    }
+  }
+  if (fname == NULL) {
+    DBG(r,"NotFound [%s]", r->filename);
+    return DECLINED;
+  }
+  for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
+    char* pos = strrchr(fname, '.');
+    if (pos && pos++) {
+      if (strcasecmp(pos, ext[ii]) == 0) {
+        next_ok = TRUE;
+        break;
+      }
+    }
+  }
+
+  if (! next_ok)  {
+    DBG(r,"NotFound [%s]", r->filename);
+    return DECLINED;
+  }
+
+  if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) {
+    DBG(r,"Found [%s]", fname);
+
+    r->filename = apr_psprintf(r->pool, "%s", fname);
+  
+    if (strcasecmp("qrc", ext[ii]) == 0)
+      r->handler = apr_psprintf(r->pool, "chxj-qrcode");
+    else
+      r->handler = apr_psprintf(r->pool, "chxj-picture");
+  }
+  DBG(r, "REQ[%X] end chxj_trans_name()", (unsigned int)(apr_size_t)r);
+  return OK;
+}
+
+
+
 /**
  * It converts it from QUERYSTRING.
  *
  * @param r   [i]
  */
-static query_string_param_t*
+static query_string_param_t *
 s_get_query_string_param(request_rec *r)
 {
-  charpair;
-  charname;
-  charvalue;
-  charpstate;
-  charvstate;
-  chars;
-  query_string_param_tparam;
+  char *pair;
+  char *name;
+  char *value;
+  char *pstate;
+  char *vstate;
+  char *s;
+  query_string_param_t *param;
 
   s = apr_pstrdup(r->pool, r->parsed_uri.query);
   param = apr_palloc(r->pool, sizeof(query_string_param_t));
@@ -1981,6 +2399,85 @@ s_get_query_string_param(request_rec *r)
 
   return param;
 }
+
+
+static char *
+s_add_comment_to_png(request_rec *r, char *data, apr_size_t *len)
+{
+  char *result = NULL;
+#define PNG_COPYRIGHT_KEY "Copyright"
+#define PNG_COPYRIGHT_VAL "kddi_copyright=on,copy=NO"
+#define PNG_SIG_AND_IHDR_SZ (33)
+  char *key = PNG_COPYRIGHT_KEY;
+  apr_size_t klen = sizeof(PNG_COPYRIGHT_KEY)-1;
+  char *val = PNG_COPYRIGHT_VAL;
+  apr_size_t vlen = sizeof(PNG_COPYRIGHT_VAL)-1;
+  apr_pool_t *pool;
+  apr_size_t total_tEXt_size;
+  apr_size_t tEXt_data_size;
+  apr_size_t pos;
+  apr_size_t ii;
+  char *buf;
+  char *valbuf;
+  uint32_t crc;
+  mod_chxj_config *conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
+
+  DBG(r, "REQ[%X] start s_add_comment_to_png()",(unsigned int)(apr_size_t)r);
+  if (conf->image_copyright) {
+    apr_pool_create(&pool, r->pool);
+
+    valbuf = apr_psprintf(pool, "%s,%s", val, conf->image_copyright);
+    vlen = strlen(valbuf);
+  
+    /* total_size = length + "tEXt" + "Copyright" + '\0' + val + crc */
+    total_tEXt_size = 4 + 4 + klen + vlen + 1 + 4;
+    result = apr_palloc(pool, total_tEXt_size + *len);
+    if (!result) {
+      DBG(r, "REQ[%X] memory allocation error.", (unsigned int)(apr_size_t)r);
+      return NULL;
+    }
+    pos = PNG_SIG_AND_IHDR_SZ;
+    memcpy(result, data, pos); /* 33 = SIGNATURE + IHDR */
+    tEXt_data_size = klen + 1 + vlen;
+    result[pos + 0] = tEXt_data_size >> 24;
+    result[pos + 1] = tEXt_data_size >> 16;
+    result[pos + 2] = tEXt_data_size >> 8;
+    result[pos + 3] = tEXt_data_size;
+    pos += 4;
+    buf = apr_palloc(pool, 4 + klen + 1 + vlen);
+    memcpy(&buf[0], "tEXt", 4); 
+    memcpy(&buf[4], key, klen);
+    buf[4+klen] = 0;
+    memcpy(&buf[4+klen+1], valbuf, vlen);
+    
+    
+    DBG(r, "REQ[%X] buf:[%s]", (unsigned int)(apr_size_t)r, buf);
+  
+    crc = 0xffffffff;
+    for (ii = 0; ii < 4 + tEXt_data_size; ii++) {
+      crc = AU_CRC_TBL[(crc ^ buf[ii]) & 0xff] ^ (crc >> 8);
+    }
+    crc ^= 0xffffffff;
+    memcpy(&result[pos], buf, 4 + klen + 1 + vlen);
+    pos += (4 + klen + 1 + vlen);
+    result[pos + 0] = crc >> 24;
+    result[pos + 1] = crc >> 16;
+    result[pos + 2] = crc >> 8;
+    result[pos + 3] = crc;
+    pos += 4;
+    memcpy(&result[pos], &data[PNG_SIG_AND_IHDR_SZ] , *len - PNG_SIG_AND_IHDR_SZ);
+    *len = *len + total_tEXt_size;
+    DBG(r, "REQ[%X] writebyte:[%d]", (unsigned int)(apr_size_t)r, (unsigned int)*len);
+  }
+  else {
+    result = data;
+  }
+  DBG(r, "REQ[%X] end s_add_comment_to_png()",(unsigned int)(apr_size_t)r);
+#undef PNG_SIG_AND_IHDR_SZ
+#undef PNG_COPYRIGHT_KEY
+#undef PNG_COPYRIGHT_VAL
+  return result;
+}
 /*
  * vim:ts=2 et
  */