|
1 /** |
|
2 * GraphLCD plugin for the Video Disk Recorder |
|
3 * |
|
4 * tuxbox.c - tuxbox logo class |
|
5 * |
|
6 * (c) 2004 Andreas Brachold <vdr04 AT deltab de> |
|
7 **/ |
|
8 |
|
9 /*************************************************************************** |
|
10 * * |
|
11 * This program is free software; you can redistribute it and/or modify * |
|
12 * it under the terms of the GNU General Public License as published by * |
|
13 * the Free Software Foundation; either version 2 of the License, or * |
|
14 * (at your option) any later version. * |
|
15 * * |
|
16 * This program is distributed in the hope that it will be useful, * |
|
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
|
19 * GNU General Public License for more details. * |
|
20 * * |
|
21 * You should have received a copy of the GNU General Public License * |
|
22 * along with this program; * |
|
23 * if not, write to the Free Software Foundation, Inc., * |
|
24 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * |
|
25 * * |
|
26 ***************************************************************************/ |
|
27 |
|
28 #include <stdio.h> |
|
29 #include <string.h> |
|
30 #include <netinet/in.h> |
|
31 |
|
32 #include <string> |
|
33 |
|
34 #include <glcdgraphics/bitmap.h> |
|
35 #include <glcdgraphics/image.h> |
|
36 |
|
37 #include "tuxbox.h" |
|
38 |
|
39 #pragma pack(1) |
|
40 struct ani_header { |
|
41 unsigned char magic[4]; // = "LCDA" |
|
42 unsigned short format; // Format |
|
43 unsigned short width; // Breite |
|
44 unsigned short height; // Höhe |
|
45 unsigned short count; // Anzahl Einzelbilder |
|
46 unsigned long delay; // µs zwischen Einzelbildern |
|
47 }; |
|
48 #pragma pack() |
|
49 |
|
50 cTuxBoxFile::cTuxBoxFile() |
|
51 { |
|
52 } |
|
53 |
|
54 cTuxBoxFile::~cTuxBoxFile() |
|
55 { |
|
56 } |
|
57 |
|
58 bool cTuxBoxFile::Load(GLCD::cImage & image, const std::string & fileName) |
|
59 { |
|
60 bool ret = false; |
|
61 FILE * fIN; |
|
62 long fileLen; |
|
63 struct ani_header header; |
|
64 bool bInvert = false; |
|
65 |
|
66 fIN = fopen(fileName.c_str(), "rb"); |
|
67 if (fIN) |
|
68 { |
|
69 // get len of file |
|
70 if (fseek(fIN, 0, SEEK_END)) |
|
71 { |
|
72 fclose(fIN); |
|
73 return false; |
|
74 } |
|
75 fileLen = ftell(fIN); |
|
76 |
|
77 // rewind and get Header |
|
78 if (fseek(fIN, 0, SEEK_SET)) |
|
79 { |
|
80 fclose(fIN); |
|
81 return false; |
|
82 } |
|
83 |
|
84 // Read header |
|
85 if (fread(&header, sizeof(header), 1, fIN) != 1) |
|
86 { |
|
87 fclose(fIN); |
|
88 return false; |
|
89 } |
|
90 |
|
91 image.Clear(); |
|
92 image.SetWidth(ntohs(header.width)); |
|
93 image.SetHeight(ntohs(header.height)); |
|
94 image.SetDelay(ntohl(header.delay) / 1000); |
|
95 |
|
96 // check Header |
|
97 if (strncmp((const char*)header.magic, "LCDA", sizeof(header.magic)) || |
|
98 !image.Width() || !image.Height() || ntohs(header.format) != 0) |
|
99 { |
|
100 fprintf(stderr, "ERROR: load %s failed, wrong header.\n", fileName.c_str()); |
|
101 fclose(fIN); |
|
102 return false; |
|
103 } |
|
104 |
|
105 //fprintf(stderr,"%d %dx%d (%d %d) %d\n",ntohs(header.count),image.Width(),image.Height(),fileLen, ( (ntohs(header.count) * (image.Width() * ((image.Height() + 7) / 8))) + sizeof(header)),lhdr.delay); |
|
106 |
|
107 // check file length |
|
108 if (!ntohs(header.count) |
|
109 || (fileLen != (long) ( (ntohs(header.count) * (image.Width() * ((image.Height() + 7) / 8))) + sizeof(header)))) |
|
110 { |
|
111 fprintf(stderr, "ERROR: load %s failed, wrong size.\n", fileName.c_str()); |
|
112 fclose(fIN); |
|
113 return false; |
|
114 } |
|
115 // Set minimal limit for next image |
|
116 if (image.Delay() < 10) |
|
117 image.SetDelay(10); |
|
118 for (unsigned int n=0;n<ntohs(header.count);++n) |
|
119 { |
|
120 ret = false; |
|
121 unsigned int nBmpSize = image.Height() * ((image.Width() + 7) / 8); |
|
122 unsigned char *bitmap = new unsigned char[nBmpSize]; |
|
123 if (!bitmap) |
|
124 { |
|
125 fprintf(stderr, "ERROR: malloc failed."); |
|
126 break; |
|
127 } |
|
128 unsigned int nAniSize = image.Width() * ((image.Height() + 7) / 8); |
|
129 unsigned char *pAni = new unsigned char[nAniSize]; |
|
130 if (!pAni) |
|
131 { |
|
132 delete[] bitmap; |
|
133 fprintf(stderr, "ERROR: malloc failed."); |
|
134 break; |
|
135 } |
|
136 |
|
137 if (1 != fread(pAni, nAniSize, 1, fIN)) |
|
138 { |
|
139 fprintf(stderr,"ERROR: Cannot read filedata: %s\n", fileName.c_str()); |
|
140 delete[] bitmap; |
|
141 delete[] pAni; |
|
142 break; |
|
143 } |
|
144 |
|
145 vert2horz(pAni,bitmap, image.Width(), image.Height()); |
|
146 delete[] pAni; |
|
147 |
|
148 if (bInvert) |
|
149 for (unsigned int i=0;i<nBmpSize;++i) |
|
150 bitmap[i] ^= 0xFF; |
|
151 |
|
152 image.AddBitmap(new GLCD::cBitmap(image.Width(), image.Height(), bitmap)); |
|
153 ret = true; |
|
154 } |
|
155 fclose(fIN); |
|
156 if (!ret) |
|
157 image.Clear(); |
|
158 } |
|
159 return ret; |
|
160 } |
|
161 |
|
162 |
|
163 bool cTuxBoxFile::Save(GLCD::cImage & image, const std::string & fileName) |
|
164 { |
|
165 FILE * fOut; |
|
166 struct ani_header header; |
|
167 bool bRet = false; |
|
168 |
|
169 if (image.Count() > 0 |
|
170 && image.Width() |
|
171 && image.Height()) |
|
172 { |
|
173 memcpy(header.magic, "LCDA", 4); |
|
174 header.format = htons(0); |
|
175 header.width = htons(image.Width()); |
|
176 header.height = htons(image.Height()); |
|
177 header.count = htons(image.Count()); |
|
178 header.delay = htonl(image.Delay() * 1000); |
|
179 |
|
180 |
|
181 if (image.Width() != 120 || image.Height() != 64) |
|
182 { |
|
183 fprintf(stderr,"WARNING: Maybe wrong image dimension (for all I know is 120x64 wanted) %s\n", fileName.c_str()); |
|
184 } |
|
185 |
|
186 fOut = fopen(fileName.c_str(), "wb"); |
|
187 if (!fOut) { |
|
188 fprintf(stderr,"ERROR: Cannot create file: %s\n", fileName.c_str()); |
|
189 return false; |
|
190 } |
|
191 |
|
192 if (1 != fwrite(&header, sizeof(header), 1, fOut)) |
|
193 { |
|
194 fprintf(stderr,"ERROR: Cannot write fileheader: %s\n", fileName.c_str()); |
|
195 fclose(fOut); |
|
196 return false; |
|
197 } |
|
198 |
|
199 for (unsigned int n = 0; n < image.Count(); n++) |
|
200 { |
|
201 bRet = false; |
|
202 unsigned int nAniSize = image.Width() * ((image.Height() + 7) / 8); |
|
203 unsigned char *pAni = new unsigned char[nAniSize]; |
|
204 if (!pAni) |
|
205 { |
|
206 fprintf(stderr, "ERROR: malloc failed."); |
|
207 break; |
|
208 } |
|
209 horz2vert(image.GetBitmap(n)->Data(), pAni, image.Width(), image.Height()); |
|
210 |
|
211 if (1 != fwrite(pAni, nAniSize, 1, fOut)) |
|
212 { |
|
213 delete [] pAni; |
|
214 fprintf(stderr,"ERROR: Cannot write filedata: %s\n", fileName.c_str()); |
|
215 break; |
|
216 } |
|
217 delete [] pAni; |
|
218 bRet = true; |
|
219 } |
|
220 |
|
221 fclose(fOut); |
|
222 } |
|
223 return bRet; |
|
224 } |
|
225 |
|
226 /** Translate memory alignment from vertical to horizontal |
|
227 rotate from {Byte} to {Byte} |
|
228 {o}[o][o][o][o][o][o][o] => { oooooooo } |
|
229 {o}[o][o][o][o][o][o][o] => [ oooooooo ] |
|
230 {o}[o][o][o][o][o][o][o] => [ oooooooo ] |
|
231 {o}[o][o][o][o][o][o][o] => [ oooooooo ] |
|
232 {o}[o][o][o][o][o][o][o] => [ oooooooo ] |
|
233 {o}[o][o][o][o][o][o][o] => [ oooooooo ] |
|
234 {o}[o][o][o][o][o][o][o] => [ oooooooo ] |
|
235 {o}[o][o][o][o][o][o][o] => [ oooooooo ]*/ |
|
236 void cTuxBoxFile::vert2horz(const unsigned char* source, unsigned char* dest, int width, int height) { |
|
237 int x, y, off; |
|
238 memset(dest,0,height*((width+7)/8)); |
|
239 |
|
240 for (y=0; y<height; ++y) |
|
241 { |
|
242 for (x=0; x<width; ++x) |
|
243 { |
|
244 off = x + ((y/8) * width); |
|
245 if (source[off] & (0x1 << (y % 8))) |
|
246 { |
|
247 off = (x / 8) + (y * ((width+7)/8)); |
|
248 dest[off] |= (unsigned char)(0x80 >> (x % 8)); |
|
249 } |
|
250 } |
|
251 } |
|
252 } |
|
253 |
|
254 /** Translate memory alignment from horizontal to vertical (rotate byte) |
|
255 rotate from {Byte} to {Byte} |
|
256 { oooooooo } => {o}[o][o][o][o][o][o][o] |
|
257 [ oooooooo ] => {o}[o][o][o][o][o][o][o] |
|
258 [ oooooooo ] => {o}[o][o][o][o][o][o][o] |
|
259 [ oooooooo ] => {o}[o][o][o][o][o][o][o] |
|
260 [ oooooooo ] => {o}[o][o][o][o][o][o][o] |
|
261 [ oooooooo ] => {o}[o][o][o][o][o][o][o] |
|
262 [ oooooooo ] => {o}[o][o][o][o][o][o][o] |
|
263 [ oooooooo ] => {o}[o][o][o][o][o][o][o]*/ |
|
264 void cTuxBoxFile::horz2vert(const unsigned char* source, unsigned char* dest, int width, int height) { |
|
265 int x, y, off; |
|
266 memset(dest,0,width*((height+7)/8)); |
|
267 |
|
268 for (y=0; y<height; ++y) |
|
269 { |
|
270 for (x=0; x<width; ++x) |
|
271 { |
|
272 off = (x / 8) + ((y) * ((width+7)/8)); |
|
273 if (source[off] & (0x80 >> (x % 8))) |
|
274 { |
|
275 off = x + ((y/8) * width); |
|
276 dest[off] |= (unsigned char)(0x1 << (y % 8)); |
|
277 } |
|
278 } |
|
279 } |
|
280 } |