|
1 // Copyright (c) 1999-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 <fbs.h> |
|
17 #include "PPM1Codec.h" |
|
18 #include "pluginextensionmanager.h" |
|
19 |
|
20 const TInt KRAWBytesPerPixel = 3; |
|
21 |
|
22 // CPpmReadCodec |
|
23 |
|
24 CPpmReadCodec* CPpmReadCodec::NewL(CPpmDecoder& aDecoder) |
|
25 { |
|
26 CPpmReadCodec* result = new (ELeave) CPpmReadCodec(aDecoder); |
|
27 CleanupStack::PushL(result); |
|
28 result->ConstructL(); |
|
29 CleanupStack::Pop(result); |
|
30 return result; |
|
31 } |
|
32 |
|
33 |
|
34 CPpmReadCodec::CPpmReadCodec(CPpmDecoder& aDecoder): |
|
35 iDecoder(&aDecoder) |
|
36 {} |
|
37 |
|
38 CPpmReadCodec::~CPpmReadCodec() |
|
39 { |
|
40 } |
|
41 |
|
42 TFrameState CPpmReadCodec::ProcessFrameL(TBufPtr8& aSrc) |
|
43 { |
|
44 const TUint8* srcStart = aSrc.Ptr(); |
|
45 iDataPtr = srcStart; |
|
46 iDataPtrLimit = srcStart + aSrc.Length(); |
|
47 |
|
48 TInt bytesUsed = 0; |
|
49 if(!iSeekRequested) |
|
50 { |
|
51 if (iDecoder->Compressed()) |
|
52 { |
|
53 DoProcessCompressed(); |
|
54 bytesUsed = iDataPtr - srcStart; |
|
55 } |
|
56 else |
|
57 { |
|
58 TLex8 lex (aSrc); |
|
59 TRAPD(error, DoProcessUncompressedL(lex)); |
|
60 if (error!=KErrNone && error!=KErrGeneral && error!=KErrUnderflow) // trap for insufficient data |
|
61 { |
|
62 User::Leave(error); |
|
63 } |
|
64 bytesUsed = lex.MarkedOffset(); |
|
65 } |
|
66 |
|
67 aSrc.Shift(bytesUsed); |
|
68 } |
|
69 |
|
70 if (iPixelsProcessed >= iPixelsExpected) |
|
71 { |
|
72 return EFrameComplete; |
|
73 } |
|
74 |
|
75 if(iSeekRequested) |
|
76 { |
|
77 /* |
|
78 Move the pointer to the end of the buffer. This is to |
|
79 workaround a problem with the ICL framework, where if we |
|
80 choose to seek and haven't incremented the pointer, then |
|
81 it returns KErrUnderflow. Thus, the first seek (when |
|
82 cropping) will fail. |
|
83 */ |
|
84 TInt bytesRemainingInBuffer = Min(iNewBytePosition, iDataPtrLimit - iDataPtr); |
|
85 aSrc.Shift(bytesRemainingInBuffer); |
|
86 iNewBytePosition -= bytesRemainingInBuffer; |
|
87 iSeekRequested = EFalse; |
|
88 return EFrameIncompleteRepositionRequest; |
|
89 } |
|
90 |
|
91 return EFrameIncomplete; |
|
92 } |
|
93 |
|
94 void CPpmReadCodec::Complete() |
|
95 { |
|
96 ImageProcessor()->FlushPixels(); |
|
97 } |
|
98 |
|
99 void CPpmReadCodec::DoProcessUncompressedL(TLex8 &aLex) |
|
100 { |
|
101 CImageProcessor*const imageProc = ImageProcessor(); |
|
102 for (;;) // exit of this will be a leave |
|
103 { |
|
104 TUint rVal; |
|
105 iDecoder->SkipCommentAndWhiteSpaceL(aLex); |
|
106 ASSERT(!iDecoder->InComment()); |
|
107 User::LeaveIfError(aLex.Val(rVal)); |
|
108 TUint gVal; |
|
109 iDecoder->SkipCommentAndWhiteSpaceL(aLex); |
|
110 ASSERT(!iDecoder->InComment()); |
|
111 User::LeaveIfError(aLex.Val(gVal)); |
|
112 TUint bVal; |
|
113 iDecoder->SkipCommentAndWhiteSpaceL(aLex); |
|
114 ASSERT(!iDecoder->InComment()); |
|
115 User::LeaveIfError(aLex.Val(bVal)); |
|
116 |
|
117 TInt dataShift = iDecoder->DataShift(); |
|
118 TRgb rgb (rVal<<dataShift, gVal<<dataShift, bVal<<dataShift); |
|
119 |
|
120 imageProc->SetPixel(rgb); |
|
121 |
|
122 aLex.Mark(); // show we've got this far - on error, only wind back this far. |
|
123 |
|
124 iPixelsProcessed += 1; |
|
125 } |
|
126 } |
|
127 |
|
128 void CPpmReadCodec::DoProcessCompressed() |
|
129 { |
|
130 CImageProcessor*const imageProc = ImageProcessor(); |
|
131 |
|
132 while (iDataPtr < iDataPtrLimit-2) |
|
133 { |
|
134 TUint8 rVal = iDataPtr[0]; |
|
135 TUint8 gVal = iDataPtr[1]; |
|
136 TUint8 bVal = iDataPtr[2]; |
|
137 iDataPtr += KRAWBytesPerPixel; |
|
138 |
|
139 TInt dataShift = iDecoder->DataShift(); |
|
140 TRgb rgb (rVal<<dataShift, gVal<<dataShift, bVal<<dataShift); |
|
141 |
|
142 imageProc->SetPos(iCurrentPosition); |
|
143 imageProc->SetPixel(rgb); |
|
144 iPixelsProcessed += 1; |
|
145 |
|
146 if(iXAxisFirst) |
|
147 { |
|
148 iCurrentPosition.iX += iXAxisIncrement; |
|
149 if(iCurrentPosition.iX == iEndPosition.iX) |
|
150 { |
|
151 iCurrentPosition.iX = iStartPosition.iX; |
|
152 iCurrentPosition.iY += iYAxisIncrement; |
|
153 if(iExtensionManager->ClippingRectExtensionRequested()) |
|
154 { |
|
155 // Clipping is required, so need to skip position in buffer |
|
156 iSeekRequested = ETrue; |
|
157 iNewBytePosition = iFrameInfo->iOverallSizeInPixels.iWidth - iExtensionManager->ClippingRect().Size().iWidth; |
|
158 iNewBytePosition *= KRAWBytesPerPixel; |
|
159 break; |
|
160 } |
|
161 } |
|
162 } |
|
163 else |
|
164 { |
|
165 iCurrentPosition.iY += iYAxisIncrement; |
|
166 if(iCurrentPosition.iY == iEndPosition.iY) |
|
167 { |
|
168 iCurrentPosition.iY = iStartPosition.iY; |
|
169 iCurrentPosition.iX += iXAxisIncrement; |
|
170 if(iExtensionManager->ClippingRectExtensionRequested()) |
|
171 { |
|
172 // Clipping is required, so need to skip position in buffer |
|
173 iSeekRequested = ETrue; |
|
174 iNewBytePosition = iFrameInfo->iOverallSizeInPixels.iWidth - iExtensionManager->ClippingRect().Size().iWidth; |
|
175 iNewBytePosition *= KRAWBytesPerPixel; |
|
176 break; |
|
177 } |
|
178 } |
|
179 } |
|
180 } |
|
181 } |
|
182 |
|
183 void CPpmReadCodec::InitFrameL(TFrameInfo& /*aFrameInfo*/, CFrameImageData& /*aFrameImageData*/, TBool aDisableErrorDiffusion, CFbsBitmap& aFrame, CFbsBitmap* /*aDestinationMask*/) |
|
184 { |
|
185 ASSERT(iFrameInfo); |
|
186 ASSERT(iExtensionManager); |
|
187 |
|
188 /* |
|
189 This function is used by both compressed and uncompressed format, although some of the |
|
190 calls aren't stricly necessary for the uncompressed format (since extensions are not |
|
191 supported, except for the GetDestinationSize() call). |
|
192 */ |
|
193 |
|
194 User::LeaveIfError(ValidateDestinationSize(aFrame.SizeInPixels())); |
|
195 |
|
196 TSize finalSize = iExtensionManager->ClippingRectExtensionRequested() ? |
|
197 iExtensionManager->ClippingRect().Size() : iFrameInfo->iOverallSizeInPixels; |
|
198 if(iExtensionManager->DimensionsSwapped()) |
|
199 { |
|
200 finalSize.SetSize(finalSize.iHeight, finalSize.iWidth); |
|
201 } |
|
202 |
|
203 TInt scalingCoefficient = ScalingCoefficientL(finalSize, aFrame.SizeInPixels()); |
|
204 TInt reductionFactor = CPluginExtensionManager::ConvertScalingCoeffToReductionFactor(scalingCoefficient); |
|
205 |
|
206 CImageProcessorExtension* imageProc = |
|
207 ImageProcessorUtility::NewImageProcessorExtensionL(aFrame, reductionFactor, iFrameInfo->iFrameDisplayMode, aDisableErrorDiffusion); |
|
208 SetImageProcessor(imageProc); |
|
209 |
|
210 iExtensionManager->TransferExtensionDataL(imageProc); |
|
211 // Pass in full size of image or clip rect |
|
212 imageProc->PrepareL(aFrame, finalSize); |
|
213 |
|
214 // Set up member variables if Operations have been requested |
|
215 SetOperationData(finalSize); |
|
216 |
|
217 ClearBitmapL(aFrame, KRgbWhite); |
|
218 // do something sensible for partial streamed decodes |
|
219 |
|
220 iPixelsProcessed = 0; |
|
221 iPixelsExpected = finalSize.iWidth * finalSize.iHeight; |
|
222 |
|
223 // Determine how many pixels to skip on the Y axis of the original, if any |
|
224 TInt pixelsToSkip = iFrameInfo->iFrameCoordsInPixels.iBr.iX * iExtensionManager->ClippingRect().iTl.iY; |
|
225 // Add X axis pixels on the left side of the crop rect, if any |
|
226 pixelsToSkip += iExtensionManager->ClippingRect().iTl.iX - iFrameInfo->iFrameCoordsInPixels.iTl.iX; |
|
227 |
|
228 iNewBytePosition = pixelsToSkip*KRAWBytesPerPixel; |
|
229 iSeekRequested = iNewBytePosition > 0 ? ETrue : EFalse; |
|
230 |
|
231 iDecoder->SetInComment(EFalse); |
|
232 } |
|
233 |
|
234 void CPpmReadCodec::InitFrameHeader(TFrameInfo& aFrameInfo, CFrameImageData& /*aFrameData*/) |
|
235 { |
|
236 ASSERT(aFrameInfo.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised); |
|
237 iFrameInfo = &aFrameInfo; |
|
238 aFrameInfo.SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader); |
|
239 } |
|
240 |
|
241 TFrameState CPpmReadCodec::ProcessFrameHeaderL(TBufPtr8&/* aData*/) |
|
242 { |
|
243 ASSERT(iFrameInfo); |
|
244 iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete); |
|
245 return EFrameComplete; |
|
246 } |
|
247 |
|
248 void CPpmReadCodec::GetNewDataPosition(TInt &aPosition, TInt &/*aLength*/) |
|
249 { |
|
250 aPosition += iNewBytePosition; |
|
251 } |
|
252 |
|
253 void CPpmReadCodec::SetExtensionManager(CPluginExtensionManager* aExtensionManager) |
|
254 { |
|
255 // Is owned by the plugin, not this codec |
|
256 iExtensionManager = aExtensionManager; |
|
257 } |
|
258 |
|
259 TInt CPpmReadCodec::ValidateDestinationSize(const TSize& aDestSize) const |
|
260 { |
|
261 ASSERT(iExtensionManager); |
|
262 |
|
263 TInt err = KErrNone; |
|
264 if(iExtensionManager->ScalerExtensionRequested()) |
|
265 { |
|
266 TSize destSizeCheck = iFrameInfo->iOverallSizeInPixels; |
|
267 err = iExtensionManager->GetDestinationSize(destSizeCheck); |
|
268 if(err == KErrNone) |
|
269 { |
|
270 // Mandatory check that the destination size matches the calculated size |
|
271 if(destSizeCheck != aDestSize) |
|
272 { |
|
273 err = KErrArgument; |
|
274 } |
|
275 } |
|
276 } |
|
277 return err; |
|
278 } |
|
279 |
|
280 TInt CPpmReadCodec::ScalingCoefficientL(const TSize& aDestinationSize, const TSize& aFrameSize) const |
|
281 { |
|
282 ASSERT(iExtensionManager); |
|
283 |
|
284 TInt scalingCoefficient = -1; // initialise to full size |
|
285 if(iExtensionManager->ScalerExtensionRequested()) |
|
286 { |
|
287 // Explicit scaling |
|
288 User::LeaveIfError(iExtensionManager->GetScalingCoefficient(scalingCoefficient, &aDestinationSize)); |
|
289 } |
|
290 else |
|
291 { |
|
292 // Implicit scaling |
|
293 scalingCoefficient = ScalingCoefficient(aDestinationSize, aFrameSize); |
|
294 } |
|
295 return scalingCoefficient; |
|
296 } |
|
297 |
|
298 void CPpmReadCodec::SetOperationData(const TRect& aDestinationBitmap) |
|
299 { |
|
300 ASSERT(iExtensionManager); |
|
301 ASSERT(!aDestinationBitmap.IsEmpty()); |
|
302 ASSERT(aDestinationBitmap.IsNormalized()); |
|
303 |
|
304 /* |
|
305 Note that iStartPosition is the starting point and so needs to |
|
306 be INSIDE the TRect, whereas iEndPosition is the end point and thus |
|
307 lies diagonally opposite the start point, and OUTSIDE the TRect. |
|
308 |
|
309 ----------------- |
|
310 |tlo| | |tro |
|
311 ----------------- |
|
312 | |tli|tri| | |
|
313 ----------------- |
|
314 | |bli|bri| | |
|
315 ----------------- |
|
316 |blo| | |bro| |
|
317 ----------------- |
|
318 |
|
319 tlo = top left outside image |
|
320 tro = top right outside image |
|
321 blo = bottom left outside image |
|
322 bro = bottom right outside image (i.e. iBr) |
|
323 |
|
324 tli = top left inside image (i.e. iTl) |
|
325 tri = top right inside image |
|
326 bli = bottom left inside image |
|
327 bri = bottom right inside image |
|
328 */ |
|
329 TPoint tlOutsideImageRegion(aDestinationBitmap.iTl.iX - 1, aDestinationBitmap.iTl.iY - 1); |
|
330 TPoint trOutsideImageRegion(aDestinationBitmap.iBr.iX, aDestinationBitmap.iTl.iY - 1); |
|
331 TPoint blOutsideImageRegion(aDestinationBitmap.iTl.iX - 1, aDestinationBitmap.iBr.iY); |
|
332 TPoint brOutsideImageRegion(aDestinationBitmap.iBr.iX, aDestinationBitmap.iBr.iY); |
|
333 TPoint tlInsideImageRegion(aDestinationBitmap.iTl.iX, aDestinationBitmap.iTl.iY); |
|
334 TPoint trInsideImageRegion(aDestinationBitmap.iBr.iX - 1, aDestinationBitmap.iTl.iY); |
|
335 TPoint blInsideImageRegion(aDestinationBitmap.iTl.iX, aDestinationBitmap.iBr.iY - 1); |
|
336 TPoint brInsideImageRegion(aDestinationBitmap.iBr.iX - 1, aDestinationBitmap.iBr.iY - 1); |
|
337 |
|
338 switch(iExtensionManager->Operation()) |
|
339 { |
|
340 case EDecodeNormal: |
|
341 iStartPosition = tlInsideImageRegion; |
|
342 iCurrentPosition = iStartPosition; |
|
343 iEndPosition = brOutsideImageRegion; |
|
344 iXAxisIncrement = 1; |
|
345 iYAxisIncrement = 1; |
|
346 iXAxisFirst = ETrue; |
|
347 break; |
|
348 case EDecodeRotate90: |
|
349 iStartPosition = trInsideImageRegion; |
|
350 iCurrentPosition = iStartPosition; |
|
351 iEndPosition = blOutsideImageRegion; |
|
352 iXAxisIncrement = -1; |
|
353 iYAxisIncrement = 1; |
|
354 iXAxisFirst = EFalse; |
|
355 break; |
|
356 case EDecodeRotate180: |
|
357 iStartPosition = brInsideImageRegion; |
|
358 iCurrentPosition = iStartPosition; |
|
359 iEndPosition = tlOutsideImageRegion; |
|
360 iXAxisIncrement = -1; |
|
361 iYAxisIncrement = -1; |
|
362 iXAxisFirst = ETrue; |
|
363 break; |
|
364 case EDecodeRotate270: |
|
365 iStartPosition = blInsideImageRegion; |
|
366 iCurrentPosition = iStartPosition; |
|
367 iEndPosition = trOutsideImageRegion; |
|
368 iXAxisIncrement = 1; |
|
369 iYAxisIncrement = -1; |
|
370 iXAxisFirst = EFalse; |
|
371 break; |
|
372 case EDecodeHorizontalFlip: |
|
373 iStartPosition = blInsideImageRegion; |
|
374 iCurrentPosition = iStartPosition; |
|
375 iEndPosition = trOutsideImageRegion; |
|
376 iXAxisIncrement = 1; |
|
377 iYAxisIncrement = -1; |
|
378 iXAxisFirst = ETrue; |
|
379 break; |
|
380 case EDecodeHorizontalFlipRotate90: |
|
381 iStartPosition = tlInsideImageRegion; |
|
382 iCurrentPosition = iStartPosition; |
|
383 iEndPosition = brOutsideImageRegion; |
|
384 iXAxisIncrement = 1; |
|
385 iYAxisIncrement = 1; |
|
386 iXAxisFirst = EFalse; |
|
387 break; |
|
388 case EDecodeVerticalFlip: |
|
389 iStartPosition = trInsideImageRegion; |
|
390 iCurrentPosition = iStartPosition; |
|
391 iEndPosition = blOutsideImageRegion; |
|
392 iXAxisIncrement = -1; |
|
393 iYAxisIncrement = 1; |
|
394 iXAxisFirst = ETrue; |
|
395 break; |
|
396 case EDecodeVerticalFlipRotate90: |
|
397 iStartPosition = brInsideImageRegion; |
|
398 iCurrentPosition = iStartPosition; |
|
399 iEndPosition = tlOutsideImageRegion; |
|
400 iXAxisIncrement = -1; |
|
401 iYAxisIncrement = -1; |
|
402 iXAxisFirst = EFalse; |
|
403 break; |
|
404 default: |
|
405 { |
|
406 ASSERT(EFalse); |
|
407 } |
|
408 } |
|
409 } |
|
410 |
|
411 // CPpm1WriteCodec |
|
412 |
|
413 const TInt KMaxColourValue = 255; |
|
414 |
|
415 CPpm1WriteCodec::CPpm1WriteCodec() |
|
416 {} |
|
417 |
|
418 CPpm1WriteCodec::~CPpm1WriteCodec() |
|
419 {} |
|
420 |
|
421 void CPpm1WriteCodec::ConstructL() |
|
422 { |
|
423 CImageWriteCodec::ConstructL(); |
|
424 } |
|
425 |
|
426 CPpm1WriteCodec* CPpm1WriteCodec::NewL() |
|
427 { |
|
428 CPpm1WriteCodec* result = new (ELeave) CPpm1WriteCodec; |
|
429 CleanupStack::PushL(result); |
|
430 result->ConstructL(); |
|
431 CleanupStack::Pop(result); |
|
432 return result; |
|
433 } |
|
434 |
|
435 void CPpm1WriteCodec::InitFrameL(TBufPtr8& aDst, const CFbsBitmap& aSource) |
|
436 { |
|
437 SetSource(&aSource); |
|
438 iDestStartPtr = const_cast<TUint8*>(aDst.Ptr()); |
|
439 iDestPtr = iDestStartPtr; |
|
440 iDestPtrLimit = iDestPtr + aDst.MaxLength(); |
|
441 |
|
442 TSize size = aSource.SizeInPixels(); |
|
443 iSourceRect = TRect(size); |
|
444 iPos.SetXY(0,0); |
|
445 |
|
446 TBuf8<256> header; // set up header in buffer |
|
447 header.Zero(); |
|
448 |
|
449 // now the standard header lines |
|
450 _LIT8(KMagicHeader, "P6\n"); |
|
451 header.AppendFormat(KMagicHeader); // ppm magic for compressed |
|
452 _LIT8(KSizeHeader, "%d %d\n"); |
|
453 header.AppendFormat(KSizeHeader, size.iWidth, size.iHeight); |
|
454 _LIT8(KMaxValueHeader, "%d\n"); |
|
455 header.AppendFormat(KMaxValueHeader, KMaxColourValue); |
|
456 |
|
457 TInt headerSize = header.Length(); |
|
458 aDst.Copy(header); |
|
459 iDestPtr+=headerSize; |
|
460 |
|
461 ASSERT(iDestPtr < iDestPtrLimit); // should always be true |
|
462 } |
|
463 |
|
464 TFrameState CPpm1WriteCodec::ProcessFrameL(TBufPtr8& aDst) |
|
465 { |
|
466 //Setup buffer to use all available space |
|
467 TUint8* destStartPtr = CONST_CAST(TUint8*,aDst.Ptr()); |
|
468 iDestPtr = destStartPtr; |
|
469 iDestPtrLimit = iDestPtr + aDst.MaxLength(); |
|
470 |
|
471 DoProcessL(*Source()); |
|
472 |
|
473 aDst.SetLength(iDestPtr - destStartPtr); |
|
474 |
|
475 // If processed all pixels |
|
476 if (iPos.iY < iSourceRect.iTl.iY) |
|
477 { |
|
478 return EFrameComplete; |
|
479 } |
|
480 |
|
481 return EFrameIncomplete; |
|
482 } |
|
483 |
|
484 void CPpm1WriteCodec::DoProcessL(const CFbsBitmap& aFrame) |
|
485 { |
|
486 TUint8* safeDestPtrLimit = iDestPtrLimit - 2; |
|
487 |
|
488 while (iDestPtr < safeDestPtrLimit) |
|
489 { |
|
490 if (iPos.iY >= iSourceRect.iBr.iY) |
|
491 { |
|
492 break; |
|
493 } |
|
494 |
|
495 TInt scanLength = Min(iSourceRect.iBr.iX - iPos.iX, (iDestPtrLimit - iDestPtr) / 3); |
|
496 TInt dstLength = scanLength * 3; |
|
497 TPtr8 dstBuf(iDestPtr, dstLength, dstLength); |
|
498 |
|
499 aFrame.GetScanLine(dstBuf, iPos, scanLength, EColor16M); |
|
500 // this comes out in order BGR, so switch |
|
501 SwitchRGB(dstBuf); |
|
502 |
|
503 iPos.iX += scanLength; |
|
504 iDestPtr += dstLength; |
|
505 |
|
506 if (iPos.iX == iSourceRect.iBr.iX) |
|
507 { |
|
508 iPos.iX = iSourceRect.iTl.iX; |
|
509 iPos.iY++; |
|
510 } |
|
511 } |
|
512 } |
|
513 |
|
514 // Assume original has pixels with BGR in order - switch to RGB |
|
515 void CPpm1WriteCodec::SwitchRGB(TDes8 &aBuf) |
|
516 { |
|
517 TUint8* buf = const_cast<TUint8*>(aBuf.Ptr()); |
|
518 TUint8* bufMax = buf + aBuf.Length(); |
|
519 |
|
520 while (buf<bufMax) |
|
521 { |
|
522 TUint8 b = buf[0]; |
|
523 TUint8 g = buf[1]; |
|
524 TUint8 r = buf[2]; |
|
525 buf[0] = r; |
|
526 buf[1] = g; |
|
527 buf[2] = b; |
|
528 |
|
529 buf += 3; |
|
530 } |
|
531 } |
|
532 |
|
533 |