1 //------------------------------------------------------------------------------
2 // emIlbmImageFileModel.cpp
3 //
4 // Copyright (C) 2004-2009,2014,2018-2019 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #include <emIlbm/emIlbmImageFileModel.h>
22
23
Acquire(emContext & context,const emString & name,bool common)24 emRef<emIlbmImageFileModel> emIlbmImageFileModel::Acquire(
25 emContext & context, const emString & name, bool common
26 )
27 {
28 EM_IMPL_ACQUIRE(emIlbmImageFileModel,context,name,common)
29 }
30
31
emIlbmImageFileModel(emContext & context,const emString & name)32 emIlbmImageFileModel::emIlbmImageFileModel(
33 emContext & context, const emString & name
34 )
35 : emImageFileModel(context,name)
36 {
37 L=NULL;
38 }
39
40
~emIlbmImageFileModel()41 emIlbmImageFileModel::~emIlbmImageFileModel()
42 {
43 emIlbmImageFileModel::QuitLoading();
44 emIlbmImageFileModel::QuitSaving();
45 }
46
47
TryStartLoading()48 void emIlbmImageFileModel::TryStartLoading()
49 {
50 int name;
51
52 L=new LoadingState;
53 L->HeaderFound=false;
54 L->Width=0;
55 L->Height=0;
56 L->Depth=0;
57 L->Compress=0;
58 L->NextY=0;
59 L->File=NULL;
60 L->Palette=NULL;
61 L->RowBuf=NULL;
62 L->BodyPos=0;
63
64 L->File=fopen(GetFilePath(),"rb");
65 if (!L->File) throw emException("%s",emGetErrorText(errno).Get());
66
67 Read32();
68 Read32();
69 name=Read32();
70
71 if (ferror(L->File)) throw emException("%s",emGetErrorText(errno).Get());
72
73 if (feof(L->File) || name!=0x494C424D/*ILBM*/) {
74 throw emException("ILBM format error");
75 }
76 }
77
78
TryContinueLoading()79 bool emIlbmImageFileModel::TryContinueLoading()
80 {
81 unsigned char * map, * row, * bm;
82 long size;
83 int name,x,y,bb,b,d,pbw,c,cb;
84
85 if (!L->BodyPos || !L->Palette || !L->HeaderFound) {
86 name=Read32();
87 size=(emUInt32)Read32();
88 if (ferror(L->File)) goto ErrFile;
89 if (feof(L->File)) goto ErrFormat;
90 if (name==0x424D4844/*BMHD*/) {
91 if (size<11) goto ErrFormat;
92 L->Width=Read16();
93 L->Height=Read16();
94 Read32();
95 L->Depth=Read8();
96 Read8();
97 L->Compress=Read8();
98 fseek(L->File,((size+1)&~1)-11,SEEK_CUR);
99 if (ferror(L->File)) goto ErrFile;
100 if (L->Depth>8 || L->Compress>1 ||
101 L->Width<=0 || L->Height<=0) goto ErrFormat;
102 L->HeaderFound=true;
103 }
104 else if (name==0x434D4150/*CMAP*/) {
105 if (!L->HeaderFound || L->Palette || size<(3<<L->Depth)) goto ErrFormat;
106 L->Palette=new unsigned char[3<<L->Depth];
107 if (fread(L->Palette,1,3<<L->Depth,L->File)!=(size_t)(3<<L->Depth)) goto ErrFormat;
108 fseek(L->File,((size+1)&~1)-(3<<L->Depth),SEEK_CUR);
109 if (ferror(L->File)) goto ErrFile;
110 }
111 else if (name==0x424F4459/*BODY*/) {
112 if (!L->HeaderFound || L->BodyPos) goto ErrFormat;
113 L->BodyPos=ftell(L->File);
114 fseek(L->File,(size+1)&~1,SEEK_CUR);
115 if (ferror(L->File)) goto ErrFile;
116 }
117 else {
118 fseek(L->File,(size+1)&~1,SEEK_CUR);
119 if (ferror(L->File)) goto ErrFile;
120 }
121 return false;
122 }
123
124 if (!L->RowBuf) {
125 L->RowBuf=new unsigned char[L->Width+15];
126 fseek(L->File,L->BodyPos,SEEK_SET);
127 Image.Setup(L->Width,L->Height,3);
128 return false;
129 }
130
131 if (L->NextY<L->Height) {
132 y=L->NextY++;
133 map=Image.GetWritableMap()+y*(size_t)Image.GetWidth()*Image.GetChannelCount();
134 pbw=((L->Width+15)&0xfff0)>>3;
135 row=L->RowBuf;
136 memset(row,0,L->Width);
137 cb=1;
138 for(d=0; d<L->Depth; d++) {
139 bm=row;
140 x=0;
141 if (L->Compress==0) {
142 while (x<pbw) {
143 b=Read8();
144 for(bb=128; bb!=0; bb>>=1) {
145 if ( (b & bb) !=0) *bm|=(unsigned char)cb;
146 bm++;
147 }
148 x++;
149 }
150 }
151 else { // Compress==1
152 while(x<pbw) {
153 c=Read8();
154 if(c<128) {
155 c=c+x; if (c>=pbw) c=pbw-1;
156 while (x<=c) {
157 b=Read8();
158 for(bb=128; bb!=0; bb>>=1) {
159 if ( (b & bb) !=0) *bm|=(unsigned char)cb;
160 bm++;
161 }
162 x++;
163 }
164 }
165 else if (c!=128) {
166 c=256-c+x; if (c>=pbw) c=pbw-1;
167 b=Read8();
168 while (x<=c) {
169 for(bb=128; bb!=0; bb>>=1) {
170 if ( (b & bb) !=0) *bm|=(unsigned char)cb;
171 bm++;
172 }
173 x++;
174 }
175 }
176 }
177 }
178 cb<<=1;
179 }
180 for (x=0; x<L->Width; x++) {
181 map[0]=L->Palette[row[x]*3+0];
182 map[1]=L->Palette[row[x]*3+1];
183 map[2]=L->Palette[row[x]*3+2];
184 map+=3;
185 }
186 return false;
187 }
188
189 FileFormatInfo=emString::Format(
190 "ILBM %d-bit %s",
191 L->Depth,
192 L->Compress ? "RLE-compressed" : "uncompressed"
193 );
194
195 Signal(ChangeSignal);
196
197 return true;
198
199 ErrFile:
200 throw emException("%s",emGetErrorText(errno).Get());
201 ErrFormat:
202 throw emException("ILBM format error");
203 }
204
205
QuitLoading()206 void emIlbmImageFileModel::QuitLoading()
207 {
208 if (L) {
209 if (L->File) fclose(L->File);
210 if (L->Palette) delete [] L->Palette;
211 if (L->RowBuf) delete [] L->RowBuf;
212 delete L;
213 L=NULL;
214 }
215 }
216
217
TryStartSaving()218 void emIlbmImageFileModel::TryStartSaving()
219 {
220 throw emException("emIlbmImageFileModel: Saving not implemented.");
221 }
222
223
TryContinueSaving()224 bool emIlbmImageFileModel::TryContinueSaving()
225 {
226 return true;
227 }
228
229
QuitSaving()230 void emIlbmImageFileModel::QuitSaving()
231 {
232 }
233
234
CalcMemoryNeed()235 emUInt64 emIlbmImageFileModel::CalcMemoryNeed()
236 {
237 if (L) {
238 return ((emUInt64)L->Width)*(L->Height*3+1);
239 }
240 else {
241 return ((emUInt64)Image.GetWidth())*
242 Image.GetHeight()*
243 Image.GetChannelCount();
244 }
245 }
246
247
CalcFileProgress()248 double emIlbmImageFileModel::CalcFileProgress()
249 {
250 double progress;
251
252 progress=0.0;
253 if (L) {
254 if (L->HeaderFound) progress+=5.0;
255 if (L->Palette) progress+=10.0;
256 if (L->Height>0) {
257 progress+=85.0*L->NextY/L->Height;
258 }
259 }
260 return progress;
261 }
262
263
Read8()264 int emIlbmImageFileModel::Read8()
265 {
266 return (unsigned char)fgetc(L->File);
267 }
268
269
Read16()270 int emIlbmImageFileModel::Read16()
271 {
272 int i;
273
274 i=Read8()<<8;
275 i|=Read8();
276 return i;
277 }
278
279
Read32()280 int emIlbmImageFileModel::Read32()
281 {
282 int i;
283
284 i=Read16()<<16;
285 i|=Read16();
286 return i;
287 }
288