戻る 目次へ
§5.1.9 image.cc
戻る 目次へ

  1: /******************************************************************************
  2:   ezht - Copyright (C) 2004 Tradcrafts
  3:   This file is part of the ezht.
  4:                                                                        
  5:   ezht is free software; you can redistribute it and/or modify
  6:   it under the terms of the GNU General Public License as published by the 
  7:   Free Software Foundation;   either version 2 of the License,  or (at your 
  8:   option) any later version.
  9: 
 10:   ezht is distributed in the hope that it will be useful, but 
 11:   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 12:   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 13:   more details.
 14: 
 15:   You should have received a copy of the GNU General Public License along with
 16:   this program; see the file COPYING.  If not, write to the Free Software 
 17:   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 18: ******************************************************************************/
 19: 
 20: #include "error.h"
 21: #include "image.h"
 22: #include "vfile.h"
 23: 
 24: #include <stdio.h>
 25: #include <errno.h>
 26: #include <stdlib.h>
 27: #include <stdint.h>
 28: 
 29: static inline void inv(void *p,int size)
 30: {
 31:   int i=0,j=size-1,m=size/2;
 32:   while(i<m)
 33:     {
 34:       int8_t tmp = *(((int8_t*)p)+i);
 35:       *(((int8_t*)p)+i++) = *(((int8_t*)p)+j);
 36:       *(((int8_t*)p)+j--) = tmp;
 37:     }
 38: }
 39: 
 40: static int16_t lendian16(int16_t num)
 41: {
 42:   uint16_t check = 0xff00;
 43:   if( *(uint8_t*)&check ){
 44:     // BIG ENDIANの場合
 45:     inv(&num,sizeof(num));
 46:   }
 47: 
 48:   return num;
 49: }
 50: 
 51: static int32_t bendian32(int32_t num)
 52: {
 53:   uint16_t check = 0x00ff;
 54:   if( *(uint8_t*)&check ){
 55:     // LITTLE ENDIANの場合
 56:     inv(&num,sizeof(num));
 57:   }
 58: 
 59:   return num;
 60: }
 61: 
 62: static int16_t bendian16(int16_t num)
 63: {
 64:   uint16_t check = 0x00ff;
 65:   if( *(uint8_t*)&check ){
 66:     // LITTLE ENDIANの場合
 67:     inv(&num,sizeof(num));
 68:   }
 69: 
 70:   return num;
 71: }
 72: 
 73: static bool get_image_info(const char *fname, int *width_r, int *height_r)
 74: {
 75:   FILE *f = fopen(fname,"rb");
 76:   if( ! f ){
 77:     warn("@image: can't open `%s': %s",fname,strerror(errno));
 78:     return false;
 79:   }
 80: 
 81:   bool success = false;
 82: 
 83:   char head[4];
 84:   fread(head,4,1,f);
 85:   
 86:   if( 0 == memcmp("GIF",head,3) ){
 87:     // GIF
 88:     fseek(f,6,SEEK_SET);
 89:     int16_t width,height;
 90:     fread(&width,2,1,f); 
 91:     fread(&height,2,1,f); 
 92:     *width_r = lendian16(width);
 93:     *height_r= lendian16(height);
 94:     success=true;
 95:   }else if( 0 == memcmp("PNG",head+1,3) ){
 96:     // PNG
 97:     fseek(f,8,SEEK_SET);
 98:     int32_t off;
 99:     char    code[4];
100:     while( fread(&off,4,1,f)==1 && fread(code,4,1,f)==1 ){
101:       off = bendian32(off);
102:       if( 0 == memcmp(code,"IHDR",4) ){
103:         int32_t width,height;
104:         fread(&width,4,1,f); 
105:         fread(&height,4,1,f); 
106:         *width_r = bendian32(width);
107:         *height_r= bendian32(height);
108:         success = true;
109:         break;
110:       }else if( 0 == memcmp(code,"IEND",4) ){
111:         break;
112:       }
113:       else{
114:         fseek(f,off+4,SEEK_CUR);
115:       }
116:     }
117:   }else{
118:     fseek(f,6,SEEK_SET);
119:     char tmp[4];
120:     fread(tmp,4,1,f);
121:     if( 0 == memcmp(tmp,"JFIF",4) ){
122:       // JPEG
123:       int b;
124:       while( EOF != (b=fgetc(f)) ){
125:         if( b==255 ){
126:           int t = fgetc(f);
127:           int16_t size;
128:           fread(&size,2,1,f);
129:           size = bendian16(size);
130:           if( t==0xc0 || t==0xc2){
131:             int16_t width,height;
132:             fgetc(f); // 捨てる
133:             fread(&height,2,1,f); 
134:             fread(&width,2,1,f); 
135:             *width_r = bendian16(width);
136:             *height_r= bendian16(height);
137:             success = true;
138:             break;
139:           }else{
140:             fseek(f,size-2,SEEK_CUR);
141:           }
142:         }
143:       }
144:       
145:     }
146:   }
147:   
148:   if( success && *width_r>0 && *height_r>0 )
149:     return true;
150: 
151:   warn("%s: could not take a image size",fname);
152:   return false;
153: 
154: 
155: }
156: 
157: #define IMGMARK "<!--img-->"
158: 
159: void cmd_image(std::vector<std::string> &args,std::string &ret_r)
160: {
161:   ret_r = ""; // デバッグ用
162:   if( args.size() == 1 ){
163:     error("@image: no image specified"); return;
164:   }
165: 
166:   if( args.size() > 3 ){
167:     error("@image: too many arguments"); return;
168:   }
169: 
170:   std::string imgfile = args[1];
171:   std::string opt;
172:   if( args.size() == 3 )
173:     opt = args[2];
174:   
175:   int width,height;
176:   if( get_image_info(args[1].c_str(),&width,&height) ){
177:     char tmp[64];
178:     sprintf(tmp,"width=\"%d\" height=\"%d\" ",width,height);
179:     opt = tmp + opt;
180:   }
181: 
182:   ret_r = IMGMARK  "<img src=\"" + imgfile + "\" " + opt + '>';
183: }
184: 
185: 
186: static bool _fix_image_callback(VFile *vf,const char *line,std::string&,
187:                                 std::string*)
188: {
189:   if( strstr(line,IMGMARK) )
190:     vf->chomp(); // 直前の行の改行を落とす
191: 
192:   return false;
193: }
194: 
195: void fixate_images()
196: {
197:   vf_each(_fix_image_callback);
198: }
199: 
200: 




Copyright 2004 Tradcrafts. ALL RIGHTS RESERVED.