OSDN Git Service

* This is a test commit.
[modchxj/mod_chxj.git] / src / chxj_img_conv_format.c
index f5723ab..2f55765 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
+ * Copyright (C) 2005-2011 Atsushi Konno All rights reserved.
  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
 
 #include <wand/magick_wand.h>
 
+/* @see htcacheclean */
+#define CACHEDATA_EXT "data"
+
+#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(0) 
@@ -77,6 +84,7 @@ struct query_string_param_t {
 /*----------------------------------------------------------------------------*/
 static device_table v_ignore_spec = {
   NULL,
+  0,
   "IGN",
   "IGN",
   CHXJ_SPEC_HTML,
@@ -94,6 +102,7 @@ static device_table v_ignore_spec = {
   96,
   65536,
   NULL,
+  "Shift_JIS"
 };
 
 /*----------------------------------------------------------------------------*/
@@ -180,7 +189,8 @@ static apr_status_t s_create_cache_file(request_rec          *r,
                                         query_string_param_t *qsp,
                                         mod_chxj_config      *conf);
 
-static apr_status_t s_send_cache_file(device_table          *spec,
+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);
@@ -230,6 +240,8 @@ static int s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_tab
 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);
 
 
 
@@ -237,26 +249,37 @@ int
 chxj_img_conv_format_handler(request_rec *r)
 {
   mod_chxj_config       *conf;
+  mod_chxj_req_config   *req_conf;
   query_string_param_t  *qsp;
   char                  *user_agent;
   device_table          *spec;
   chxjconvrule_entry    *entryp;
+  int                   rtn;
 
-  DBG(r, "start chxj_img_conv_format_handler()");
+  DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
+
+  s_chxj_trans_name2(r);
   
-  if (r->handler && !STRCASEEQ('c','C',"chxj-picture",r->handler) && !STRCASEEQ('c','C',"chxj-qrcode",r->handler)) {
-    DBG(r, "end chxj_img_conv_format_handler()");
+  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]", TO_ADDR(r), r->status);
+    DBG(r,"REQ[%X] r->handler is[%s]", TO_ADDR(r), r->handler);
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return DECLINED;
   }
 
   qsp = s_get_query_string_param(r);
   conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
+  req_conf = chxj_get_req_config(r);
   if (conf == NULL) {
-    DBG(r, "end chxj_img_conv_format_handler() conf is null");
+    DBG(r,"REQ[%X] conf is null",TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return DECLINED;
   }
 
   if (STRCASEEQ('c','C',"chxj-qrcode",r->handler) && conf->image == CHXJ_IMG_OFF) {
+    DBG(r,"REQ[%X] chxj-qrcode and ImageEngineOff", TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return DECLINED;
   }
 
@@ -270,7 +293,15 @@ chxj_img_conv_format_handler(request_rec *r)
     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
   }
   else {
-    entryp = chxj_apply_convrule(r, conf->convrules);
+    /*-------------------------------------------------------------------------*/
+    /* already setup entryp if request_conf->user_agent is not null            */
+    /*-------------------------------------------------------------------------*/
+    if (req_conf->user_agent) {
+      entryp = req_conf->entryp;
+    }
+    else {
+      entryp = chxj_apply_convrule(r, conf->convrules);
+    }
     if (entryp && entryp->user_agent) {
       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
     }
@@ -283,14 +314,31 @@ chxj_img_conv_format_handler(request_rec *r)
 
   if (qsp->ua_flag == UA_IGN)
     spec = &v_ignore_spec;
-  else
-    spec = chxj_specified_device(r, user_agent);
+  else {
+    if (user_agent) {
+      if (!req_conf->spec || !req_conf->user_agent) {
+        spec = chxj_specified_device(r, user_agent);
+      }
+      else if (req_conf->user_agent && strcmp(req_conf->user_agent, user_agent) != 0) {
+        spec = chxj_specified_device(r, user_agent);
+      }
+      else {
+        spec = req_conf->spec;
+      }
+    }
+  }
 
-  DBG(r,"found device_name=[%s]", spec->device_name);
-  DBG(r,"User-Agent=[%s]", user_agent);
+  DBG(r,"REQ[%X] found device_name=[%s]", TO_ADDR(r), spec->device_name);
+  DBG(r,"REQ[%X] User-Agent=[%s]", TO_ADDR(r), user_agent);
 
 
-  return s_img_conv_format_from_file(r, conf, user_agent, qsp, spec);
+  /*-------------------------------------------------------------------------*/
+  /* Do not process output_filter                                            */
+  /*-------------------------------------------------------------------------*/
+  chxj_remove_filter(r);
+  rtn = s_img_conv_format_from_file(r, conf, user_agent, qsp, spec);
+  DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
+  return rtn;
 }
 
 
@@ -313,11 +361,12 @@ chxj_convert_image(request_rec *r, const char **src, apr_size_t *len)
   char                  *conv_check;
   chxjconvrule_entry    *entryp;
 
-  DBG(r, "start chxj_convert_image()");
+  DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
 
   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] already convert.", TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return NULL;
   }
 
@@ -325,10 +374,11 @@ chxj_convert_image(request_rec *r, const char **src, apr_size_t *len)
   qsp = s_get_query_string_param(r);
   conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
   if (conf == NULL) {
-    DBG(r, "end chxj_convert_image()");
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return NULL;
   }
 
+  mod_chxj_req_config *req_conf = chxj_get_req_config(r);
   /*--------------------------------------------------------------------------*/
   /* User-Agent to spec                                                       */
   /*--------------------------------------------------------------------------*/
@@ -336,7 +386,15 @@ chxj_convert_image(request_rec *r, const char **src, apr_size_t *len)
     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
   }
   else {
-    entryp = chxj_apply_convrule(r, conf->convrules);
+    /*-------------------------------------------------------------------------*/
+    /* already setup entryp if request_conf->user_agent is not null            */
+    /*-------------------------------------------------------------------------*/
+    if (req_conf->user_agent) {
+      entryp = req_conf->entryp;
+    }
+    else {
+      entryp = chxj_apply_convrule(r, conf->convrules);
+    }
     if (entryp && entryp->user_agent) {
       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
     }
@@ -347,20 +405,34 @@ chxj_convert_image(request_rec *r, const char **src, apr_size_t *len)
 
   if (qsp->ua_flag == UA_IGN)
     spec = &v_ignore_spec;
-  else
-    spec = chxj_specified_device(r, user_agent);
+  else {
+    if (user_agent) {
+      if (!req_conf->spec || !req_conf->user_agent) {
+        spec = chxj_specified_device(r, user_agent);
+      }
+      else if (req_conf->user_agent && strcmp(req_conf->user_agent, user_agent) != 0) {
+        spec = chxj_specified_device(r, user_agent);
+      }
+      else {
+        spec = req_conf->spec;
+      }
+    }
+  }
 
-  DBG(r,"found device_name=[%s]", spec->device_name);
-  DBG(r, "User-Agent=[%s]", user_agent);
+  DBG(r,"REQ[%X] found device_name=[%s]",TO_ADDR(r),spec->device_name);
+  DBG(r,"REQ[%X] User-Agent=[%s]",TO_ADDR(r),user_agent);
 
-  if (spec->width == 0 || spec->heigh == 0) 
+  if (spec->width == 0 || spec->heigh == 0) {
+    DBG(r,"REQ[%X] not convert (width or height is 0)",TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return NULL;
+  }
 
   dst = s_create_blob_data(r, spec, qsp, (char*)*src, len);
   if (dst == NULL) 
     *len = 0;
 
-  DBG(r, "end chxj_convert_image()");
+  DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
 
   return dst;
 }
@@ -391,7 +463,7 @@ s_img_conv_format_from_file(
   /* Create Workfile Name                                                     */
   /*--------------------------------------------------------------------------*/
   tmpfile = s_create_workfile_name(r, conf, user_agent, qsp);
-  DBG(r,"workfile=[%s]", tmpfile);
+  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)
@@ -412,16 +484,16 @@ 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);
     }
     if (rv == OK) break;
     if (rv == HTTP_NOT_FOUND) {
-      DBG(r, "recheck wait... try_count[%d]", try_count);
+      DBG(r,"REQ[%X] recheck wait... try_count[%d]", TO_ADDR(r),try_count);
       apr_sleep(CACHE_RECHECK_WAIT);
     }
   } while (try_count--); 
@@ -430,7 +502,7 @@ s_img_conv_format_from_file(
     WRN(r, "cache file was deleted...");
   }
 
-  DBG(r,"end chxj_img_conv_format");
+  DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
 
   return rv;
 }
@@ -494,26 +566,68 @@ s_create_cache_file(request_rec          *r,
     /*------------------------------------------------------------------------*/
     /* 通常のイメージファイルの場合                                           */
     /*------------------------------------------------------------------------*/
+#if APR_HAS_MMAP
+    DBG(r, "REQ[%X] Use mmap to read original image.", TO_ADDR(r));
+    {
+      apr_finfo_t finfo;
+      apr_mmap_t *mmap = NULL;
+      rv = apr_file_open(&fin, 
+                         r->filename, 
+                         APR_FOPEN_READ | APR_FOPEN_SHARELOCK, 
+                         APR_OS_DEFAULT, 
+                         r->pool);
+      if (rv != APR_SUCCESS) {
+        char buf[256];
+        ERR(r,"REQ[%X] %s:%d apr_file_open failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+        ERR(r,"REQ[%X] %s:%d file open failed.[%s]", TO_ADDR(r),__FILE__,__LINE__,r->filename);
+        DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+        return HTTP_NOT_FOUND;
+      }
+      rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fin);
+      if (rv != APR_SUCCESS) {
+        char buf[256];
+        apr_file_close(fin);
+        ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+        DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+        return HTTP_NOT_FOUND;
+      }
+      rv = apr_mmap_create(&mmap, fin, 0, finfo.size, APR_MMAP_READ, r->pool);
+      if (rv != APR_SUCCESS) {
+        char buf[256];
+        apr_file_close(fin);
+        ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+        DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+        return HTTP_NOT_FOUND;
+      }
+      readdata = apr_palloc(r->pool, st->size);
+      readbyte = st->size;
+      memcpy(readdata, mmap->mm, st->size);
+      //apr_mmap_delete(mmap);
+      apr_file_close(fin);
+    }
+#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_OS_DEFAULT, 
                     r->pool);
     if (rv != APR_SUCCESS) {
-      DBG(r,"file open failed.[%s]", r->filename);
+      DBG(r,"REQ[%X] file open failed.[%s]", TO_ADDR(r),r->filename);
       return HTTP_NOT_FOUND;
     }
   
     readdata = apr_palloc(r->pool, st->size);
     rv = apr_file_read_full(fin, (void*)readdata, st->size, &readbyte);
+    apr_file_close(fin);
     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;
     }
+#endif
   }
-  DBG(r,"start img convert");
+  DBG(r,"REQ[%X] start img convert", TO_ADDR(r));
 
 
   magick_wand = NewMagickWand();
@@ -526,7 +640,7 @@ s_create_cache_file(request_rec          *r,
   /* for AnimationGIF */
   /*------------------*/
   img_count = MagickGetNumberImages(magick_wand);
-  DBG(r, "REQ[%X] img_count is [%d]", (unsigned int)(apr_size_t)r, img_count);
+  DBG(r, "REQ[%X] img_count is [%d]", TO_ADDR(r), img_count);
   if (img_count > 1) {
     MagickSetImageIndex(magick_wand, 0);
     MagickWand *magick_wand2 = MagickGetImage(magick_wand);
@@ -539,17 +653,35 @@ s_create_cache_file(request_rec          *r,
     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;
+    int ww = spec->width;
+    int hh = spec->heigh;
+    if (IS_IPHONE(spec) || IS_ANDROID(spec)) {
+      ww = (int)((double)ww * (double)1.5);
+      hh = (int)((double)hh * (double)1.5);
+      if (IS_ANDROID(spec)) {
+        ww = ww - ADJUST_WIDTH_FOR_ANDROID;
+      }
+    }
     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)) {
+      || (qsp->mode != IMG_CONV_MODE_WALLPAPER && ww < oldw && hh < oldh)) {
       /*
        * The size of the image is changed.
        */
-      DBG(r,"call s_fixup_size()");
+      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;
@@ -559,7 +691,7 @@ s_create_cache_file(request_rec          *r,
     /*
      * 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;
@@ -567,7 +699,7 @@ 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;
@@ -577,7 +709,7 @@ s_create_cache_file(request_rec          *r,
       /*
        * The size of the image is changed.
        */
-      DBG(r,"call s_fixup_size()");
+      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;
     }
@@ -609,9 +741,17 @@ s_create_cache_file(request_rec          *r,
           fixFormatFlag = 1;
         }
       }
+      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;
+        }
+      }
     }
 
-    DBG(r,"start convert and compression");
+    DBG(r,"REQ[%X] start convert and compression", TO_ADDR(r));
   
     if (! fixFormatFlag) {
       if (spec->available_jpeg) {
@@ -641,7 +781,7 @@ s_create_cache_file(request_rec          *r,
     /*
      * Add Comment (Copyright and so on.)
      */
-    DBG(r, "call s_add_copyright()");
+    DBG(r,"REQ[%X] call s_add_copyright()",TO_ADDR(r));
   
     if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL) 
       return HTTP_NOT_FOUND;
@@ -676,7 +816,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);
@@ -684,15 +825,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,"REQ[%X] end convert and compression",TO_ADDR(r));
 
-  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.",TO_ADDR(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 (writedata) free(writedata);
+    if (sv_writedata) free(sv_writedata);
     return HTTP_INTERNAL_SERVER_ERROR;
   }
   
@@ -710,7 +863,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 (writedata) free(writedata);
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
     memset(&dcf, 0, sizeof(apr_finfo_t));
@@ -723,7 +876,7 @@ s_create_cache_file(request_rec          *r,
       }
       if (dirf.name && strcmp(dirf.name, ".") != 0 && strcmp(dirf.name, "..") != 0) {
         total_size += (unsigned long)dirf.size;
-        DBG(r, "dirf.name=[%s] dirf.size=[%ld] dirf.atime=[%lld]", dirf.name, (long)dirf.size, (long long int)dirf.atime);
+        DBG(r,"REQ[%x] dirf.name=[%s] dirf.size=[%ld] dirf.atime=[%lld]", TO_ADDR(r),dirf.name, (long)dirf.size, (long long int)dirf.atime);
         if (dcf.atime >= dirf.atime) {
           memcpy(&dcf, &dirf, sizeof(apr_finfo_t));
         }
@@ -732,43 +885,44 @@ s_create_cache_file(request_rec          *r,
     }
     apr_dir_close(dir);
     if (total_size + writebyte < max_size) {
-      DBG(r, "There is an enough size in cache. total_size:[%lu] max_size:[%lu] found_file=[%d] max_size=[%lu]", total_size, max_size, found_file, max_size);
+      DBG(r,"REQ[%X] There is an enough size in cache. total_size:[%lu] max_size:[%lu] found_file=[%d] max_size=[%lu]", TO_ADDR(r),total_size, max_size, found_file, max_size);
       break;
     }
     if (found_file == 0 && writebyte >= max_size) {
-      ERR(r, "==========================================");
-      ERR(r, "cache space is too small...");
-      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 (writedata) free(writedata);
+      ERR(r,"REQ[%X] ==========================================",TO_ADDR(r));
+      ERR(r,"REQ[%X] cache space is too small...",TO_ADDR(r));
+      ERR(r,"REQ[%X] At least the same size as %luByte is necessary for me.", TO_ADDR(r),(unsigned long)writebyte); 
+      ERR(r,"REQ[%X] Please specify the ChxjImageCacheLimit that is larger than now value. ",TO_ADDR(r));
+      ERR(r,"REQ[%X] ==========================================",TO_ADDR(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);
+    DBG(r,"REQ[%X] Image Cache dir is full. total_size:[%lu] max_size:[%lu]",TO_ADDR(r),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, (long long int)dcf.atime);
+    DBG(r,"REQ[%X] delete image cache target:[%s] atime:[%lld]", TO_ADDR(r),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 (writedata) free(writedata);
+      ERR(r,"REQ[%X] cache file delete failure.[%s]", TO_ADDR(r),delete_file_name);
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
-    DBG(r, "deleted image cache target:[%s]", delete_file_name);
+    DBG(r,"REQ[%X] deleted image cache target:[%s]", TO_ADDR(r),delete_file_name);
     if (total_size + writebyte - dcf.size < max_size) {
-      DBG(r, "OK, there is an enough size in cache.");
+      DBG(r,"REQ[%X] OK, there is an enough size in cache.",TO_ADDR(r));
       break;
     }
   }
 
   /* 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);
-    if (writedata) free(writedata);
+    ERR(r,"REQ[%X] file open error.[%s]", TO_ADDR(r), tmpfile);
+    if (sv_writedata) free(sv_writedata);
     return HTTP_INTERNAL_SERVER_ERROR;
   }
 
@@ -776,7 +930,7 @@ s_create_cache_file(request_rec          *r,
   if (rv != APR_SUCCESS) {
     DestroyMagickWand(magick_wand);
     apr_file_close(fout);
-    if (writedata) free(writedata);
+    if (sv_writedata) free(sv_writedata);
     return HTTP_INTERNAL_SERVER_ERROR;
   }
 
@@ -791,24 +945,24 @@ s_create_cache_file(request_rec          *r,
     rv = apr_file_putc((crc >> 8)  & 0xff, fout);
     if (rv != APR_SUCCESS) {
       DestroyMagickWand(magick_wand);
-      if (writedata) free(writedata);
+      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 (writedata) free(writedata);
+      if (sv_writedata) free(sv_writedata);
       return HTTP_INTERNAL_SERVER_ERROR;
     }
   }
 
   DestroyMagickWand(magick_wand);
-  if (writedata) free(writedata);
+  if (sv_writedata) free(sv_writedata);
 
   rv = apr_file_close(fout);
   if (rv != APR_SUCCESS) {
-    DBG(r,"file write error.[%s]", tmpfile);
+    DBG(r,"REQ[%X] file write error.[%s]",TO_ADDR(r),tmpfile);
     return HTTP_INTERNAL_SERVER_ERROR;
   }
 
@@ -839,7 +993,7 @@ s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_table *spec)
   
   r->content_type = apr_psprintf(r->pool, "image/jpeg");
   ap_set_content_type(r, "image/jpeg");
-  DBG(r,"convert to jpg");
+  DBG(r,"REQ[%X] convert to jpg",TO_ADDR(r));
   return 0;
 }
 
@@ -867,7 +1021,7 @@ s_convert_to_png(MagickWand *magick_wand, request_rec *r, device_table *spec)
   
   r->content_type = apr_psprintf(r->pool, "image/png");
   ap_set_content_type(r, "image/png");
-  DBG(r, "convert to png");
+  DBG(r,"REQ[%X] convert to png",TO_ADDR(r));
   return 0;
 }
 
@@ -896,7 +1050,7 @@ s_convert_to_gif(MagickWand *magick_wand, request_rec *r, device_table *spec)
   r->content_type = apr_psprintf(r->pool, "image/gif");
   ap_set_content_type(r, "image/gif");
   
-  DBG(r,"convert to gif");
+  DBG(r,"REQ[%X] convert to gif",TO_ADDR(r));
   return 0;
 }
 
@@ -925,7 +1079,7 @@ s_convert_to_bmp(MagickWand *magick_wand, request_rec *r, device_table *spec)
   r->content_type = apr_psprintf(r->pool, "image/bmp");
   ap_set_content_type(r, "image/bmp");
   
-  DBG(r, "convert to bmp(unsupported)");
+  DBG(r,"REQ[%X] convert to bmp(unsupported)",TO_ADDR(r));
   return 0;
 }
 
@@ -962,12 +1116,21 @@ s_create_blob_data(request_rec          *r,
     int oldw = MagickGetImageWidth(magick_wand);
     int oldh = MagickGetImageHeight(magick_wand);
     int done_fixup_size = 0;
+    int ww = spec->width;
+    int hh = spec->heigh;
+    if (IS_IPHONE(spec) || IS_ANDROID(spec)) {
+      ww = (int)((double)ww * (double)1.5);
+      hh = (int)((double)hh * (double)1.5);
+      if (IS_ANDROID(spec)) {
+        ww = ww - ADJUST_WIDTH_FOR_ANDROID;
+      }
+    }
     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)) {
+      || (qsp->mode != IMG_CONV_MODE_WALLPAPER && ww < oldw && hh < oldh)) {
       /*
        * The size of the image is changed.
        */
-      DBG(r,"call s_fixup_size()");
+      DBG(r,"REQ[%X] call s_fixup_size()",TO_ADDR(r));
 
       if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) {
         EXIT_MAGICK_ERROR();
@@ -979,7 +1142,7 @@ s_create_blob_data(request_rec          *r,
     /*
      * 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) {
       EXIT_MAGICK_ERROR();
@@ -989,7 +1152,7 @@ s_create_blob_data(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) {
       EXIT_MAGICK_ERROR();
@@ -1001,7 +1164,7 @@ s_create_blob_data(request_rec          *r,
       /*
        * The size of the image is changed.
        */
-      DBG(r,"call s_fixup_size()");
+      DBG(r,"REQ[%X] call s_fixup_size()",TO_ADDR(r));
       if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) {
         EXIT_MAGICK_ERROR();
         return NULL;
@@ -1038,7 +1201,7 @@ s_create_blob_data(request_rec          *r,
     }
   }
 
-  DBG(r,"start convert and compression");
+  DBG(r,"REQ[%X] start convert and compression",TO_ADDR(r));
 
   if (!fixFormatFlag) {
     if (spec->available_jpeg) {
@@ -1065,7 +1228,7 @@ s_create_blob_data(request_rec          *r,
   /*--------------------------------------------------------------------------*/
   /* Add Comment (Copyright and so on.)                                       */
   /*--------------------------------------------------------------------------*/
-  DBG(r,"call s_add_copyright()");
+  DBG(r,"REQ[%X] call s_add_copyright()",TO_ADDR(r));
 
   if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL)
     return NULL;
@@ -1074,11 +1237,11 @@ s_create_blob_data(request_rec          *r,
 
   if (! writebyte) {
     DestroyMagickWand(magick_wand);
-    DBG(r,"convert failure to Jpeg ");
+    DBG(r,"REQ[%X] convert failure to Jpeg ",TO_ADDR(r));
     return NULL;
   }
 
-  DBG(r,"end convert and compression");
+  DBG(r,"REQ[%X] end convert and compression",TO_ADDR(r));
 
 
   
@@ -1120,22 +1283,32 @@ s_fixup_size(MagickWand           *magick_wand,
   oldw = MagickGetImageWidth(magick_wand);
   oldh = MagickGetImageHeight(magick_wand);
 
-  DBG(r,"detect width=[%d]", oldw);
-  DBG(r,"detect heigh=[%d]", oldh);
+  DBG(r,"REQ[%X] detect width=[%d]", TO_ADDR(r),oldw);
+  DBG(r,"REQ[%X] detect heigh=[%d]", TO_ADDR(r),oldh);
 
   neww = oldw;
   newh = oldh;
 
-  DBG(r,"detect spec width=[%d]", spec->width);
-  DBG(r,"detect spec heigh=[%d]", spec->heigh);
+  DBG(r,"REQ[%X] detect spec width=[%d]", TO_ADDR(r),spec->width);
+  DBG(r,"REQ[%X] detect spec heigh=[%d]", TO_ADDR(r),spec->heigh);
 
   c_width = spec->width;
   c_heigh = spec->heigh;
 
+  if (IS_IPHONE(spec) || IS_ANDROID(spec)) {
+    c_width = (int)((double)c_width * (double)1.5);
+    c_heigh = (int)((double)c_heigh * (double)1.5);
+    if (IS_ANDROID(spec)) {
+      c_width = c_width - ADJUST_WIDTH_FOR_ANDROID;
+    }
+    DBG(r,"REQ[%X] detect iphone/android width=[%d]", TO_ADDR(r),c_width);
+    DBG(r,"REQ[%X] detect iphone/android heigh=[%d]", TO_ADDR(r),c_heigh);
+  }
+
   switch(mode) {
   case IMG_CONV_MODE_THUMBNAIL:
 
-    DBG(r,"**** detect thumbnail mode ****");
+    DBG(r,"REQ[%X] **** detect thumbnail mode ****",TO_ADDR(r));
 
     if (neww > c_width) {
       newh = (int)((double)newh * (double)((double)c_width / (double)neww));
@@ -1153,24 +1326,24 @@ s_fixup_size(MagickWand           *magick_wand,
   case IMG_CONV_MODE_WALLPAPER:
   case IMG_CONV_MODE_EZGET:
 
-    DBG(r,"**** detect wallpaper mode ****");
+    DBG(r,"REQ[%X] **** detect wallpaper mode ****",TO_ADDR(r));
 
     if (spec->wp_width && spec->wp_heigh) {
       c_width = spec->wp_width;
       c_heigh = spec->wp_heigh;
     }
 
-    DBG(r,"calc new width and height");
+    DBG(r,"REQ[%X] calc new width and height",TO_ADDR(r));
 
     neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
     newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
 
-    DBG(r,"newh = [%d] neww = [%d]", newh, neww);
+    DBG(r,"REQ[%X] newh = [%d] neww = [%d]", TO_ADDR(r),newh, neww);
     break;
 
   default:
 
-    DBG(r,"**** detect normal mode ****");
+    DBG(r,"REQ[%X] **** detect normal mode ****",TO_ADDR(r));
 
     if (qsp->ua_flag != UA_IGN && spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
       if (neww > c_width) {
@@ -1190,8 +1363,8 @@ s_fixup_size(MagickWand           *magick_wand,
   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);
+    DBG(r,"REQ[%X] convert width=[%d --> %d]", TO_ADDR(r),oldw, neww);
+    DBG(r,"REQ[%X] convert heigh=[%d --> %d]", TO_ADDR(r),oldh, newh);
   
     MagickResetIterator(magick_wand);
   
@@ -1217,11 +1390,11 @@ s_fixup_size(MagickWand           *magick_wand,
   
       case IMG_CONV_MODE_NORMAL:
         if (qsp->width) {
-          DBG(r,"convert width=[%d --> %d]", neww, qsp->width);
+          DBG(r,"REQ[%X] convert width=[%d --> %d]", TO_ADDR(r),neww, qsp->width);
           neww = qsp->width;
         }
         if (qsp->height) {
-          DBG(r,"convert heigh=[%d --> %d]", newh, qsp->height);
+          DBG(r,"REQ[%X] convert heigh=[%d --> %d]", TO_ADDR(r),newh, qsp->height);
           newh = qsp->height;
         }
   
@@ -1260,39 +1433,41 @@ s_fixup_size(MagickWand           *magick_wand,
 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()");
+  DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
 
   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
-    DBG(r, "Pass s_fixup_color proc");
+    DBG(r,"REQ[%X] Pass s_fixup_color proc",TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return magick_wand;
   }
 
   unsigned long colors = MagickGetImageColors(magick_wand);
-  DBG(r, "now color:[%ld] spec->color:[%ld]", colors, (unsigned long)spec->color);
+  DBG(r,"REQ[%X] now color:[%ld] spec->color:[%ld]", TO_ADDR(r),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);
+    DBG(r,"REQ[%X] Pass s_fixup_color proc. color:[%ld] spec->color:[%d]", TO_ADDR(r),colors, spec->color);
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return magick_wand;
   }
 
   if (spec->color >= 256) {
 
-    DBG(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color);
+    DBG(r,"REQ[%X] call MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
 
     if (MagickQuantizeImage(magick_wand,
                            spec->color,
                            RGBColorspace,
-                           0,
+                           4,   /* tree depth of 4 */
                            1,
                            0) == MagickFalse) {
       EXIT_MAGICK_ERROR();
       return NULL;
     }
 
-    DBG(r,"call end MagickQuantizeImage() spec->color=[%d]",spec->color);
+    DBG(r,"REQ[%X] call end MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
 
   }
   else {
-    DBG(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color);
+    DBG(r,"REQ[%X] call MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
 
     if (MagickQuantizeImage(magick_wand,
                            spec->color,
@@ -1304,11 +1479,11 @@ s_fixup_color(MagickWand *magick_wand, request_rec *r, device_table *spec, img_c
       return NULL;
     }
 
-    DBG(r,"call end MagickQuantizeImage() spec->color=[%d]",spec->color);
+    DBG(r,"REQ[%X] call end MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
   }
 
 
-  DBG(r,"end chxj_fixup_clor()");
+  DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
 
   return magick_wand;
 }
@@ -1319,7 +1494,7 @@ 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");
+    DBG(r,"REQ[%X] Pass s_fixup_depth proc",TO_ADDR(r));
     return magick_wand;
   }
 
@@ -1382,13 +1557,13 @@ s_add_copyright(MagickWand *magick_wand, request_rec *r, device_table *spec)
   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");
+    DBG(r,"REQ[%X] Pass add_copiright proc",TO_ADDR(r));
     return magick_wand;
   }
 
   if (conf->image_copyright) {
 
-    DBG(r, "Add COPYRIGHT [%s]", conf->image_copyright);
+    DBG(r,"REQ[%X] Add COPYRIGHT [%s]", TO_ADDR(r),conf->image_copyright);
 
     if (spec->html_spec_type == CHXJ_SPEC_Jhtml
     ||  spec->html_spec_type == CHXJ_SPEC_Jxhtml) {
@@ -1435,7 +1610,6 @@ s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
   apr_size_t         writebyte = 0;
   char               *writedata;
   apr_size_t         prev_size = 0;
-  int                revers_flag = 0;
   char               *fmt;
   int                fmt_type = 0;
   
@@ -1458,10 +1632,9 @@ s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
       }
   
       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 (writebyte >= prev_size) {
+        DBG(r,"REQ[%X] quality=[%ld] size=[%d]", TO_ADDR(r),(long)quality, (int)writebyte);
+        quality += 5;
         if (quality > 100) {
           if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
             EXIT_MAGICK_ERROR();
@@ -1469,11 +1642,14 @@ s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
           }
           break;
         }
-        prev_size = writebyte;
-        continue;
+        if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
+          EXIT_MAGICK_ERROR();
+          return NULL;
+        }
+        break;
       }
   
-      DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte);
+      DBG(r,"REQ[%X] quality=[%ld] size=[%d]", TO_ADDR(r),(long)quality, (int)writebyte);
   
       if (spec->cache == 0)
         break;
@@ -1481,7 +1657,7 @@ s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
       if (writebyte <= (unsigned int)spec->cache)
         break;
   
-      quality -= 10;
+      quality -= 5;
   
       if (quality == 0 || quality > 100)
         break;
@@ -1543,7 +1719,7 @@ s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
       }
       writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
 
-      DBG(r,"now_color=[%ld] size=[%d]", (long)now_color, (int)writebyte);
+      DBG(r,"REQ[%X] now_color=[%ld] size=[%d]",TO_ADDR(r),(long)now_color, (int)writebyte);
 
       /* Once per request */
       break;
@@ -1556,31 +1732,103 @@ s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
 
 
 static apr_status_t 
-s_send_cache_file(device_table *UNUSED(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_size_t   sendbyte;
   char         *contentLength;
+  char         *readdata;
 
   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);
+
+  /* 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) {
     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
     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);
+    readdata = apr_palloc(r->pool, st.size);
+#if APR_HAS_MMAP
+    DBG(r, "REQ[%X] Use mmap to read cache file", TO_ADDR(r));
+    {
+      apr_finfo_t finfo;
+      apr_mmap_t *mmap = NULL;
+      rv = apr_file_open(&fout, tmpfile, 
+        APR_FOPEN_READ, 
+        APR_OS_DEFAULT, r->pool);
+      if (rv != APR_SUCCESS) {
+        char buf[256];
+        ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+        ERR(r,"REQ[%X] %s:%d tmpfile open failed[%s]", TO_ADDR(r),__FILE__,__LINE__,tmpfile);
+        DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+        return HTTP_NOT_FOUND;
+      }
+      rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fout);
+      if (rv != APR_SUCCESS) {
+        char buf[256];
+        apr_file_close(fout);
+        ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+        DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+        return HTTP_NOT_FOUND;
+      }
+      rv = apr_mmap_create(&mmap, fout, 0, finfo.size, APR_MMAP_READ, r->pool);
+      if (rv != APR_SUCCESS) {
+        char buf[256];
+        apr_file_close(fout);
+        ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+        DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+        return HTTP_NOT_FOUND;
+      }
+      memcpy(readdata, mmap->mm, st.size);
+      //apr_mmap_delete(mmap);
+      apr_file_close(fout);
+    }
+#else
+    {
+      apr_size_t   readbyte;
+      rv = apr_file_open(&fout, tmpfile, 
+        APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK, 
+        APR_OS_DEFAULT, r->pool);
+      if (rv != APR_SUCCESS) {
+        ERR(r, "REQ[%X] %s:%d cache file open failed[%s]", TO_ADDR(r),__FILE__,__LINE__,tmpfile);
+        return HTTP_NOT_FOUND;
+      }
+      rv = apr_file_read_full(fout, (void*)readdata, st.size, &readbyte);
+      apr_file_close(fout);
+      if (rv != APR_SUCCESS) {
+        char buf[256];
+        ERR(r,"REQ[%X] %s:%d apr_file_read_full failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+        ERR(r,"REQ[%X] %s:%d tmpfile open failed[%s]", TO_ADDR(r),__FILE__,__LINE__,tmpfile);
+        return HTTP_NOT_FOUND;
+      }
+    }
+#endif
+
     MagickWand *magick_wand = NewMagickWand();
-    if (MagickReadImage(magick_wand,tmpfile) == MagickFalse) {
+    if (MagickReadImageBlob(magick_wand,readdata, st.size) == MagickFalse) {
       EXIT_MAGICK_ERROR();
+      DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
       return HTTP_NOT_FOUND;
     }
     if (MagickStripImage(magick_wand) == MagickFalse) {
@@ -1590,38 +1838,87 @@ s_send_cache_file(device_table *UNUSED(spec), query_string_param_t *query_string
     }
     char *nowFormat = MagickGetImageFormat(magick_wand);
     DestroyMagickWand(magick_wand);
+    char *fname = apr_pstrdup(r->pool, r->filename);
+    char *ext = strrchr(fname, '.');
     if (nowFormat) {
       if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) {
-        DBG(r, "detect cache file => jpg.");
+        DBG(r,"REQ[%X] detect cache file => jpg.",TO_ADDR(r));
         ap_set_content_type(r, "image/jpeg");
+
+        if (!ext) {
+          fname = apr_pstrcat(r->pool, fname, ".jpg");
+        }
+        else if (ext && strcasecmp(".jpeg", ext) != 0 && strcasecmp(".jpg", ext) != 0) {
+          *ext = 0;
+          fname = apr_pstrcat(r->pool, fname, ".jpg");
+        }
       }
       else if (STRCASEEQ('p','P',"png", nowFormat)) {
-        DBG(r, "detect cache file => png.");
+        DBG(r,"REQ[%X] detect cache file => png.",TO_ADDR(r));
         ap_set_content_type(r, "image/png");
+
+        if (!ext) {
+          fname = apr_pstrcat(r->pool, fname, ".png");
+        }
+        else if (ext && strcasecmp(".png", ext) != 0) {
+          *ext = 0;
+          fname = apr_pstrcat(r->pool, fname, ".png");
+        }
+
       }
       else if (STRCASEEQ('g','G',"gif", nowFormat)) {
-        DBG(r, "detect cache file => gif.");
+        DBG(r,"REQ[%X] detect cache file => gif.",TO_ADDR(r));
         ap_set_content_type(r, "image/gif");
+
+        if (!ext) {
+          fname = apr_pstrcat(r->pool, fname, ".gif");
+        }
+        else if (ext && strcasecmp(".gif", ext) != 0) {
+DBG(r, "REQ[%X]", TO_ADDR(r));
+          *ext = '\0';
+          fname = apr_pstrcat(r->pool, fname, ".gif");
+        }
       }
       else if (STRCASEEQ('b','B',"bmp", nowFormat)) {
-        DBG(r, "detect cache file => bmp.");
+        DBG(r,"REQ[%X] detect cache file => bmp.",TO_ADDR(r));
         ap_set_content_type(r, "image/bmp");
+
+        if (!ext) {
+          fname = apr_pstrcat(r->pool, fname, ".bmp");
+        }
+        else if (ext && strcasecmp(".bmp", ext) != 0) {
+          *ext = 0;
+          fname = apr_pstrcat(r->pool, fname, ".bmp");
+        }
       }
       else {
-        ERR(r, "detect unknown file");
+        ERR(r,"REQ[%X] detect unknown file",TO_ADDR(r));
         return HTTP_NOT_FOUND;
       }
     }
-    rv = apr_file_open(&fout, tmpfile, 
-      APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
-    if (rv != APR_SUCCESS) {
-      DBG(r, "cache file open failed[%s]", tmpfile);
-      return HTTP_NOT_FOUND;
+    if (query_string->mode == IMG_CONV_MODE_WALLPAPER && (IS_IPHONE(spec)||IS_ANDROID(spec))) {
+      ap_set_content_type(r, "application/octet-stream");
+      apr_table_setn(r->headers_out, "Content-Disposition", apr_psprintf(r->pool, "attachment; filename=%s", fname));
+      DBG(r,"REQ[%X] detect cache file => iphone/android",TO_ADDR(r));
     }
-    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);
+    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");
+      }
+    }
+    {
+      conn_rec *c = r->connection;
+      apr_bucket_brigade *bb = NULL;
+      apr_bucket *b;
+  
+      bb = apr_brigade_create(r->pool, c->bucket_alloc);
+      b = apr_bucket_heap_create(readdata, st.size, NULL, c->bucket_alloc);
+      APR_BRIGADE_INSERT_TAIL(bb, b);
+      ap_pass_brigade(r->output_filters, bb);
+      sendbyte = st.size;
+    }
+    DBG(r, "REQ[%X] send file data[%d]byte", TO_ADDR(r), (int)sendbyte);
   }
   else
   if (query_string->mode == IMG_CONV_MODE_EZGET) {
@@ -1666,20 +1963,56 @@ s_send_cache_file(device_table *UNUSED(spec), query_string_param_t *query_string
       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 APR_HAS_MMAP
+      DBG(r, "REQ[%X] Use ap_send_mmap to send cache file", TO_ADDR(r));
+      {
+        apr_finfo_t finfo;
+        apr_mmap_t *mmap;
+        rv = apr_file_open(&fout, tmpfile, 
+          APR_FOPEN_READ | APR_FOPEN_BINARY, 
+          APR_OS_DEFAULT, r->pool);
+        if (rv != APR_SUCCESS) {
+          ERR(r,"REQ[%X] %s:%d tmpfile open failed[%s]", TO_ADDR(r),__FILE__,__LINE__,tmpfile);
+          DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+          return HTTP_NOT_FOUND;
+        }
+        rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fout);
+        if (rv != APR_SUCCESS) {
+          char buf[256];
+          apr_file_close(fout);
+          ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+          DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+          return HTTP_NOT_FOUND;
+        }
+        rv = apr_mmap_create(&mmap, fout, 0, finfo.size, APR_MMAP_READ, r->pool);
+        if (rv != APR_SUCCESS) {
+          char buf[256];
+          apr_file_close(fout);
+          ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+          DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+          return HTTP_NOT_FOUND;
+        }
+        sendbyte = ap_send_mmap(mmap, r, query_string->offset, query_string->count);
+        // apr_mmap_delete(mmap);
+        apr_file_close(fout);
+      }
+      ap_rflush(r);
+#else
       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_OS_DEFAULT, r->pool);
 
       if (rv != APR_SUCCESS) {
-        DBG(r,"tmpfile open failed[%s]", tmpfile);
+        DBG(r,"REQ[%X] tmpfile open failed[%s]", TO_ADDR(r),tmpfile);
         return HTTP_NOT_FOUND;
       }
 
       ap_send_fd(fout, r, query_string->offset, query_string->count, &sendbyte);
       apr_file_close(fout);
       ap_rflush(r);
-      DBG(r, "send file data[%d]byte", (int)sendbyte);
+#endif
+      DBG(r,"REQ[%X] send file data[%d]byte", TO_ADDR(r),(int)sendbyte);
     }
   }
   
@@ -1699,37 +2032,90 @@ s_send_original_file(request_rec *r, const char *originalfile)
   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);
+  }
+
+#if APR_HAS_MMAP
+  DBG(r, "REQ[%X] Use ap_send_mmap to send original image file", TO_ADDR(r));
+  {
+    apr_finfo_t finfo;
+    apr_mmap_t *mmap = NULL;
+    rv = apr_file_open(&fout, 
+                       originalfile, 
+                       APR_FOPEN_READ | APR_FOPEN_SHARELOCK, 
+                       APR_OS_DEFAULT, r->pool);
+    if (rv != APR_SUCCESS) {
+      char buf[256];
+      ERR(r,"REQ[%X] %s:%d apr_file_open failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+      ERR(r,"REQ[%X] %s:%d original file open failed[%s]", TO_ADDR(r),__FILE__,__LINE__,originalfile);
+      DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+      return HTTP_NOT_FOUND;
+    }
+    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fout);
+    if (rv != APR_SUCCESS) {
+      char buf[256];
+      apr_file_close(fout);
+      ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+      DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+      return HTTP_NOT_FOUND;
+    }
+    rv = apr_mmap_create(&mmap, fout, 0, finfo.size, APR_MMAP_READ, r->pool);
+    if (rv != APR_SUCCESS) {
+      char buf[256];
+      apr_file_close(fout);
+      ERR(r,"REQ[%X] %s:%d apr_file_info_get failed. [%s]", TO_ADDR(r),__FILE__,__LINE__,apr_strerror(rv,buf,256));
+      DBG(r,"REQ[%X] end %s",TO_ADDR(r), __func__);
+      return HTTP_NOT_FOUND;
+    }
+    sendbyte = ap_send_mmap(mmap, r, 0, st.size);
+    //apr_mmap_delete(mmap);
+    apr_file_close(fout);
+  }
+  ap_rflush(r);
+#else
   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_OS_DEFAULT, r->pool);
   if (rv != APR_SUCCESS) {
-    DBG(r, "originalfile open failed[%s]", originalfile);
+    DBG(r,"REQ[%X] originalfile open failed[%s]", TO_ADDR(r),originalfile);
     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);
+#endif
+  DBG(r,"REQ[%x] send file data[%d]byte", TO_ADDR(r),(int)sendbyte);
   
   return OK;
 }
 
 
 static apr_status_t 
-s_header_only_cache_file(device_table *UNUSED(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;
+  mod_chxj_config *conf = ap_get_module_config(r->per_dir_config, &chxj_module);
+
+  DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
 
   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
-  if (rv != APR_SUCCESS)
+  if (rv != APR_SUCCESS) {
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     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 (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
@@ -1749,28 +2135,28 @@ s_header_only_cache_file(device_table *UNUSED(spec), query_string_param_t *query
     DestroyMagickWand(magick_wand);
     if (nowFormat) {
       if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) {
-        DBG(r, "detect cache file => jpg.");
+        DBG(r,"REQ[%x] detect cache file => jpg.",TO_ADDR(r));
         ap_set_content_type(r, "image/jpeg");
       }
       else if (STRCASEEQ('p','P',"png", nowFormat)) {
-        DBG(r, "detect cache file => png.");
+        DBG(r,"REQ[%X] detect cache file => png.",TO_ADDR(r));
         ap_set_content_type(r, "image/png");
       }
       else if (STRCASEEQ('g','G',"gif", nowFormat)) {
-        DBG(r, "detect cache file => gif.");
+        DBG(r,"REQ[%X] detect cache file => gif.",TO_ADDR(r));
         ap_set_content_type(r, "image/gif");
       }
       else if (STRCASEEQ('b','B',"bmp", nowFormat)) {
-        DBG(r, "detect cache file => bmp.");
+        DBG(r,"REQ[%X] detect cache file => bmp.",TO_ADDR(r));
         ap_set_content_type(r, "image/bmp");
       }
       else {
-        ERR(r, "detect unknown file");
+        ERR(r, "REQ[%X] detect unknown file", TO_ADDR(r));
         return HTTP_NOT_FOUND;
       }
     }
   
-    DBG(r,"Content-Length:[%d]", (int)st.size);
+    DBG(r,"REQ[%X] Content-Length:[%d]", TO_ADDR(r),(int)st.size);
   }
   else
   if (query_string->mode == IMG_CONV_MODE_EZGET) {
@@ -1807,10 +2193,17 @@ s_header_only_cache_file(device_table *UNUSED(spec), query_string_param_t *query
       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()",TO_ADDR(r),__func__);
   return OK;
 }
 
@@ -1828,7 +2221,7 @@ s_init_serial_pattern(apr_pool_t *p)
     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][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z] ");
+    v_softbank_serial_pattern1 = chxj_compile_for_preg_replace(p, "/SN[0-9a-zA-Z]+ ");
   }  
 }
 
@@ -1857,20 +2250,20 @@ s_create_workfile_name(
   /* 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);
+  DBG(r,"REQ[%X] old user_agent:[%s] ==> new user_agent:[%s]", TO_ADDR(r),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, new_user_agent);
-    DBG(r, "mode=thumbnail [%s]", fname);
+    DBG(r,"REQ[%X] mode=thumbnail [%s]", TO_ADDR(r),fname);
     break;
 
   case IMG_CONV_MODE_WALLPAPER:
   case IMG_CONV_MODE_EZGET:
     fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, new_user_agent);
-    DBG(r, "mode=WallPaper [%s]", fname);
+    DBG(r,"REQ[%X] mode=WallPaper [%s]", TO_ADDR(r),fname);
     break;
 
   case IMG_CONV_MODE_NORMAL:
@@ -1884,7 +2277,7 @@ s_create_workfile_name(
     if (qsp->height)
       fname = apr_psprintf(r->pool, "%s.h%d", fname, qsp->height);
 
-    DBG(r,"mode=normal [%s]", fname);
+    DBG(r,"REQ[%X] mode=normal [%s]", TO_ADDR(r),fname);
     break;
   }
   if (qsp->ua_flag == UA_IGN) {
@@ -1897,6 +2290,7 @@ s_create_workfile_name(
     if (fname[ii] == '/' 
     ||  fname[ii] == ' ' 
     ||  fname[ii] == '-' 
+    ||  fname[ii] == '.' 
     ||  fname[ii] == '(' 
     ||  fname[ii] == ')') {
       w[jj++] = '_';
@@ -1906,7 +2300,7 @@ s_create_workfile_name(
     }
   }
 
-  return apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir,w);
+  return apr_psprintf(r->pool, "%s/%s.%s", conf->image_cache_dir,w,CACHEDATA_EXT);
 }
 
 
@@ -1937,10 +2331,15 @@ chxj_trans_name(request_rec *r)
   int             ii;
   char            *ext[] = {
           "jpg",
+          "JPG",
           "jpeg",
+          "JPEG",
           "png",
+          "PNG",
           "bmp",
+          "BMP",
           "gif",
+          "GIF",
           "qrc",    /* QRCode出力用ファイルの拡張子 */
           "",
   };
@@ -1950,22 +2349,24 @@ chxj_trans_name(request_rec *r)
   int      do_ext_check = TRUE;
   int      next_ok      = FALSE;
 
-  DBG(r, "start chxj_trans_name()");
+  DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
 
   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);
+    DBG(r,"REQ[%X] conf is null[%s]", TO_ADDR(r),r->uri);
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return DECLINED;
   }
 
   if (conf->image != CHXJ_IMG_ON) {
-    DBG(r, "end chxj_trans_name() conf not found");
+    DBG(r,"REQ[%X] conf not found",TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
     return DECLINED;
   }
 
 
-  DBG(r,"Match URI[%s]", r->uri);
+  DBG(r,"REQ[%X] Match URI[%s]", TO_ADDR(r),r->uri);
 
 
   if (r->filename == NULL) 
@@ -1977,7 +2378,7 @@ chxj_trans_name(request_rec *r)
   else 
     filename_sv = r->filename;
 
-  DBG(r,"r->filename[%s]", filename_sv);
+  DBG(r,"REQ[%X] r->filename[%s]", TO_ADDR(r),filename_sv);
 
   ccp = ap_document_root(r);
   if (ccp == NULL)
@@ -1997,10 +2398,131 @@ chxj_trans_name(request_rec *r)
   else
     filename_sv = apr_pstrcat(r->pool, docroot, filename_sv, NULL);
 
-  DBG(r,"URI[%s]", filename_sv);
+  DBG(r,"REQ[%X] URI[%s]", TO_ADDR(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,"REQ[%X] search [%s]", TO_ADDR(r),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,"REQ[%X] NotFound [%s]", TO_ADDR(r),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,"REQ[%X] NotFound [%s]", TO_ADDR(r),r->filename);
+    return DECLINED;
+  }
+
+  if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) {
+    DBG(r,"REQ[%X] Found [%s]", TO_ADDR(r),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 %s()",TO_ADDR(r),__func__);
+  return OK;
+}
+
+
+
+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 %s()",TO_ADDR(r),__func__);
+
+  conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
+
+  if (conf == NULL) {
+    DBG(r,"REQ[%X] conf is null[%s]", TO_ADDR(r), r->uri);
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
+    return DECLINED;
+  }
+
+  if (conf->image != CHXJ_IMG_ON) {
+    DBG(r,"REQ[%X] ImageEngineOff", TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
+    return DECLINED;
+  }
+
+
+  DBG(r,"REQ[%X] Match URI[%s]", TO_ADDR(r),r->uri);
+
+  if (r->filename == NULL) {
+    DBG(r,"REQ[%X] r->filename is null", TO_ADDR(r));
+    DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
+    return DECLINED;
+  }
+     
+  filename_sv = r->filename;
+
+  DBG(r,"REQ[%x] r->filename[%s]", TO_ADDR(r), 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) {
@@ -2012,14 +2534,14 @@ 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);
       }
       else 
         fname = apr_psprintf(r->pool, "%s.%s", filename_sv, ext[ii]);
   
-      DBG(r,"search [%s]", fname);
+      DBG(r,"REQ[%X] search [%s]", TO_ADDR(r),fname);
   
       rv = apr_stat(&st, fname, APR_FINFO_MIN, r->pool);
       if (rv == APR_SUCCESS) {
@@ -2031,10 +2553,10 @@ chxj_trans_name(request_rec *r)
     }
   }
   if (fname == NULL) {
-    DBG(r,"NotFound [%s]", r->filename);
+    DBG(r,"REQ[%X] NotFound [%s]", TO_ADDR(r),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) {
@@ -2045,12 +2567,12 @@ chxj_trans_name(request_rec *r)
   }
 
   if (! next_ok)  {
-    DBG(r,"NotFound [%s]", r->filename);
+    DBG(r,"REQ[%X] NotFound [%s]", TO_ADDR(r),r->filename);
     return DECLINED;
   }
 
   if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) {
-    DBG(r,"Found [%s]", fname);
+    DBG(r,"REQ[%X] Found [%s]", TO_ADDR(r),fname);
 
     r->filename = apr_psprintf(r->pool, "%s", fname);
   
@@ -2059,7 +2581,7 @@ chxj_trans_name(request_rec *r)
     else
       r->handler = apr_psprintf(r->pool, "chxj-picture");
   }
-  DBG(r, "end chxj_trans_name()");
+  DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
   return OK;
 }
 
@@ -2183,6 +2705,86 @@ 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()",TO_ADDR(r),__func__);
+  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) {
+      ERR(r, "REQ[%X] memory allocation error.", TO_ADDR(r));
+      DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
+      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]", TO_ADDR(r), (unsigned int)*len);
+  }
+  else {
+    result = data;
+  }
+  DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
+#undef PNG_SIG_AND_IHDR_SZ
+#undef PNG_COPYRIGHT_KEY
+#undef PNG_COPYRIGHT_VAL
+  return result;
+}
 /*
  * vim:ts=2 et
  */