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