|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <s32mem.h> |
|
17 #include "CFAXIO.H" |
|
18 |
|
19 #include "FAXSTPAN.H" |
|
20 #include "FAXUHUFF.H" |
|
21 #include "FAXHUFF.H" |
|
22 |
|
23 // COPIED function from pdrutil |
|
24 |
|
25 GLDEF_C void Panic (TFaxStorePanic aPanic) |
|
26 // Panic the process with ETEXT as the category. |
|
27 // |
|
28 |
|
29 { |
|
30 User::Panic (_L ("FaxStore"), aPanic); |
|
31 } |
|
32 |
|
33 // END OF COPIED |
|
34 |
|
35 //#define KFaxFileName _L("c:\\temp.fax") |
|
36 |
|
37 /********************************************************************/ |
|
38 |
|
39 #define RLE_MAKEUP(aTable,aRun) TUint8((aTable)+KRleMakeup+((aRun)>>6<<1)) |
|
40 #define RLE_RUN(aTable,aRun) TUint8((aTable)+((aRun)<<1)) |
|
41 |
|
42 #define WRITE_RLE(ptr,table,run) {if (run>63) {*ptr++=RLE_MAKEUP(table,run);run&=0x3f;} *ptr++=RLE_RUN(table,run);} |
|
43 #define READ_RLE(ptr,pos) {TInt x=*ptr++;if (x>=KRleMakeup) {pos+=(x&KRleMakeupMask)<<5;x=*ptr++;}pos+=x>>1;} |
|
44 |
|
45 LOCAL_C TUint8* RleEncoding(const TUint32 * aScan, TUint8* aRleEncoding) |
|
46 // |
|
47 // RLE encode a 1728 pixel scanline into the buffer, and return the end-of-rle data |
|
48 // The edge detection algorithm is almost optimal for ARM |
|
49 // |
|
50 { |
|
51 // the edge detection looks at multiple pixels at a time |
|
52 // tests show that for ARM, testing 8 is only 1-2% faster than testing 6 |
|
53 // testing only 6 makes for a smaller lookup table |
|
54 |
|
55 // The FirstBit table is (5 - bitpos) of the least significant |
|
56 // bit that is set in the array index value |
|
57 |
|
58 const TInt KTestBitCount=6; |
|
59 const TInt KTestBitMask=(1u<<KTestBitCount)-1; |
|
60 const TInt KRunBias=KTestBitCount-2; |
|
61 static const TUint8 KFirstBit[64]= |
|
62 { |
|
63 0,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5,1,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5, |
|
64 0,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5,1,5,4,5,3,5,4,5,2,5,4,5,3,5,4,5 |
|
65 }; |
|
66 |
|
67 const TUint32 *end = aScan + (KFaxPixelsPerScanLine >> 5); |
|
68 TUint32 color = ~0u; // white at start |
|
69 TInt table=KRleWhite; |
|
70 TInt run = KRunBias; // initialise run length |
|
71 const TUint8* lookup=KFirstBit; // force the table to be in a register |
|
72 |
|
73 nextword: |
|
74 while (aScan < end) |
|
75 { |
|
76 run += 32; |
|
77 TUint32 pixels = *aScan++ ^ color; |
|
78 if (pixels) // do no work if there is no edge |
|
79 { |
|
80 TInt bit = 31 + KTestBitCount; |
|
81 for (;;) |
|
82 { |
|
83 TUint pix; |
|
84 do |
|
85 { |
|
86 if ((bit-=KTestBitCount) < 0) |
|
87 goto nextword; // finished processing the word |
|
88 // now examine the next 6 pixels |
|
89 // break out if we have found an edge |
|
90 pix=(pixels>>(31-bit))&KTestBitMask; |
|
91 } while (pix==0); |
|
92 // there is an edge, use the table to discover which pixel |
|
93 bit+=lookup[pix]; |
|
94 // store the run-length |
|
95 run-=bit; |
|
96 WRITE_RLE(aRleEncoding,table,run); |
|
97 // flip color and look for the next edge |
|
98 color = ~color; |
|
99 table=KRleWhite-table; |
|
100 pixels=~pixels; |
|
101 run = bit; |
|
102 } |
|
103 } |
|
104 } |
|
105 // store the final run |
|
106 run-=KRunBias; |
|
107 WRITE_RLE(aRleEncoding,table,run); |
|
108 return aRleEncoding; |
|
109 } |
|
110 |
|
111 LOCAL_C TUint8* RleEncoding (const TUint32 *aScanline,TInt aLength,TUint8* aRleEncoding) |
|
112 // |
|
113 // Justify the scanline into a full size buffer before encoding |
|
114 // |
|
115 { |
|
116 __ASSERT_DEBUG(aLength < (KFaxPixelsPerScanLine >> 3),User::Invariant()); |
|
117 // |
|
118 TUint32 justified[KFaxPixelsPerScanLine/32]; |
|
119 // |
|
120 TInt margin = ((KFaxPixelsPerScanLine >> 3) - aLength) / 2; |
|
121 Mem::Fill (justified, sizeof(justified), 0xff); // white fill |
|
122 Mem::Copy ((TUint8*)justified + margin, aScanline, aLength); |
|
123 return RleEncoding(justified,aRleEncoding); |
|
124 } |
|
125 |
|
126 LOCAL_C TUint8* RleEncoding (const TDesC8& aScanLine, TUint8* aRleEncoding) |
|
127 // |
|
128 // Build the RLE encoding for aScanline, handling wrong-sized scanlines |
|
129 // |
|
130 { |
|
131 TInt len = aScanLine.Length (); |
|
132 const TUint32 *scan = (const TUint32 *) aScanLine.Ptr (); |
|
133 __ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxEncodeScanlineAlignment)); |
|
134 if (len >= (KFaxPixelsPerScanLine >> 3)) |
|
135 return RleEncoding(scan + ((len - (KFaxPixelsPerScanLine >> 3)) >> 3),aRleEncoding); // margin in words |
|
136 else |
|
137 return RleEncoding(scan,len,aRleEncoding); |
|
138 } |
|
139 |
|
140 LOCAL_C void EncodeHuffman(TDes8 & anEncodedScanLine,TInt aTagCode,const TUint8* aRleEncoding,const TUint8* aRleEnd) |
|
141 // |
|
142 // Starting with the tag code, encode all codes in the rle data using the single huffman table |
|
143 // |
|
144 { |
|
145 TUint8 *t4 = (TUint8 *) anEncodedScanLine.Ptr (); |
|
146 TUint8 *const e4 = t4; |
|
147 // start with tag code |
|
148 TCodeDef huff=KCodes[aTagCode]; |
|
149 TUint code=HUFFBITS(huff); |
|
150 TInt bits=HUFFLEN(huff)-16; |
|
151 while (aRleEncoding<aRleEnd) |
|
152 { |
|
153 __ASSERT_DEBUG (bits < 0, User::Invariant ()); |
|
154 TUint8 c=*aRleEncoding++; |
|
155 TCodeDef huff=KCodes[c]; |
|
156 code|=HUFFBITS(huff)>>(bits+16); |
|
157 bits+=HUFFLEN(huff); |
|
158 if (bits<0) |
|
159 continue; |
|
160 *t4++=TUint8(code>>24); |
|
161 *t4++=TUint8(code>>16); |
|
162 code<<=16; |
|
163 bits-=16; |
|
164 } |
|
165 if (bits>-16) |
|
166 { // flush out the remaining bits |
|
167 *t4++=TUint8(code>>24); |
|
168 if (bits>-8) |
|
169 *t4++=TUint8(code>>16); |
|
170 } |
|
171 anEncodedScanLine.SetLength (t4 - e4); |
|
172 } |
|
173 |
|
174 /********************************************************************/ |
|
175 |
|
176 inline CFaxT4::CFaxT4 () |
|
177 {PageInitialize(EFaxNormal,EModifiedHuffman);} |
|
178 |
|
179 EXPORT_C CFaxT4 *CFaxT4::NewLC () |
|
180 /** Constructs a CFaxT4 object, which provides utility functions to encode and |
|
181 decode fax scan lines. |
|
182 |
|
183 As is usual in Symbian OS, the only difference between this function and NewL() |
|
184 is that this variant pushes the object to the cleanup stack. |
|
185 |
|
186 The new object is constructed with the default compression and resolution: |
|
187 EModifiedHuffman and EFaxNormal respectively. |
|
188 |
|
189 @leave KErrNoMemory There is insufficient memory to perform the operation. |
|
190 @return A pointer to the newly created object. |
|
191 @capability None |
|
192 */ |
|
193 { |
|
194 CFaxT4 *self = NewL (); |
|
195 CleanupStack::PushL (self); |
|
196 return self; |
|
197 } |
|
198 |
|
199 EXPORT_C CFaxT4 *CFaxT4::NewL () |
|
200 /** Constructs a CFaxT4 object, which provides utility functions to encode and |
|
201 decode fax scan lines. |
|
202 |
|
203 The function is exactly the same as NewLC() except that the new object is |
|
204 popped from the cleanup stack. |
|
205 |
|
206 The new object is constructed with the default compression and resolution: |
|
207 EModifiedHuffman and EFaxNormal respectively. |
|
208 |
|
209 @leave KErrNoMemory There is insufficient memory to perform the operation. |
|
210 @return A pointer to the newly created object. |
|
211 @capability None |
|
212 */ |
|
213 { |
|
214 return new (ELeave) CFaxT4; |
|
215 } |
|
216 |
|
217 EXPORT_C void CFaxT4::PageInitialize (TFaxResolution aResolution, TFaxCompression aCompression, TInt aFlag2) |
|
218 /** |
|
219 Initialize fax page, set page parameters. |
|
220 |
|
221 @param aResolution defines fax resolution |
|
222 @param aCompression defines fax compression |
|
223 @param aFlag2 reserved flag. |
|
224 @capability None |
|
225 */ |
|
226 { |
|
227 __ASSERT_ALWAYS (((aCompression == EModifiedHuffman) || (aCompression == EModifiedRead)), Panic (EFaxUnsupportedCompression)); |
|
228 iCompression = aCompression; |
|
229 iResolution = aResolution; |
|
230 iReservedFlag2 = aFlag2; |
|
231 iK = iResolution == EFaxFine ? 4 : 2; |
|
232 iLineCount = 1; |
|
233 // an all-white reference line |
|
234 iRef[0]=RLE_MAKEUP(KRleWhite,KFaxBytesPerScanLine); |
|
235 iRef[1]=RLE_RUN(KRleWhite,0); |
|
236 iEndRef=iRef+2; |
|
237 } |
|
238 |
|
239 EXPORT_C void CFaxT4::EncodeScanLine (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine) |
|
240 /** Encodes a scan line using either one dimensional Modified Huffman (MH) or two |
|
241 dimensional Modified Read (MR) encoding. |
|
242 |
|
243 The type of encoding used depends on the compression type specified when the |
|
244 object was initialised - using PageInitialize(). If the object was not initialised, |
|
245 then the default compression is MH. |
|
246 |
|
247 @param aScanLine The raw scan line to be encoded. |
|
248 @param anEncodedScanLine On return, contains the encoded scan line. |
|
249 @capability None |
|
250 */ |
|
251 { |
|
252 if (iCompression == EModifiedRead) |
|
253 EncodeScanLine2D (aScanLine, anEncodedScanLine); |
|
254 else |
|
255 EncodeScanLine1D(aScanLine,anEncodedScanLine); |
|
256 } |
|
257 |
|
258 EXPORT_C void CFaxT4::EncodeScanLine1D (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine) |
|
259 /** Encodes a scan line using Modified Huffman compression. |
|
260 |
|
261 @param aScanLine The scan line to be encoded. |
|
262 @param anEncodedScanLine On return, contains the MH encoded scan line. |
|
263 @capability None |
|
264 */ |
|
265 { |
|
266 iEndRef=RleEncoding(aScanLine,iRef); |
|
267 EncodeHuffman(anEncodedScanLine,iCompression == EModifiedHuffman ? KRleStd1D : KRleTag1D,iRef,iEndRef); |
|
268 } |
|
269 |
|
270 EXPORT_C void CFaxT4::EncodeScanLine2D (const TDesC8 & aScanLine, TDes8 & anEncodedScanLine) |
|
271 /** Encodes a scan line using Modified Read compression. |
|
272 |
|
273 @param aScanLine The scan line to be encoded. |
|
274 @param anEncodedScanLine On return, contains the MR encoded scan line. |
|
275 @capability None |
|
276 */ |
|
277 { |
|
278 // initialize our own scan line |
|
279 TInt lc=iLineCount-1; |
|
280 if (lc==0) |
|
281 { // 1D reference line |
|
282 iLineCount=iK; |
|
283 EncodeScanLine1D(aScanLine,anEncodedScanLine); |
|
284 } |
|
285 else |
|
286 { // 2D line |
|
287 iLineCount=lc; |
|
288 DoEncodeScanLine2D(aScanLine,anEncodedScanLine); |
|
289 } |
|
290 } |
|
291 |
|
292 void CFaxT4::DoEncodeScanLine2D (const TDesC8 & aScanLine, TDes8 & aEncodedScanLine) |
|
293 { |
|
294 TUint8 rlebuf[KFaxPixelsPerScanLine*3/2 + 16]; // for output + reference line |
|
295 |
|
296 // the buffer is big enough that the 2d coding output into the buffer will not |
|
297 // catch the reference coding before it is used |
|
298 |
|
299 // copy the reference line into the end of the stack buffer |
|
300 |
|
301 TInt len=iEndRef-iRef; |
|
302 TUint8* ref=rlebuf+sizeof(rlebuf)-len; |
|
303 Mem::Copy(ref,iRef,len); |
|
304 |
|
305 // Do the standard RLE encoding of the current line |
|
306 iEndRef=RleEncoding(aScanLine,iRef); |
|
307 const TUint8* cur=iRef; |
|
308 |
|
309 TUint8* rle=rlebuf; |
|
310 TInt a0=-1; // previous edge on current line |
|
311 TInt a1=0; // current edge on current line |
|
312 TInt b0; // previous edge on reference line |
|
313 TInt b1=0; // current edge on reference line |
|
314 TInt b2=0; // look-ahead edge on reference line |
|
315 TInt color=KRleWhite; // color at a0 (initially white) |
|
316 |
|
317 // the reference color is not tracked. Instead the number of reference edges |
|
318 // traversed is monitored (modulo 2) to ensure that edge b1 is of the same |
|
319 // color to a1 at "gotB2" |
|
320 |
|
321 READ_RLE(cur,a1); // find the first edge |
|
322 |
|
323 for (;;) |
|
324 { |
|
325 do |
|
326 { // find the new current and next edges on reference line |
|
327 b0=b1; |
|
328 b1=b2; |
|
329 if (b1==KFaxPixelsPerScanLine) |
|
330 break; // end of line |
|
331 READ_RLE(ref,b2); |
|
332 refMove1: // find just the look-ahead edge on the reference line |
|
333 b0=b1; |
|
334 b1=b2; |
|
335 if (b1==KFaxPixelsPerScanLine) |
|
336 break; |
|
337 READ_RLE(ref,b2); |
|
338 } while(b1<=a0); // ensure that we have the right reference edge |
|
339 |
|
340 gotB2: if (b2 < a1) |
|
341 { // pass mode detected |
|
342 *rle++=KRlePassMode; |
|
343 a0=b2; // move along by 2 edges |
|
344 continue; |
|
345 } |
|
346 |
|
347 if (TUint(b1-a1+3)<=6u) |
|
348 { // vertical mode |
|
349 *rle++=TUint8(KRleVertMode0 + (b1 - a1)); |
|
350 if (a1==KFaxPixelsPerScanLine) |
|
351 break; // complete |
|
352 if (b0>a1) |
|
353 { |
|
354 // special case of vertical mode edge "cross-over" |
|
355 // the next edge may match an earlier reference edge than this! |
|
356 // rewind the reference line by 2 edges |
|
357 // we know that [b0,b1] is small, and so only uses 1 byte in the rle |
|
358 // we check for [b1,b2] requiring a makeup byte as well |
|
359 ref-=2; |
|
360 if (b2-b1>=64) |
|
361 --ref; |
|
362 b2=b0; |
|
363 b1=0; // no longer know b0, but this cannot happen again without traversing 2 edges |
|
364 } |
|
365 a0 = a1; // traverse a single edge |
|
366 READ_RLE(cur,a1); |
|
367 color=KRleWhite-color; |
|
368 goto refMove1; |
|
369 } |
|
370 |
|
371 // we must be in horizontal mode - write out the RLE codes for remainder |
|
372 // and copy RLE codes for next edge from current coding |
|
373 |
|
374 *rle++=KRleHorzMode; |
|
375 a0=Max(0,a0); // deal with start-effects (a0==-1) |
|
376 TInt run=a1-a0; |
|
377 WRITE_RLE(rle,color,run); |
|
378 // copy the next run |
|
379 if (a1==KFaxPixelsPerScanLine) |
|
380 { // complete, need a zero-length, other-color, run to finish |
|
381 *rle++=RLE_RUN(KRleWhite-color,0); |
|
382 break; |
|
383 } |
|
384 // copy the next RLE code directly from the current line |
|
385 TInt x=*cur++; |
|
386 __ASSERT_DEBUG((x&KRleWhite)==KRleWhite-color,User::Invariant()); |
|
387 if (x>=KRleMakeup) |
|
388 { |
|
389 *rle++=TUint8(x); |
|
390 a1+=(x&KRleMakeupMask)<<5; |
|
391 x=*cur++; |
|
392 } |
|
393 *rle++=TUint8(x); |
|
394 a1+=x>>1; |
|
395 if (a1==KFaxPixelsPerScanLine) |
|
396 break; // complete |
|
397 a0=a1; |
|
398 READ_RLE(cur,a1); // traverse another edge |
|
399 if (b1>a0) |
|
400 goto gotB2; |
|
401 } |
|
402 EncodeHuffman(aEncodedScanLine,KRleTag2D,rlebuf,rle); |
|
403 } |
|
404 |
|
405 EXPORT_C TInt CFaxT4::DecodeScanLine (TDes8 & aScanLine, const TDesC8 & anEncodedScanLine) |
|
406 /** Decodes a scan line. |
|
407 |
|
408 The decoding method depends on the compression type specified when the object |
|
409 was initialised - using PageInitialize(). If the object was not initialised, |
|
410 then the scan line is decoded as Modified Huffman. |
|
411 |
|
412 The fax client can determine the type of compression used in a fax from its |
|
413 header, and can hence use PageInitialize() to set the correct decoding method. |
|
414 KErrUnderflow is returned if the wrong type of compression is specified. |
|
415 |
|
416 @param aScanLine On return, contains the decoded scan line. |
|
417 @param anEncodedScanLine The encoded scan line to be decoded. |
|
418 @return KErrNone if successful, otherwise another of the system-wide error |
|
419 codes. |
|
420 @capability None |
|
421 */ |
|
422 { |
|
423 if (iCompression == EModifiedHuffman) |
|
424 return (DecodeScanLine1D (aScanLine, anEncodedScanLine)); |
|
425 else |
|
426 return (DecodeScanLine2D (aScanLine, anEncodedScanLine)); |
|
427 } |
|
428 |
|
429 void CFaxT4::DecodeHuffman(const TDesC8 & aEncodedScanLine) |
|
430 { |
|
431 // If all goes wrong then the reference line is unchanged and will be |
|
432 // used for the current line |
|
433 |
|
434 const TUint8* t4=aEncodedScanLine.Ptr(); |
|
435 const TUint8* endt4=t4+aEncodedScanLine.Length(); |
|
436 TUint bits=0; |
|
437 |
|
438 // store the basic RLE data locally, and copy to the member data if the decode |
|
439 // is successful |
|
440 |
|
441 TUint8 rlebuf[KFaxPixelsPerScanLine+4]; |
|
442 TUint8* rle=rlebuf; |
|
443 |
|
444 // Keep track of where we have got to on the reference (previous) line |
|
445 const TUint8* ref=iRef; |
|
446 TInt b1=0; // pixel position on the reference line |
|
447 TInt a0=0; // previous position on the current line |
|
448 TInt a1=0; // current position on the current line |
|
449 |
|
450 // start decoding using the tag-tree, which finds the first 1-bit |
|
451 // and then determines the encoding (1D or 2D) based on the next bit |
|
452 const TNode* tree=KTagTree; |
|
453 |
|
454 // "color" stores the current line color (in bit 0), the reference line |
|
455 // color (in bit 1), and the number of white/black codes to expect (x4) |
|
456 // if color<0, then we are in 2d-tree mode |
|
457 // initially unused until the encoding type is known |
|
458 |
|
459 TInt color=0; |
|
460 TInt code; |
|
461 |
|
462 for (;;) |
|
463 { |
|
464 // the structure of the following code maxmises the speed of the |
|
465 // huffman decoder. Don't change it. |
|
466 code = 0; // start at the root of the tree |
|
467 nextBit2d: |
|
468 if (((bits <<= 1) & 0x80000000)==0) |
|
469 goto nextByte2d; // run out of bits in the current byte |
|
470 decode2d: |
|
471 code = CODE (tree, code, bits & 0x80); |
|
472 if (ISBRANCH (code)) |
|
473 goto nextBit2d; // a branch code |
|
474 |
|
475 // We have the huffman code |
|
476 |
|
477 if (code<KOurEol) |
|
478 { // the code was a white/black length code |
|
479 __ASSERT_DEBUG(color>=0,User::Invariant()); |
|
480 TInt v=CODEVALUE(code); |
|
481 a1+=v; |
|
482 if (a1>KFaxPixelsPerScanLine) |
|
483 return; // overflow |
|
484 if (v < 64) |
|
485 { // a run code (as opposed to make-up code). Emit the RLE |
|
486 a0=a1-a0; |
|
487 WRITE_RLE(rle,(color&1),a0); |
|
488 a0=a1; |
|
489 color^=KRleWhite; // switch color |
|
490 color-=4; // one less white/black code |
|
491 tree=color>=0 ? color&KRleWhite ? KWhiteTree : KBlackTree : KTwoTree; |
|
492 } |
|
493 continue; |
|
494 } |
|
495 if (code<KPassMode) |
|
496 { |
|
497 if (code == KHorzMode) |
|
498 { // expect two white/black codes to follow |
|
499 color+=8; |
|
500 tree = color&KRleWhite ? KWhiteTree : KBlackTree; |
|
501 continue; |
|
502 } |
|
503 if (code==KTag1D) |
|
504 { // 1d decoding: set color to maximum positive value |
|
505 // as all codes are standard white/black code. |
|
506 color=KMaxTInt; // current and reference color both 1 (white) |
|
507 tree=KWhiteTree; |
|
508 continue; |
|
509 } |
|
510 if (code==KTag2D) |
|
511 { // 2d decoding: set color negative to indicate 2d-tree |
|
512 color=-1; // current and reference color both 1 (white) |
|
513 tree=KTwoTree; |
|
514 continue; |
|
515 } |
|
516 if (code==KOurEol) |
|
517 goto eol2d; |
|
518 __ASSERT_DEBUG(code == KBadRun,User::Invariant()); |
|
519 return; // bad run, give up |
|
520 } |
|
521 |
|
522 // The remaining 2D possibilities all require that we know the various 2D determinants |
|
523 // so we proceed as follows : |
|
524 |
|
525 // b0 tracks the previous "edge" in the reference line |
|
526 TInt b0=0; |
|
527 // find the next "edge" on the reference line after a1 |
|
528 // if we've just started decoding (rle==rlebuf), b1 boundary at 0 is correct |
|
529 if (rle!=rlebuf) |
|
530 { |
|
531 while (b1<=a1) |
|
532 { |
|
533 color^=KRleWhite<<1; |
|
534 b0=b1; |
|
535 if (b1!=KFaxPixelsPerScanLine) |
|
536 READ_RLE(ref,b1); |
|
537 } |
|
538 } |
|
539 // the b1 "edge" must match the colors of a1, so move one more edge if |
|
540 // the a0 color (color&1) is the same as the b1 color (color&2) |
|
541 if (((color^(color>>1))&1)==0) |
|
542 { |
|
543 b0=b1; |
|
544 if (b1!=KFaxPixelsPerScanLine) |
|
545 READ_RLE(ref,b1); |
|
546 color^=KRleWhite<<1; |
|
547 } |
|
548 |
|
549 // If the code is below PASSMODE then it is one of the vertical code words |
|
550 // which are pretty easy to decipher as we have all the data. Vertical mode |
|
551 // flips the colour and then continues |
|
552 |
|
553 if (code==KPassMode) |
|
554 { |
|
555 // we need to identify the next reference "edge" |
|
556 if (b1==KFaxPixelsPerScanLine) |
|
557 return; // overflow |
|
558 READ_RLE(ref,b1); |
|
559 if (b1==KFaxPixelsPerScanLine) |
|
560 return; // overflow |
|
561 color^=KRleWhite<<1; |
|
562 a1=b1; |
|
563 continue; |
|
564 } |
|
565 |
|
566 __ASSERT_DEBUG(code>=KVtMode3n && code<=KVtMode3p,User::Invariant()); |
|
567 // vertical mode |
|
568 a1=b1+(code-(KVtMode0)); |
|
569 if (a1>KFaxPixelsPerScanLine) |
|
570 return; // overflow |
|
571 if (b0>a1) |
|
572 { |
|
573 // special case of vertical mode cross-over |
|
574 // rewind the reference line to the previous "edge" |
|
575 b1=b0; |
|
576 --ref; |
|
577 color^=KRleWhite<<1; |
|
578 } |
|
579 a0=a1-a0; |
|
580 WRITE_RLE(rle,(color&1),a0); |
|
581 a0=a1; |
|
582 color^=KRleWhite; |
|
583 } |
|
584 nextByte2d: |
|
585 if (t4 < endt4) |
|
586 { |
|
587 bits = 0xff000000u | *t4++; |
|
588 goto decode2d; |
|
589 } |
|
590 eol2d: |
|
591 if (a0==KFaxPixelsPerScanLine) |
|
592 iEndRef=Mem::Copy(iRef,rlebuf,rle-rlebuf); |
|
593 } |
|
594 |
|
595 EXPORT_C TInt CFaxT4::DecodeScanLine2D (TDes8 & aScanLine, const TDesC8 & aEncodedScanLine) |
|
596 /** Decodes a Modified Read encoded scan line. |
|
597 |
|
598 @param aScanLine On return, contains the decoded scan line. |
|
599 @param anEncodedScanLine The 2D encoded scan line to be decoded. |
|
600 @return KErrNone if successful, KErrUnderflow if the scan line is encoded as |
|
601 MR, otherwise another of the system-wide error codes. |
|
602 @capability None |
|
603 */ |
|
604 { |
|
605 DecodeHuffman(aEncodedScanLine); |
|
606 // |
|
607 // decode the RLE into the scanline |
|
608 // |
|
609 aScanLine.SetLength (KFaxPixelsPerScanLine / 8); |
|
610 TUint32 *scan = (TUint32 *) aScanLine.Ptr (); |
|
611 __ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxDecodeScanlineAlignment)); |
|
612 |
|
613 const TUint8* rle=iRef; |
|
614 const TUint8* const end=iEndRef; |
|
615 |
|
616 TUint color = ~0u; // start white |
|
617 TUint out = 0; // output pixels in accumulation |
|
618 TInt bits = 0; // this is the number of used bits in out |
|
619 |
|
620 while (rle<end) |
|
621 { |
|
622 TInt run=*rle++; |
|
623 __ASSERT_DEBUG(TUint((run&1))==(color&1),User::Invariant()); // rle-data correct |
|
624 if (run<KRleMakeup) |
|
625 { // run length code (x2) |
|
626 out += color << bits; // complete the current 32-bits |
|
627 bits += run >> 1; // add the run length |
|
628 if (bits < 32) // hasn't completed the word |
|
629 out -= color << bits; // remove the trailing bits |
|
630 else |
|
631 { |
|
632 *scan++ = out; // write the 32-bits |
|
633 bits -= 64; |
|
634 if (bits >= 0) |
|
635 *scan++ = color; // + another 32 bits |
|
636 else |
|
637 bits += 32; // no extra |
|
638 out = color - (color<<bits); // bits remaining |
|
639 } |
|
640 color = ~color; // swap color |
|
641 } |
|
642 else |
|
643 { |
|
644 // make-up code. (run-KRleMakeup)>>1 is the multiple of 64 bits |
|
645 out += color << bits; // complete the current 32-bits |
|
646 *scan++ = out; // output |
|
647 *scan++ = color; // +32 bits of color |
|
648 for (run -= KRleMakeup+4;run >= 0;run -= 2) |
|
649 { // extra multiples of 64 bits |
|
650 *scan++ = color; |
|
651 *scan++ = color; |
|
652 } |
|
653 out = color - (color<<bits); // remainder bits |
|
654 } |
|
655 } |
|
656 return KErrNone; |
|
657 } |
|
658 |
|
659 EXPORT_C TInt CFaxT4::DecodeScanLine1D (TDes8 & aScanLine, const TDesC8 & anEncodedScanLine) |
|
660 // |
|
661 // This could be done through DecodeScanLine2D, but this is an optimized version for 1D |
|
662 // The intermediate rle encoding is skipped |
|
663 // |
|
664 /** Decodes a Modified Huffman encoded scan line. |
|
665 |
|
666 @param aScanLine On return, contains the decoded scan line. |
|
667 @param anEncodedScanLine The MH encoded scan line to be decoded. |
|
668 @return KErrNone if successful, KErrUnderflow if the scan line is encoded as |
|
669 MR, otherwise another of the system-wide error codes. |
|
670 @capability None |
|
671 */ |
|
672 { |
|
673 const TUint8 *t4 = anEncodedScanLine.Ptr (); |
|
674 const TUint8 *const endt4 = t4 + anEncodedScanLine.Length (); |
|
675 // |
|
676 aScanLine.SetLength (KFaxPixelsPerScanLine / 8); |
|
677 TUint32 *scan = (TUint32 *) aScanLine.Ptr (); |
|
678 __ASSERT_DEBUG ((TUint (scan) & 3) == 0, Panic (EFaxDecodeScanlineAlignment)); |
|
679 TUint out = 0; |
|
680 TInt bits = 0; // this is the number ofused bits |
|
681 // |
|
682 TInt dotsleft = KFaxPixelsPerScanLine; |
|
683 const TNode *tree = KSynchTree; |
|
684 TUint octet=0; |
|
685 TUint color = 0xffffffffu; |
|
686 |
|
687 nextCode1d: |
|
688 TInt code = 0; |
|
689 nextBit1d: |
|
690 if (((octet <<= 1) & 0x80000000)==0) |
|
691 goto nextByte1d; |
|
692 decode1d: |
|
693 code = CODE (tree, code, octet & 0x80); |
|
694 if (ISBRANCH (code)) |
|
695 goto nextBit1d; |
|
696 |
|
697 // end of huffman code |
|
698 |
|
699 if (code<KEndCode+0x40) |
|
700 { |
|
701 code-=KEndCode; |
|
702 if ((dotsleft -= code) < 0) |
|
703 return KErrOverflow; |
|
704 out += color<<bits; |
|
705 bits+=code; |
|
706 if (bits<32) |
|
707 out -= color<<bits; // output word not full |
|
708 else |
|
709 { // out is full |
|
710 *scan++=out; |
|
711 bits-=64; |
|
712 if (bits>=0) |
|
713 *scan++=color; |
|
714 else |
|
715 bits+=32; |
|
716 out=color-(color<<bits); |
|
717 } |
|
718 color = ~color; |
|
719 if (color) |
|
720 tree=KWhiteTree; |
|
721 else |
|
722 tree=KBlackTree; |
|
723 goto nextCode1d; |
|
724 } |
|
725 else if (code<=KEndCode+KMaxRun) |
|
726 { // makeup (multiple of 64) |
|
727 code-=KEndCode+0x40; |
|
728 if ((dotsleft -= code<<6) < 0) |
|
729 return KErrOverflow; |
|
730 out += color << bits; |
|
731 *scan++=out; |
|
732 *scan++=color; |
|
733 for (code-=2;code>=0;--code) |
|
734 { |
|
735 *scan++=color; |
|
736 *scan++=color; |
|
737 } |
|
738 out = color-(color<<bits); |
|
739 goto nextCode1d; |
|
740 } |
|
741 else if (code == KOurEol) |
|
742 goto eol1d; |
|
743 else if (code == KStd1D) |
|
744 { |
|
745 tree=KWhiteTree; |
|
746 goto nextCode1d; |
|
747 } |
|
748 else |
|
749 { |
|
750 __ASSERT_DEBUG (code == KBadRun, User::Invariant ()); |
|
751 return KErrCorrupt; |
|
752 } |
|
753 nextByte1d: |
|
754 if (t4 < endt4) |
|
755 { |
|
756 octet = 0xff000000u | *t4++; |
|
757 goto decode1d; |
|
758 } |
|
759 eol1d: |
|
760 __ASSERT_DEBUG (dotsleft || (TUint8 *) scan - aScanLine.Ptr () == KFaxPixelsPerScanLine / 8, User::Invariant ()); |
|
761 return dotsleft ? KErrUnderflow : KErrNone; |
|
762 } |
|
763 |