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: