1 //------------------------------------------------------------------------------
2 // emPnmImageFileModel.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 <emPnm/emPnmImageFileModel.h>
22
23
Acquire(emContext & context,const emString & name,bool common)24 emRef<emPnmImageFileModel> emPnmImageFileModel::Acquire(
25 emContext & context, const emString & name, bool common
26 )
27 {
28 EM_IMPL_ACQUIRE(emPnmImageFileModel,context,name,common)
29 }
30
31
emPnmImageFileModel(emContext & context,const emString & name)32 emPnmImageFileModel::emPnmImageFileModel(
33 emContext & context, const emString & name
34 )
35 : emImageFileModel(context,name)
36 {
37 L=NULL;
38 }
39
40
~emPnmImageFileModel()41 emPnmImageFileModel::~emPnmImageFileModel()
42 {
43 emPnmImageFileModel::QuitLoading();
44 emPnmImageFileModel::QuitSaving();
45 }
46
47
TryStartLoading()48 void emPnmImageFileModel::TryStartLoading()
49 {
50 errno=0;
51
52 L=new LoadingState;
53 memset(L,0,sizeof(LoadingState));
54
55 L->File=fopen(GetFilePath(),"rb");
56 if (!L->File) goto Err;
57
58 if (Read8()!='P') goto Err;
59 L->Format=ReadDecimal();
60 if (L->Format<1 || L->Format>6) goto Err;
61
62 L->Width=ReadDecimal();
63 L->Height=ReadDecimal();
64 if (L->Width<1 || L->Height<1) goto Err;
65 if (L->Width>0x7fffff || L->Height>0x7fffff) goto Err;
66
67 if (L->Format==2 || L->Format==3 || L->Format==5 || L->Format==6) {
68 L->MaxVal=ReadDecimal();
69 if (L->MaxVal<1 || L->MaxVal>65535) goto Err;
70 }
71
72 return;
73
74 Err:
75 if (errno) throw emException("%s",emGetErrorText(errno).Get());
76 else throw emException("PNM format error");
77 }
78
79
TryContinueLoading()80 bool emPnmImageFileModel::TryContinueLoading()
81 {
82 unsigned char * map, * mapEnd;
83 int i,n,v;
84
85 errno=0;
86
87 if (L->Format==3 || L->Format==6) n=3; else n=1;
88
89 if (!L->ImagePrepared) {
90 Image.Setup(L->Width,L->Height,n);
91 switch (L->Format) {
92 case 1: FileFormatInfo="PNM P1 (PBM ASCII)"; break;
93 case 2: FileFormatInfo="PNM P2 (PGM ASCII)"; break;
94 case 3: FileFormatInfo="PNM P3 (PPM ASCII)"; break;
95 case 4: FileFormatInfo="PNM P4 (PBM RAW)"; break;
96 case 5: FileFormatInfo="PNM P5 (PGM RAW)"; break;
97 case 6: FileFormatInfo="PNM P6 (PPM RAW)"; break;
98 }
99 Signal(ChangeSignal);
100 L->ImagePrepared=true;
101 return false;
102 }
103
104 if (L->NextY>=L->Height) {
105 return true;
106 }
107
108 map=Image.GetWritableMap()+L->NextY*(size_t)L->Width*n;
109 mapEnd=map+n*L->Width;
110
111 if (L->Format==1) {
112 for (; map<mapEnd; map++) {
113 v=ReadDigit(true);
114 if (v<0 || v>1) goto Err;
115 map[0]=(unsigned char)(v?0:255);
116 }
117 }
118 else if (L->Format==4) {
119 for (i=0, v=0; map<mapEnd; map++, i=(i+1)&7) {
120 if (i==0) {
121 v=Read8();
122 if (v<0) goto Err;
123 }
124 map[0]=(unsigned char)((v&(128>>i))?0:255);
125 }
126 }
127 else if (L->Format==2 || L->Format==5) {
128 for (; map<mapEnd; map++) {
129 v=ReadVal();
130 if (v<0) goto Err;
131 map[0]=(unsigned char)v;
132 }
133 }
134 else if (L->Format==3 || L->Format==6) {
135 for (; map<mapEnd; map+=3) {
136 v=ReadVal();
137 if (v<0) goto Err;
138 map[0]=(unsigned char)v;
139 v=ReadVal();
140 if (v<0) goto Err;
141 map[1]=(unsigned char)v;
142 v=ReadVal();
143 if (v<0) goto Err;
144 map[2]=(unsigned char)v;
145 }
146 }
147
148 Signal(ChangeSignal);
149
150 if (ferror(L->File)) goto Err;
151
152 L->NextY++;
153 if (L->NextY>=L->Height) {
154 return true;
155 }
156
157 return false;
158
159 Err:
160 if (errno) throw emException("%s",emGetErrorText(errno).Get());
161 else throw emException("PNM format error");
162 }
163
164
QuitLoading()165 void emPnmImageFileModel::QuitLoading()
166 {
167 if (L) {
168 if (L->File) fclose(L->File);
169 delete L;
170 L=NULL;
171 }
172 }
173
174
TryStartSaving()175 void emPnmImageFileModel::TryStartSaving()
176 {
177 throw emException("emPnmImageFileModel: Saving not implemented.");
178 }
179
180
TryContinueSaving()181 bool emPnmImageFileModel::TryContinueSaving()
182 {
183 return true;
184 }
185
186
QuitSaving()187 void emPnmImageFileModel::QuitSaving()
188 {
189 }
190
191
CalcMemoryNeed()192 emUInt64 emPnmImageFileModel::CalcMemoryNeed()
193 {
194 emUInt64 m;
195
196 if (L) {
197 m=((emUInt64)L->Width)*L->Height;
198 if (L->Format==3 || L->Format==6) m*=3;
199 return m;
200 }
201 else {
202 return ((emUInt64)Image.GetWidth())*
203 Image.GetHeight()*
204 Image.GetChannelCount();
205 }
206 }
207
208
CalcFileProgress()209 double emPnmImageFileModel::CalcFileProgress()
210 {
211 if (L && L->Height>0) {
212 return 100.0*L->NextY/L->Height;
213 }
214 else {
215 return 0.0;
216 }
217 }
218
219
Read8()220 int emPnmImageFileModel::Read8()
221 {
222 return (unsigned char)fgetc(L->File);
223 }
224
225
Read16()226 int emPnmImageFileModel::Read16()
227 {
228 int i;
229
230 i=Read8()<<8;
231 i|=Read8();
232 return i;
233 }
234
235
ReadDigit(bool allowSpace)236 int emPnmImageFileModel::ReadDigit(bool allowSpace)
237 {
238 int c;
239
240 for (;;) {
241 c=fgetc(L->File);
242 if (c>='0' && c<='9') return c-'0';
243 if (c=='#') {
244 do {
245 c=fgetc(L->File);
246 if (c<0) return -1;
247 } while (c!=0x0a);
248 }
249 if (!allowSpace || c<0 || c>0x20) return -1;
250 }
251 }
252
253
ReadDecimal()254 int emPnmImageFileModel::ReadDecimal()
255 {
256 int i,j;
257
258 i=ReadDigit(true);
259 if (i>=0) {
260 for (;;) {
261 j=ReadDigit(false);
262 if (j<0) break;
263 i=i*10+j;
264 }
265 }
266 return i;
267 }
268
269
ReadVal()270 int emPnmImageFileModel::ReadVal()
271 {
272 int v;
273
274 if (L->Format<=3) v=ReadDecimal();
275 else if (L->MaxVal<=255) v=Read8();
276 else v=Read16();
277 if (v<0 || v>L->MaxVal) return -1;
278 return (v*255+L->MaxVal/2)/L->MaxVal;
279 }
280