|
1 /* |
|
2 * Copyright (c) 2003, 2004 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: CJ2kImageWriter class used to perform inverse transformation and |
|
15 * writing decoded image data to bitmap. |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 // INCLUDE FILES |
|
21 #include <e32math.h> |
|
22 #include <fbs.h> |
|
23 #include "JP2KImageUtils.h" |
|
24 #include "JP2KFormat.h" |
|
25 #include "JP2KTileInfo.h" |
|
26 #include "JP2KImageInfo.h" |
|
27 #include "JP2KSubband.h" |
|
28 #include "JP2KComponentInfo.h" |
|
29 #include "JP2KImageWriter.h" |
|
30 |
|
31 // EXTERNAL DATA STRUCTURES |
|
32 |
|
33 // EXTERNAL FUNCTION PROTOTYPES |
|
34 |
|
35 // CONSTANTS |
|
36 |
|
37 // MACROS |
|
38 #define INT2BYTE( n ) ( ( n ) < 0 ? (TUint8)0 : ( ( n ) > 255 ? (TUint8)255 : (TUint8)( n ) ) ) |
|
39 #define CLIPINT( n,bitdepth ) ( ( n >= ( 1 << bitdepth ) ) ? ( ( 1<<bitdepth ) - 1 ) : ( n < 0 ) ? 0 : n ) |
|
40 #define CLIP2BITDEPTH( n, maxValue ) ( ( n > maxValue ) ? ( maxValue ) : ( n < 0 ) ? 0 : n ) |
|
41 #define CLIP2RANGE( n, minValue, maxValue ) ( ( n > maxValue ) ? ( maxValue ) : ( n < minValue ) ? minValue : n ) |
|
42 |
|
43 // LOCAL CONSTANTS AND MACROS |
|
44 |
|
45 // MODULE DATA STRUCTURES |
|
46 |
|
47 // LOCAL FUNCTION PROTOTYPES |
|
48 |
|
49 // FORWARD DECLARATIONS |
|
50 |
|
51 // LOCAL CONSTANTS AND MACROS |
|
52 |
|
53 |
|
54 |
|
55 // ============================ MEMBER FUNCTIONS =============================== |
|
56 |
|
57 // Destructor |
|
58 CJ2kWriterComponentInfo::~CJ2kWriterComponentInfo() |
|
59 { |
|
60 iTileStartList.Close(); |
|
61 FreeData(); |
|
62 } |
|
63 |
|
64 // ----------------------------------------------------------------------------- |
|
65 // CJ2kWriterComponentInfo::AllocDataL |
|
66 // Allocate 2-D data array with a size |
|
67 // (other items were commented in a header). |
|
68 // ----------------------------------------------------------------------------- |
|
69 // |
|
70 void CJ2kWriterComponentInfo::AllocDataL( const TSize& aSize ) |
|
71 { |
|
72 FreeData(); |
|
73 iData = TJ2kUtils::Alloc2DArrayL( aSize.iHeight, aSize.iWidth ); |
|
74 } |
|
75 |
|
76 // ----------------------------------------------------------------------------- |
|
77 // CJ2kWriterComponentInfo::FreeData |
|
78 // Free the 2-D data array |
|
79 // (other items were commented in a header). |
|
80 // ----------------------------------------------------------------------------- |
|
81 // |
|
82 void CJ2kWriterComponentInfo::FreeData() |
|
83 { |
|
84 if ( iData ) |
|
85 { |
|
86 TJ2kUtils::Free2DArray( iData ); |
|
87 iData = 0; |
|
88 } |
|
89 } |
|
90 |
|
91 // ----------------------------------------------------------------------------- |
|
92 // CJ2kWriterComponentInfo::Data |
|
93 // Get the 2-D data array |
|
94 // (other items were commented in a header). |
|
95 // ----------------------------------------------------------------------------- |
|
96 // |
|
97 TPrecInt** CJ2kWriterComponentInfo::Data() |
|
98 { |
|
99 return iData; |
|
100 } |
|
101 |
|
102 // ----------------------------------------------------------------------------- |
|
103 // CJ2kWriterComponentInfo::TileStartAt |
|
104 // Get the starting point of a tile |
|
105 // (other items were commented in a header). |
|
106 // ----------------------------------------------------------------------------- |
|
107 // |
|
108 TPoint& CJ2kWriterComponentInfo::TileStartAt( TUint16 aTileIndex ) |
|
109 { |
|
110 return iTileStartList[aTileIndex]; |
|
111 } |
|
112 |
|
113 // ----------------------------------------------------------------------------- |
|
114 // CJ2kWriterComponentInfo::UpdateNextTileStartAt |
|
115 // Update the starting point of next tile |
|
116 // (other items were commented in a header). |
|
117 // ----------------------------------------------------------------------------- |
|
118 // |
|
119 void CJ2kWriterComponentInfo::UpdateNextTileStartAt( TUint16 aTileIndex, |
|
120 const TSize& aSize, |
|
121 CJ2kImageInfo& aImageInfo ) |
|
122 { |
|
123 TUint16 numOfHorizTiles = aImageInfo.NumOfHorizTiles(); |
|
124 TUint16 numOfVertTiles = aImageInfo.NumOfVertTiles(); |
|
125 |
|
126 // Calculate the p and q of a tile |
|
127 TDiv tDiv = TJ2kUtils::Div( aTileIndex, numOfHorizTiles ); |
|
128 if ( tDiv.rem != ( numOfHorizTiles - 1 ) ) |
|
129 { |
|
130 iTileStartList[aTileIndex + 1].iX = iTileStartList[aTileIndex].iX + aSize.iWidth; |
|
131 } |
|
132 |
|
133 if ( tDiv.quot != ( numOfVertTiles - 1 ) ) |
|
134 { |
|
135 iTileStartList[aTileIndex + numOfHorizTiles].iY = iTileStartList[aTileIndex].iY + aSize.iHeight; |
|
136 } |
|
137 } |
|
138 |
|
139 |
|
140 // ============================ MEMBER FUNCTIONS =============================== |
|
141 |
|
142 // ----------------------------------------------------------------------------- |
|
143 // CJ2kImageWriter::NewL |
|
144 // Two-phased constructor. |
|
145 // ----------------------------------------------------------------------------- |
|
146 // |
|
147 CJ2kImageWriter* CJ2kImageWriter::NewL( CImageProcessor* aImageProcessor, |
|
148 CJ2kImageInfo& aImageInfo, |
|
149 TJ2kInfo& aJ2kInfo ) |
|
150 { |
|
151 CJ2kImageWriter *self = new ( ELeave ) CJ2kImageWriter( aImageProcessor, aImageInfo, aJ2kInfo ); |
|
152 |
|
153 CleanupStack::PushL( self ); |
|
154 self->ConstructL(); |
|
155 CleanupStack::Pop(); |
|
156 |
|
157 return self; |
|
158 } |
|
159 |
|
160 // Destructor |
|
161 CJ2kImageWriter::~CJ2kImageWriter() |
|
162 { |
|
163 iComponents.ResetAndDestroy(); |
|
164 |
|
165 delete iLinearsRGBLut; |
|
166 iLinearsRGBLut = 0; |
|
167 |
|
168 User::Free( iGrayTRCLut ); |
|
169 User::Free( iRedTRCLut ); |
|
170 User::Free( iGreenTRCLut ); |
|
171 User::Free( iBlueTRCLut ); |
|
172 User::Free( iMonoPixelBlock ); |
|
173 User::Free( iColorPixelBlock ); |
|
174 } |
|
175 |
|
176 // ----------------------------------------------------------------------------- |
|
177 // CJ2kImageWriter::WriterComponentAt |
|
178 // Get the component of the image writer |
|
179 // (other items were commented in a header). |
|
180 // ----------------------------------------------------------------------------- |
|
181 // |
|
182 const CJ2kWriterComponentInfo& CJ2kImageWriter::WriterComponentAt( TUint16 aIndex ) const |
|
183 { |
|
184 return *iComponents[aIndex]; |
|
185 } |
|
186 |
|
187 // ----------------------------------------------------------------------------- |
|
188 // CJ2kImageWriter::OutputImageL |
|
189 // Output the image related to the component of the tile |
|
190 // (other items were commented in a header). |
|
191 // ----------------------------------------------------------------------------- |
|
192 // |
|
193 void CJ2kImageWriter::OutputImageL( CJ2kTileInfo& aTile, TUint16 aComponentIndex ) |
|
194 { |
|
195 TUint8 bitdepth = 0; |
|
196 TUint16 c = 0; |
|
197 CJ2kComponentInfo& componentInfo = CONST_CAST( CJ2kComponentInfo&, aTile.ComponentAt( aComponentIndex ) ); |
|
198 |
|
199 TInt16 reducedLevels = (TInt16)( componentInfo.Levels() - iImageInfo.LevelDrop() ); |
|
200 if ( reducedLevels < 0 ) |
|
201 { |
|
202 reducedLevels = 0; |
|
203 } |
|
204 |
|
205 CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, componentInfo.SubbandAt( (TUint8)reducedLevels ) ); |
|
206 |
|
207 if ( subband->SubbandResLevel() != 0 ) |
|
208 { |
|
209 subband = subband->Parent(); |
|
210 } |
|
211 |
|
212 TSize subbandSize = subband->SubbandCanvasSize(); |
|
213 |
|
214 // Note that in case of component truncation color transform is not performed |
|
215 if ( iImageInfo.ComponentDrop() ) |
|
216 { |
|
217 iNumComponents = 1; |
|
218 } |
|
219 else // Only perform color transform if we don't drop components |
|
220 { |
|
221 // Perform the color transfrom |
|
222 if ( aComponentIndex == 2 && aTile.ColorTransformation() ) |
|
223 { |
|
224 // Perform the inverse color transform |
|
225 if ( aTile.ComponentAt( 0 ).IsReversible() ) // If RCT is used |
|
226 { |
|
227 PerformInverseRCT( subbandSize ); |
|
228 } |
|
229 else |
|
230 { |
|
231 PerformInverseICT( subbandSize ); |
|
232 } |
|
233 } |
|
234 } |
|
235 |
|
236 // Check if palettes are used. If so, get the number of output channels |
|
237 if ( iJ2kInfo.iCMPList.Count() ) |
|
238 { |
|
239 TUint16 numCSComp = iImageInfo.NumOfComponents(); |
|
240 |
|
241 // Allocate more memory for data if needed |
|
242 if ( iNumComponents > numCSComp ) |
|
243 { |
|
244 for ( c = numCSComp; c < iNumComponents; c++ ) |
|
245 { |
|
246 // Allocate memory for component data |
|
247 iComponents[c]->AllocDataL( subbandSize ); |
|
248 } |
|
249 } |
|
250 // Check if we have all the necessary channels for component mapping |
|
251 if ( aComponentIndex == ( numCSComp - 1 ) ) |
|
252 { |
|
253 MapComponentsL( numCSComp, reducedLevels, subbandSize, aTile ); |
|
254 } |
|
255 } |
|
256 |
|
257 // We start the output of files: |
|
258 if ( iSingleFileOutput ) |
|
259 { |
|
260 if ( iNumComponents == 3 ) // 3 comp to combine |
|
261 { |
|
262 // Compute the subbandSize from the first component since others might be downsampled. |
|
263 TInt16 tempNumLevels = (TUint16)( aTile.ComponentAt( 0 ).Levels() - iImageInfo.LevelDrop() ); |
|
264 |
|
265 if ( tempNumLevels < 0 ) |
|
266 { |
|
267 tempNumLevels = 0; |
|
268 } |
|
269 |
|
270 CJ2kSubband* tempSubband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( 0 ).SubbandAt( (TUint8)tempNumLevels ) ); |
|
271 |
|
272 if ( tempSubband->SubbandResLevel() != 0 ) |
|
273 { |
|
274 tempSubband = tempSubband->Parent(); |
|
275 } |
|
276 |
|
277 subbandSize = tempSubband->SubbandCanvasSize(); |
|
278 |
|
279 if( !iColorPixelBlock ) |
|
280 { |
|
281 // Allocate memory for block of color pixels |
|
282 iColorPixelBlock = STATIC_CAST( TRgb*, User::AllocL( 2 * KPixelsBlock * sizeof( TRgb ) ) ); |
|
283 } |
|
284 |
|
285 CombineOutputFile( aTile, subbandSize ); |
|
286 for ( c = 0; c < iNumComponents; c++ ) |
|
287 { |
|
288 iComponents[c]->FreeData(); |
|
289 } |
|
290 } |
|
291 else // 1 comp to output |
|
292 { |
|
293 if ( iImageInfo.ComponentDrop() ) |
|
294 { |
|
295 c = ( TUint16 )( iImageInfo.ComponentDrop() - 1 ); |
|
296 } |
|
297 else |
|
298 { |
|
299 c = aComponentIndex; |
|
300 } |
|
301 |
|
302 bitdepth = iImageInfo.DepthOfComponent( c ); |
|
303 |
|
304 if( !iMonoPixelBlock ) |
|
305 { |
|
306 // Allocate memory for block of grayscale pixels |
|
307 iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) ); |
|
308 } |
|
309 |
|
310 // Output a single component |
|
311 WriteOutputFile( aTile, c, subbandSize, bitdepth ); |
|
312 iComponents[c]->FreeData(); |
|
313 } |
|
314 } |
|
315 else |
|
316 { |
|
317 // Write out three independent output files |
|
318 if( !iMonoPixelBlock ) |
|
319 { |
|
320 // Allocate memory for block of grayscale pixels |
|
321 iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) ); |
|
322 } |
|
323 |
|
324 if ( aComponentIndex == 2 && aTile.ColorTransformation() ) |
|
325 { |
|
326 for ( c = 0; c < 3; c++ ) |
|
327 { |
|
328 bitdepth = iImageInfo.DepthOfComponent( c ); |
|
329 |
|
330 // Output single files |
|
331 WriteOutputFile( aTile, c, subbandSize, bitdepth ); |
|
332 iComponents[c]->FreeData(); |
|
333 } |
|
334 } |
|
335 else if ( iJ2kInfo.iCMPList.Count() ) |
|
336 { |
|
337 for ( c = 0; c < iNumComponents; c++ ) |
|
338 { |
|
339 // Bitdepth is the lowest seven bits plus one for palettes |
|
340 bitdepth = ( TUint8 )( ( iJ2kInfo.iPalette.iBList[0] & 0x7f )+1 ); |
|
341 |
|
342 // Output single files |
|
343 WriteOutputFile( aTile, c, subbandSize, bitdepth ); |
|
344 iComponents[c]->FreeData(); |
|
345 } |
|
346 } |
|
347 else |
|
348 { |
|
349 bitdepth = iImageInfo.DepthOfComponent( aComponentIndex ); |
|
350 |
|
351 // Output only the first component to screen |
|
352 if( aComponentIndex == 0 ) |
|
353 { |
|
354 WriteOutputFile( aTile, aComponentIndex, subbandSize, bitdepth ); |
|
355 } |
|
356 iComponents[aComponentIndex]->FreeData(); |
|
357 } |
|
358 } |
|
359 } |
|
360 |
|
361 // ----------------------------------------------------------------------------- |
|
362 // CJ2kImageWriter::OutputImageL |
|
363 // Output the image related to the component of the tile |
|
364 // (other items were commented in a header). |
|
365 // ----------------------------------------------------------------------------- |
|
366 // |
|
367 void CJ2kImageWriter::OutputImageL( CJ2kTileInfo& aTile, TUint16 aComponentIndex, |
|
368 const TSize& aSize ) |
|
369 { |
|
370 TUint8 bitdepth = 0; |
|
371 TUint16 c = 0; |
|
372 CJ2kComponentInfo& componentInfo = CONST_CAST( CJ2kComponentInfo&, aTile.ComponentAt( aComponentIndex ) ); |
|
373 |
|
374 TInt16 reducedLevels = (TInt16)( componentInfo.Levels() - iImageInfo.LevelDrop() ); |
|
375 if ( reducedLevels < 0 ) |
|
376 { |
|
377 reducedLevels = 0; |
|
378 } |
|
379 |
|
380 CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, componentInfo.SubbandAt( (TUint8)reducedLevels ) ); |
|
381 if ( subband->SubbandResLevel() != 0 ) |
|
382 { |
|
383 subband = subband->Parent(); |
|
384 } |
|
385 |
|
386 TSize subbandSize = aSize; |
|
387 |
|
388 // Note that in case of component truncation color transform is not performed |
|
389 if ( iImageInfo.ComponentDrop() ) |
|
390 { |
|
391 iNumComponents = 1; |
|
392 } |
|
393 else // Only perform color transform if we don't drop components |
|
394 { |
|
395 // Perform the color transfrom |
|
396 if ( aComponentIndex == 2 && aTile.ColorTransformation() ) |
|
397 { |
|
398 // Perform the inverse color transform |
|
399 if ( aTile.ComponentAt( 0 ).IsReversible() ) // If RCT is used |
|
400 { |
|
401 PerformInverseRCT( subbandSize ); |
|
402 } |
|
403 else |
|
404 { |
|
405 PerformInverseICT( subbandSize ); |
|
406 } |
|
407 } |
|
408 } |
|
409 |
|
410 // Check if palettes are used. If so, get the number of output channels |
|
411 if ( iJ2kInfo.iCMPList.Count() ) |
|
412 { |
|
413 TUint16 numCSComp = iImageInfo.NumOfComponents(); |
|
414 |
|
415 // Allocate more memory for data if needed |
|
416 if ( iNumComponents > numCSComp ) |
|
417 { |
|
418 for ( c = numCSComp; c < iNumComponents; c++ ) |
|
419 { |
|
420 // Allocate memory for component data |
|
421 iComponents[c]->AllocDataL( subbandSize ); |
|
422 } |
|
423 } |
|
424 // Check if we have all the necessary channels for component mapping |
|
425 if ( aComponentIndex == ( numCSComp - 1 ) ) |
|
426 { |
|
427 MapComponentsL( numCSComp, reducedLevels, subbandSize, aTile ); |
|
428 } |
|
429 } |
|
430 |
|
431 // We start the output of files: |
|
432 if ( iSingleFileOutput ) |
|
433 { |
|
434 if ( iNumComponents == 3 ) // 3 comp to combine |
|
435 { |
|
436 if( !iColorPixelBlock ) |
|
437 { |
|
438 // Allocate memory for block of color pixels |
|
439 iColorPixelBlock = STATIC_CAST( TRgb*, User::AllocL( 2 * KPixelsBlock * sizeof( TRgb ) ) ); |
|
440 } |
|
441 |
|
442 CombineOutputFile( aTile, subbandSize ); |
|
443 for ( c = 0; c < iNumComponents; c++ ) |
|
444 { |
|
445 iComponents[c]->FreeData(); |
|
446 } |
|
447 } |
|
448 else // 1 comp to output |
|
449 { |
|
450 if ( iImageInfo.ComponentDrop() ) |
|
451 { |
|
452 c = (TUint16)( iImageInfo.ComponentDrop() - 1 ); |
|
453 } |
|
454 else |
|
455 { |
|
456 c = aComponentIndex; |
|
457 } |
|
458 |
|
459 bitdepth = iImageInfo.DepthOfComponent( c ); |
|
460 |
|
461 if( !iMonoPixelBlock ) |
|
462 { |
|
463 // Allocate memory for block of grayscale pixels |
|
464 iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) ); |
|
465 } |
|
466 |
|
467 // Output a single component |
|
468 WriteOutputFile( aTile, c, subbandSize, bitdepth ); |
|
469 iComponents[c]->FreeData(); |
|
470 } |
|
471 } |
|
472 else |
|
473 { |
|
474 // Write out three independent output files |
|
475 if( !iMonoPixelBlock ) |
|
476 { |
|
477 // Allocate memory for block of grayscale pixels |
|
478 iMonoPixelBlock = STATIC_CAST( TUint32*, User::AllocL( KPixelsBlock * sizeof( TUint32 ) ) ); |
|
479 } |
|
480 |
|
481 if ( aComponentIndex == 2 && aTile.ColorTransformation() ) |
|
482 { |
|
483 for ( c = 0; c < 3; c++ ) |
|
484 { |
|
485 bitdepth = iImageInfo.DepthOfComponent( c ); |
|
486 |
|
487 // Output single files |
|
488 WriteOutputFile( aTile, c, subbandSize, bitdepth ); |
|
489 iComponents[c]->FreeData(); |
|
490 } |
|
491 } |
|
492 else if ( iJ2kInfo.iCMPList.Count() ) |
|
493 { |
|
494 for ( c = 0; c < iNumComponents; c++ ) |
|
495 { |
|
496 // Bitdepth is the lowest seven bits plus one for palettes |
|
497 bitdepth = (TUint8)( ( iJ2kInfo.iPalette.iBList[0] & 0x7f )+1 ); |
|
498 |
|
499 // Output single files |
|
500 WriteOutputFile( aTile, c, subbandSize, bitdepth ); |
|
501 iComponents[c]->FreeData(); |
|
502 } |
|
503 } |
|
504 else |
|
505 { |
|
506 bitdepth = iImageInfo.DepthOfComponent( aComponentIndex ); |
|
507 |
|
508 // Output only the first component to screen |
|
509 if( aComponentIndex == 0 ) |
|
510 { |
|
511 WriteOutputFile( aTile, aComponentIndex, subbandSize, bitdepth ); |
|
512 } |
|
513 |
|
514 iComponents[aComponentIndex]->FreeData(); |
|
515 } |
|
516 } |
|
517 } |
|
518 |
|
519 // ----------------------------------------------------------------------------- |
|
520 // CJ2kImageWriter::OutputBlockL |
|
521 // Output the image related to the component of the tile |
|
522 // (other items were commented in a header). |
|
523 // ----------------------------------------------------------------------------- |
|
524 // |
|
525 void CJ2kImageWriter::OutputBlockL( CJ2kTileInfo& aTile, TUint16 aComponentIndex, |
|
526 TInt32 aBlockXCoord, TInt32 aBlockYCoord, |
|
527 TSize aFirstCompSize, TSize aThisCompSize ) |
|
528 { |
|
529 TUint32 tileIndex = 0; |
|
530 CJ2kWriterComponentInfo* currentComponent = iComponents[aComponentIndex]; |
|
531 TPoint tmpTileStart( 0, 0 ); |
|
532 TPoint tmpTileStart1( 0, 0 ); |
|
533 TPoint tmpTileStart2( 0, 0 ); |
|
534 |
|
535 CJ2kComponentInfo& componentInfo = CONST_CAST( CJ2kComponentInfo&, aTile.ComponentAt( aComponentIndex ) ); |
|
536 TSize outputSize( 0, 0 ); |
|
537 |
|
538 tileIndex = aTile.SotMarker().iIsot; |
|
539 |
|
540 // Update the subband size ( which will be used to compute output size ) |
|
541 TInt16 reducedLevels = (TInt16)( componentInfo.Levels() - iImageInfo.LevelDrop() ); |
|
542 if ( reducedLevels < 0 ) |
|
543 { |
|
544 |
|
545 TInt32 i; |
|
546 TInt32 stepSize = 1; |
|
547 |
|
548 // Compute the output step size, the stepSize indicates how much more |
|
549 // resolution has to be dropped if the image didn't have enough wavelet |
|
550 // levels to begin with. One indicates no extra resolution drop (write |
|
551 // each sample) and for each extra drop skip half of the samples, i.e. |
|
552 // stepSize is 2^extraLevels in case extra drop is needed. |
|
553 |
|
554 // Compute the stepSize |
|
555 for ( i = 0; i < (-reducedLevels); i++ ) |
|
556 { |
|
557 // Double the step size for every extra level dropped. |
|
558 stepSize *= 2; |
|
559 } |
|
560 |
|
561 // Adjust the block coordinates, so that next block is drawn to the right coordinates |
|
562 aBlockXCoord /= stepSize; |
|
563 aBlockYCoord /= stepSize; |
|
564 |
|
565 reducedLevels = 0; |
|
566 } |
|
567 |
|
568 CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, componentInfo.SubbandAt( (TUint8)reducedLevels ) ); |
|
569 if ( subband->SubbandResLevel() != 0 ) |
|
570 { |
|
571 subband = subband->Parent(); |
|
572 } |
|
573 |
|
574 // If we are going to combine the output into a single file we must use the first components size and |
|
575 // tile-start values ( other components might be sub sampled ). |
|
576 if( iSingleFileOutput && iNumComponents == 3 ) |
|
577 { |
|
578 // Update the tileStartCoordinates |
|
579 tmpTileStart = iComponents[0]->TileStartAt( aTile.SotMarker().iIsot ); |
|
580 iComponents[0]->iTileStartList[tileIndex].iX += aBlockXCoord; |
|
581 iComponents[0]->iTileStartList[tileIndex].iY += aBlockYCoord; |
|
582 |
|
583 // Also store and update the tileStartCoordinates of the other two components, as they may be output to file |
|
584 tmpTileStart1 = iComponents[1]->TileStartAt( aTile.SotMarker().iIsot ); |
|
585 iComponents[1]->iTileStartList[tileIndex].iX += aBlockXCoord; |
|
586 iComponents[1]->iTileStartList[tileIndex].iY += aBlockYCoord; |
|
587 tmpTileStart2 = iComponents[2]->TileStartAt( aTile.SotMarker().iIsot ); |
|
588 iComponents[2]->iTileStartList[tileIndex].iX += aBlockXCoord; |
|
589 iComponents[2]->iTileStartList[tileIndex].iY += aBlockYCoord; |
|
590 |
|
591 outputSize = aFirstCompSize; |
|
592 } |
|
593 else |
|
594 { |
|
595 // Update the tileStartCoordinates |
|
596 tmpTileStart = currentComponent->TileStartAt( aTile.SotMarker().iIsot ); |
|
597 currentComponent->iTileStartList[tileIndex].iX += aBlockXCoord; |
|
598 currentComponent->iTileStartList[tileIndex].iY += aBlockYCoord; |
|
599 |
|
600 outputSize = aThisCompSize; |
|
601 } |
|
602 |
|
603 // Call OutputImageL with the changed parameters |
|
604 OutputImageL( aTile, aComponentIndex, outputSize ); |
|
605 |
|
606 // Restore the original values |
|
607 if( iSingleFileOutput && iNumComponents == 3 ) |
|
608 { |
|
609 iComponents[0]->iTileStartList[tileIndex] = tmpTileStart; |
|
610 iComponents[1]->iTileStartList[tileIndex] = tmpTileStart1; |
|
611 iComponents[2]->iTileStartList[tileIndex] = tmpTileStart2; |
|
612 } |
|
613 else |
|
614 { |
|
615 currentComponent->iTileStartList[tileIndex] = tmpTileStart; |
|
616 } |
|
617 } |
|
618 |
|
619 // ----------------------------------------------------------------------------- |
|
620 // CJ2kImageWriter::SetNewImageProcessor |
|
621 // Set the image processor of the image write |
|
622 // (other items were commented in a header). |
|
623 // ----------------------------------------------------------------------------- |
|
624 // |
|
625 void CJ2kImageWriter::SetNewImageProcessor( CImageProcessor* aImageProcessor ) |
|
626 { |
|
627 iImageProcessor = aImageProcessor; |
|
628 } |
|
629 |
|
630 // ----------------------------------------------------------------------------- |
|
631 // CJ2kImageWriter::SingleFileOutput |
|
632 // Get the single output file |
|
633 // (other items were commented in a header). |
|
634 // ----------------------------------------------------------------------------- |
|
635 // |
|
636 TUint8 CJ2kImageWriter::SingleFileOutput() const |
|
637 { |
|
638 return iSingleFileOutput; |
|
639 } |
|
640 |
|
641 // ----------------------------------------------------------------------------- |
|
642 // CJ2kImageWriter::CSCode |
|
643 // Get the EnumCS |
|
644 // (other items were commented in a header). |
|
645 // ----------------------------------------------------------------------------- |
|
646 // |
|
647 TUint8 CJ2kImageWriter::CSCode() const |
|
648 { |
|
649 return (TUint8)iJ2kInfo.iEnumCS; |
|
650 } |
|
651 |
|
652 // ----------------------------------------------------------------------------- |
|
653 // CJ2kImageWriter::CJ2kImageWriter |
|
654 // C++ default constructor can NOT contain any code, that |
|
655 // might leave. |
|
656 // ----------------------------------------------------------------------------- |
|
657 // |
|
658 CJ2kImageWriter::CJ2kImageWriter( CImageProcessor* aImageProcessor, |
|
659 CJ2kImageInfo& aImageInfo, |
|
660 TJ2kInfo& aJ2kInfo ) : |
|
661 iImageProcessor( aImageProcessor ), |
|
662 iImageInfo( aImageInfo ), |
|
663 iJ2kInfo( aJ2kInfo ) |
|
664 { |
|
665 } |
|
666 |
|
667 // ----------------------------------------------------------------------------- |
|
668 // CJ2kImageWriter::ConstructL |
|
669 // Symbian 2nd phase constructor can leave. |
|
670 // ----------------------------------------------------------------------------- |
|
671 // |
|
672 void CJ2kImageWriter::ConstructL() |
|
673 { |
|
674 TInt32 i = 0; |
|
675 |
|
676 TSizMarker& sizMarker = CONST_CAST( TSizMarker&, iImageInfo.SizMarker() ); |
|
677 |
|
678 iNumComponents = iImageInfo.NumOfComponents(); |
|
679 |
|
680 if ( iJ2kInfo.iCMPList.Count() ) |
|
681 { |
|
682 iNumComponents = (TUint16)( iJ2kInfo.iCMPList.Count() ); |
|
683 |
|
684 if(iNumComponents < iImageInfo.NumOfComponents()) |
|
685 { |
|
686 // Every component in the codestream must have a mapping defined |
|
687 User::Leave( KErrCorrupt ); |
|
688 } |
|
689 } |
|
690 |
|
691 for ( i = 0; i < iNumComponents; i++ ) |
|
692 { |
|
693 CJ2kWriterComponentInfo *info = new ( ELeave ) CJ2kWriterComponentInfo; |
|
694 CleanupStack::PushL( info ); |
|
695 User::LeaveIfError( iComponents.Append( info ) ); |
|
696 CleanupStack::Pop(1); |
|
697 } |
|
698 |
|
699 if ( iNumComponents == 3 ) |
|
700 { |
|
701 iSingleFileOutput = 1; |
|
702 if ( sizMarker.iXRsiz[1] == 2 * sizMarker.iXRsiz[0] && |
|
703 sizMarker.iXRsiz[2] == 2 * sizMarker.iXRsiz[0] ) |
|
704 { |
|
705 if ( sizMarker.iYRsiz[1] == 2 * sizMarker.iYRsiz[0] && |
|
706 sizMarker.iYRsiz[2] == 2 * sizMarker.iYRsiz[0] ) |
|
707 { |
|
708 iFileType = KYUV420; |
|
709 } |
|
710 else |
|
711 { |
|
712 iFileType = KYUV422; |
|
713 } |
|
714 } |
|
715 } |
|
716 else if ( iNumComponents == 1 ) |
|
717 { |
|
718 iFileType = KRGB; |
|
719 } |
|
720 |
|
721 if ( iImageInfo.ComponentDrop() ) //lint !e961 no else is needed here at the end of if...else if |
|
722 { |
|
723 iFileType = KRGB; |
|
724 } |
|
725 |
|
726 if ( iJ2kInfo.iICCProfile ) |
|
727 { |
|
728 iICCProfile = ETrue; |
|
729 InitializeICCProfileL(); |
|
730 } |
|
731 |
|
732 // Initialize the output parameters |
|
733 if ( iImageInfo.Crop() ) |
|
734 { |
|
735 // Currently do nothing. |
|
736 } |
|
737 else |
|
738 { |
|
739 InitializeOutputParametersL(); |
|
740 } |
|
741 } |
|
742 |
|
743 // ----------------------------------------------------------------------------- |
|
744 // CJ2kImageWriter::PerformInverseRCT |
|
745 // Perform the inverse reversible color transformation |
|
746 // (other items were commented in a header). |
|
747 // ----------------------------------------------------------------------------- |
|
748 // |
|
749 void CJ2kImageWriter::PerformInverseRCT( const TSize& aSize ) |
|
750 { |
|
751 TInt32 col = 0; |
|
752 TPrecInt red = 0; |
|
753 TPrecInt green = 0; |
|
754 TPrecInt blue = 0; |
|
755 TPrecInt** block1 = iComponents[0]->iData; |
|
756 TPrecInt** block2 = iComponents[1]->iData; |
|
757 TPrecInt** block3 = iComponents[2]->iData; |
|
758 |
|
759 for ( TInt32 row = 0; row < aSize.iHeight; row++ ) |
|
760 { |
|
761 for ( col = 0; col < aSize.iWidth; col++ ) |
|
762 { |
|
763 red = block1[row][col]; |
|
764 green = block2[row][col]; |
|
765 blue = block3[row][col]; |
|
766 |
|
767 block2[row][col] = red - ( ( blue + green ) >> 2 ); //lint !e704 shifting is OK. |
|
768 block1[row][col] = blue + block2[row][col]; |
|
769 block3[row][col] = green + block2[row][col]; |
|
770 } |
|
771 } |
|
772 } |
|
773 |
|
774 // ----------------------------------------------------------------------------- |
|
775 // CJ2kImageWriter::PerformInverseICT |
|
776 // Perform the inverse irreversible color transformation |
|
777 // (other items were commented in a header). |
|
778 // ----------------------------------------------------------------------------- |
|
779 // |
|
780 void CJ2kImageWriter::PerformInverseICT( const TSize& aSize ) |
|
781 { |
|
782 TInt32 col = 0; |
|
783 TPrecInt red = 0; |
|
784 TPrecInt green = 0; |
|
785 TPrecInt blue = 0; |
|
786 TPrecInt** block1 = iComponents[0]->iData; |
|
787 TPrecInt** block2 = iComponents[1]->iData; |
|
788 TPrecInt** block3 = iComponents[2]->iData; |
|
789 |
|
790 for ( TInt32 row = 0; row < aSize.iHeight; row++ ) |
|
791 { |
|
792 for ( col = 0; col < aSize.iWidth; col++ ) |
|
793 { |
|
794 red = block1[row][col]; |
|
795 green = block2[row][col]; |
|
796 blue = block3[row][col]; |
|
797 InverseICTTransform( red, green, blue, block1[row][col], block2[row][col], block3[row][col] ); |
|
798 } |
|
799 } |
|
800 } |
|
801 |
|
802 // ----------------------------------------------------------------------------- |
|
803 // CJ2kImageWriter::InverseICTTransform |
|
804 // Inverse irreversible color transformation |
|
805 // (other items were commented in a header). |
|
806 // ----------------------------------------------------------------------------- |
|
807 // |
|
808 void CJ2kImageWriter::InverseICTTransform( TPrecInt aY, TPrecInt aU, TPrecInt aV, |
|
809 TPrecInt& aR, TPrecInt& aG, TPrecInt& aB ) |
|
810 { |
|
811 aR = ( TPrecInt )( ( ( ( aY << KFractionBits ) + |
|
812 ( KIctCoefficient11 * aV ) ) + KOffset ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
813 aG = ( TPrecInt )( ( ( ( aY << KFractionBits ) + |
|
814 ( KIctCoefficient21 * aU ) + ( KIctCoefficient22 * aV ) ) + KOffset ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
815 aB = ( TPrecInt )( ( ( ( aY << KFractionBits ) + |
|
816 ( KIctCoefficient31 * aU ) ) + KOffset ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
817 } |
|
818 |
|
819 // ----------------------------------------------------------------------------- |
|
820 // CJ2kImageWriter::InverseICTTransform |
|
821 // Inverse irreversible color transformation. |
|
822 // Performs fast transform and outputs even and odd samples at the same time |
|
823 // (other items were commented in a header). |
|
824 // ----------------------------------------------------------------------------- |
|
825 // |
|
826 void CJ2kImageWriter::InverseICTTransform( TPrecInt aY1, TPrecInt aY2, TPrecInt aU, TPrecInt aV, |
|
827 TPrecInt& aR1, TPrecInt& aG1, TPrecInt& aB1, |
|
828 TPrecInt& aR2, TPrecInt& aG2, TPrecInt& aB2) |
|
829 { |
|
830 TInt32 y1Shifted; |
|
831 TInt32 y2Shifted; |
|
832 TInt32 rTempValue; |
|
833 TInt32 gTempValue; |
|
834 TInt32 bTempValue; |
|
835 |
|
836 y1Shifted = ( aY1 << KFractionBits ); |
|
837 y2Shifted = ( aY2 << KFractionBits ); |
|
838 rTempValue = ( KIctCoefficient11 * aV ) + KOffset; |
|
839 gTempValue = ( KIctCoefficient21 * aU ) + ( KIctCoefficient22 * aV ) + KOffset; |
|
840 bTempValue = ( KIctCoefficient31 * aU ) + KOffset; |
|
841 |
|
842 aR1 = ( TPrecInt )( ( y1Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
843 aG1 = ( TPrecInt )( ( y1Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
844 aB1 = ( TPrecInt )( ( y1Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
845 aR2 = ( TPrecInt )( ( y2Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
846 aG2 = ( TPrecInt )( ( y2Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
847 aB2 = ( TPrecInt )( ( y2Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
848 } |
|
849 |
|
850 // ----------------------------------------------------------------------------- |
|
851 // CJ2kImageWriter::InverseICTFastYUV420Transform |
|
852 // Inverse irreversible color transformation |
|
853 // Performs fast transform and outputs even and odd samples on even and odd |
|
854 // rows (four samples) at the same time. |
|
855 // (other items were commented in a header). |
|
856 // ----------------------------------------------------------------------------- |
|
857 // |
|
858 void CJ2kImageWriter::InverseICTTransform( TPrecInt aY1, TPrecInt aY2, TPrecInt aY3, TPrecInt aY4, |
|
859 TPrecInt aU, TPrecInt aV, |
|
860 TPrecInt& aR1, TPrecInt& aG1, TPrecInt& aB1, |
|
861 TPrecInt& aR2, TPrecInt& aG2, TPrecInt& aB2, |
|
862 TPrecInt& aR3, TPrecInt& aG3, TPrecInt& aB3, |
|
863 TPrecInt& aR4, TPrecInt& aG4, TPrecInt& aB4) |
|
864 { |
|
865 TInt32 y1Shifted; |
|
866 TInt32 y2Shifted; |
|
867 TInt32 y3Shifted; |
|
868 TInt32 y4Shifted; |
|
869 TInt32 rTempValue; |
|
870 TInt32 gTempValue; |
|
871 TInt32 bTempValue; |
|
872 |
|
873 y1Shifted = ( aY1 << KFractionBits ); |
|
874 y2Shifted = ( aY2 << KFractionBits ); |
|
875 y3Shifted = ( aY3 << KFractionBits ); |
|
876 y4Shifted = ( aY4 << KFractionBits ); |
|
877 rTempValue = ( KIctCoefficient11 * aV ) + KOffset; |
|
878 gTempValue = ( KIctCoefficient21 * aU ) + ( KIctCoefficient22 * aV ) + KOffset; |
|
879 bTempValue = ( KIctCoefficient31 * aU ) + KOffset; |
|
880 |
|
881 aR1 = ( TPrecInt )( ( y1Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
882 aG1 = ( TPrecInt )( ( y1Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
883 aB1 = ( TPrecInt )( ( y1Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
884 aR2 = ( TPrecInt )( ( y2Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
885 aG2 = ( TPrecInt )( ( y2Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
886 aB2 = ( TPrecInt )( ( y2Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
887 aR3 = ( TPrecInt )( ( y3Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
888 aG3 = ( TPrecInt )( ( y3Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
889 aB3 = ( TPrecInt )( ( y3Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
890 aR4 = ( TPrecInt )( ( y4Shifted + rTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
891 aG4 = ( TPrecInt )( ( y4Shifted + gTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
892 aB4 = ( TPrecInt )( ( y4Shifted + bTempValue ) >> KFractionBits ); //lint !e704 shifting is OK. |
|
893 } |
|
894 |
|
895 // ----------------------------------------------------------------------------- |
|
896 // CJ2kImageWriter::InitializeICCProfileL |
|
897 // Initialize the ICC profile from JP2 file format ( iJ2kInfo ) |
|
898 // (other items were commented in a header). |
|
899 // ----------------------------------------------------------------------------- |
|
900 // |
|
901 void CJ2kImageWriter::InitializeICCProfileL() |
|
902 { |
|
903 const TUint8* iterator = iJ2kInfo.iICCProfile->Ptr(); |
|
904 TUint8* origin = CONST_CAST( TUint8*, iJ2kInfo.iICCProfile->Ptr() ); |
|
905 |
|
906 // Skip the first 128 bytes |
|
907 iterator += KICCSkipBytes; |
|
908 |
|
909 // Get the tag count |
|
910 TUint32 tagCount = PtrReadUtil::ReadBigEndianUint32Inc( iterator ); |
|
911 |
|
912 TUint32 tagSignature = 0; |
|
913 TUint32 tagSize = 0; |
|
914 TUint32 redXYZOffset = 0; |
|
915 TUint32 greenXYZOffset = 0; |
|
916 TUint32 blueXYZOffset = 0; |
|
917 TUint32 trcOffset = 0; |
|
918 TUint32 index = 0; |
|
919 TInt32 i = 0; |
|
920 TInt entries = 0; |
|
921 HBufC16* redTRC = 0; |
|
922 HBufC16* greenTRC = 0; |
|
923 HBufC16* blueTRC = 0; |
|
924 HBufC16* grayTRC = 0; |
|
925 TUint8 isColor = EFalse; |
|
926 TReal value = 0.0; |
|
927 |
|
928 for ( index = 0; index < tagCount; ++index ) |
|
929 { |
|
930 tagSignature = PtrReadUtil::ReadBigEndianUint32Inc( iterator ); |
|
931 switch ( tagSignature ) |
|
932 { |
|
933 case KRedMatrixTag: |
|
934 { |
|
935 redXYZOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 8; |
|
936 iterator += 4; |
|
937 break; |
|
938 } |
|
939 case KGreenMatrixTag: |
|
940 { |
|
941 greenXYZOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 8; |
|
942 iterator += 4; |
|
943 break; |
|
944 } |
|
945 case KBlueMatrixTag: |
|
946 { |
|
947 blueXYZOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 8; |
|
948 iterator += 4; |
|
949 break; |
|
950 } |
|
951 case KRedTrcTag: |
|
952 { |
|
953 isColor = ETrue; |
|
954 trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12; |
|
955 tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12; |
|
956 entries = tagSize >> 1; |
|
957 redTRC = HBufC16::NewLC( entries ); |
|
958 TPtr16 tmpPtr = ( redTRC->Des() ); |
|
959 |
|
960 // Read bytes into the TRC values array |
|
961 for( i = 0; i < entries; i++ ) |
|
962 { |
|
963 tmpPtr.Append( (TUint16)( ( origin[trcOffset + 2 * i] << 8 ) | |
|
964 origin[trcOffset + 2 * i + 1] ) ); |
|
965 } |
|
966 |
|
967 break; |
|
968 } |
|
969 case KGreenTrcTag: |
|
970 { |
|
971 isColor = ETrue; |
|
972 trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12; |
|
973 tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12; |
|
974 entries = tagSize >> 1; |
|
975 greenTRC = HBufC16::NewLC( entries ); |
|
976 TPtr16 tmpPtr = ( greenTRC->Des() ); |
|
977 |
|
978 // Read bytes into the TRC values array |
|
979 for( i = 0; i < entries; i++ ) |
|
980 { |
|
981 tmpPtr.Append( (TUint16)( ( origin[trcOffset + 2 * i] << 8 ) | |
|
982 origin[trcOffset + 2 * i + 1] ) ); |
|
983 } |
|
984 |
|
985 break; |
|
986 } |
|
987 case KBlueTrcTag: |
|
988 { |
|
989 isColor = ETrue; |
|
990 trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12; |
|
991 tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12; |
|
992 entries = tagSize >> 1; |
|
993 blueTRC = HBufC16::NewLC( entries ); |
|
994 TPtr16 tmpPtr = ( blueTRC->Des() ); |
|
995 |
|
996 // Read bytes into the TRC values array |
|
997 for( i = 0; i < entries; i++ ) |
|
998 { |
|
999 tmpPtr.Append( (TUint16)( ( origin[trcOffset+2*i] << 8 ) | |
|
1000 origin[trcOffset+2*i+1] ) ); |
|
1001 } |
|
1002 |
|
1003 break; |
|
1004 } |
|
1005 case KGrayTrcTag: |
|
1006 { |
|
1007 trcOffset = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) + 12; |
|
1008 tagSize = PtrReadUtil::ReadBigEndianUint32Inc( iterator ) - 12; |
|
1009 entries = tagSize >> 1; |
|
1010 grayTRC = HBufC16::NewLC( entries ); |
|
1011 TPtr16 tmpPtr = ( grayTRC->Des() ); |
|
1012 |
|
1013 // Read bytes into the TRC values array |
|
1014 for( i = 0; i < entries; i++ ) |
|
1015 { |
|
1016 tmpPtr.Append( (TUint16)( ( origin[trcOffset + 2 * i] << 8 ) | |
|
1017 origin[trcOffset + 2 * i + 1] ) ); |
|
1018 } |
|
1019 |
|
1020 break; |
|
1021 } |
|
1022 default: |
|
1023 { |
|
1024 iterator += 8; |
|
1025 break; |
|
1026 } |
|
1027 } |
|
1028 } |
|
1029 |
|
1030 TReal gamma = 0.0; |
|
1031 TReal maxInput = 0.0; |
|
1032 TReal src = 0.0; |
|
1033 TUint32 numPerSample = 0; |
|
1034 TUint32 lutSize = 0; |
|
1035 if ( iJ2kInfo.iBPCList.Count() ) |
|
1036 { |
|
1037 lutSize = 1 << ( iJ2kInfo.iBPCList[0] & 0x7f + 1 ); |
|
1038 } |
|
1039 else |
|
1040 { |
|
1041 lutSize = 1 << iImageInfo.DepthOfComponent( 0 ); |
|
1042 } |
|
1043 |
|
1044 if ( isColor ) |
|
1045 { |
|
1046 // Read the RGB( lin. ) -> XYZ conversion matrix coefficients |
|
1047 // The matrix is the following: |
|
1048 // _ _ |
|
1049 // | redX greenX blueX | |
|
1050 // | redY greenY blueY | |
|
1051 // | redZ greenZ blueZ | |
|
1052 // |_ _| |
|
1053 // |
|
1054 TReal redX = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + redXYZOffset ) / KDivisor; |
|
1055 TReal redY = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + redXYZOffset + 4 ) / KDivisor; |
|
1056 TReal redZ = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + redXYZOffset + 8 ) / KDivisor; |
|
1057 |
|
1058 TReal greenX = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + greenXYZOffset ) / KDivisor; |
|
1059 TReal greenY = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + greenXYZOffset + 4 ) / KDivisor; |
|
1060 TReal greenZ = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + greenXYZOffset + 8 ) / KDivisor; |
|
1061 |
|
1062 TReal blueX = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + blueXYZOffset ) / KDivisor; |
|
1063 TReal blueY = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + blueXYZOffset + 4 ) / KDivisor; |
|
1064 TReal blueZ = ( TReal )PtrReadUtil::ReadBigEndianUint32( origin + blueXYZOffset + 8 ) / KDivisor; |
|
1065 |
|
1066 // Combine the RGB( lin. ) -> XYZ and the XYZ -> sRGB( lin. ) conversions, i.e. |
|
1067 // perform the matrix multiplication. Store the result in "iMatrix". |
|
1068 iMatrix[0] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB00 * redX + KSRGB01 * redY + KSRGB02 * redZ ) ); |
|
1069 iMatrix[1] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB00 * greenX + KSRGB01 * greenY + KSRGB02 * greenZ ) ); |
|
1070 iMatrix[2] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB00 * blueX + KSRGB01 * blueY + KSRGB02 * blueZ ) ); |
|
1071 |
|
1072 iMatrix[3] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB10 * redX + KSRGB11 * redY + KSRGB12 * redZ ) ); |
|
1073 iMatrix[4] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB10 * greenX + KSRGB11 * greenY + KSRGB12 * greenZ ) ); |
|
1074 iMatrix[5] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB10 * blueX + KSRGB11 * blueY + KSRGB12 * blueZ ) ); |
|
1075 |
|
1076 iMatrix[6] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB20 * redX + KSRGB21 * redY + KSRGB22 * redZ ) ); |
|
1077 iMatrix[7] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB20 * greenX + KSRGB21 * greenY + KSRGB22 * greenZ ) ); |
|
1078 iMatrix[8] = ( TInt32 )( KSRGBMaxIntShifted * ( KSRGB20 * blueX + KSRGB21 * blueY + KSRGB22 * blueZ ) ); |
|
1079 |
|
1080 iRedTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) ); |
|
1081 if ( redTRC->Length() == 1 ) |
|
1082 { |
|
1083 gamma = (TReal)( *redTRC )[0] / KGamma; |
|
1084 maxInput = (TReal)( lutSize - 1 ); |
|
1085 for ( index = 0; index < lutSize; ++index ) |
|
1086 { |
|
1087 src = index / maxInput; |
|
1088 Math::Pow( value, src, gamma ); |
|
1089 iRedTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 ); |
|
1090 } |
|
1091 } |
|
1092 else |
|
1093 { |
|
1094 numPerSample = lutSize / (TUint32)( redTRC->Length() ); |
|
1095 if ( numPerSample ) |
|
1096 { |
|
1097 for ( index = 0; index < lutSize; ++index ) |
|
1098 { |
|
1099 value = ( *redTRC )[index / numPerSample] / KDivisor; |
|
1100 iRedTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 ); |
|
1101 } |
|
1102 } |
|
1103 } |
|
1104 |
|
1105 if ( iJ2kInfo.iBPCList.Count() ) |
|
1106 { |
|
1107 lutSize = 1 << ( iJ2kInfo.iBPCList[1] & 0x7f + 1 ); |
|
1108 } |
|
1109 else |
|
1110 { |
|
1111 lutSize = 1 << iImageInfo.DepthOfComponent( 1 ); |
|
1112 } |
|
1113 |
|
1114 iGreenTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) ); |
|
1115 if ( greenTRC->Length() == 1 ) |
|
1116 { |
|
1117 gamma = (TReal)( *greenTRC )[0] / KGamma; |
|
1118 maxInput = (TReal)( lutSize - 1 ); |
|
1119 for ( index = 0; index < lutSize; ++index ) |
|
1120 { |
|
1121 src = index / maxInput; |
|
1122 Math::Pow( value, src, gamma ); |
|
1123 iGreenTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 ); |
|
1124 } |
|
1125 } |
|
1126 else |
|
1127 { |
|
1128 numPerSample = lutSize / (TUint32)( greenTRC->Length() ); |
|
1129 if ( numPerSample ) |
|
1130 { |
|
1131 for ( index = 0; index < lutSize; ++index ) |
|
1132 { |
|
1133 value = ( *greenTRC )[index / numPerSample] / KDivisor; |
|
1134 iGreenTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 ); |
|
1135 } |
|
1136 } |
|
1137 } |
|
1138 |
|
1139 if ( iJ2kInfo.iBPCList.Count() ) |
|
1140 { |
|
1141 lutSize = 1 << ( iJ2kInfo.iBPCList[2] & 0x7f + 1 ); |
|
1142 } |
|
1143 else |
|
1144 { |
|
1145 lutSize = 1 << iImageInfo.DepthOfComponent( 2 ); |
|
1146 } |
|
1147 |
|
1148 iBlueTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) ); |
|
1149 if ( blueTRC->Length() == 1 ) |
|
1150 { |
|
1151 gamma = (TReal)( *blueTRC )[0] / KGamma; |
|
1152 maxInput = (TReal)( lutSize - 1 ); |
|
1153 for ( index = 0; index < lutSize; ++index ) |
|
1154 { |
|
1155 src = index / maxInput; |
|
1156 Math::Pow( value, src, gamma ); |
|
1157 iBlueTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 ); |
|
1158 } |
|
1159 } |
|
1160 else |
|
1161 { |
|
1162 numPerSample = lutSize / (TUint32)( blueTRC->Length() ); |
|
1163 if ( numPerSample ) |
|
1164 { |
|
1165 for ( index = 0; index < lutSize; ++index ) |
|
1166 { |
|
1167 value = ( *blueTRC )[index / numPerSample] / KDivisor; |
|
1168 iBlueTRCLut[index] = (TInt32)( value * KTRCShiftMultiplier + 0.5 ); |
|
1169 } |
|
1170 } |
|
1171 } |
|
1172 } |
|
1173 else |
|
1174 { |
|
1175 |
|
1176 iGrayTRCLut = STATIC_CAST( TInt32*, User::AllocL( lutSize * sizeof( TInt32 ) ) ); |
|
1177 if ( grayTRC->Length() == 1 ) |
|
1178 { |
|
1179 |
|
1180 gamma = (TReal)( *grayTRC )[0] / KGamma; |
|
1181 maxInput = (TReal)( lutSize - 1 ); |
|
1182 for ( index = 0; index < lutSize; ++index ) |
|
1183 { |
|
1184 src = index / maxInput; |
|
1185 Math::Pow( value, src, gamma ); |
|
1186 iGrayTRCLut[index] = (TInt32)( value*KSRGBMax+0.5 ); |
|
1187 } |
|
1188 } |
|
1189 else |
|
1190 { |
|
1191 numPerSample = lutSize / (TUint32)( grayTRC->Length() ); |
|
1192 if ( numPerSample ) |
|
1193 { |
|
1194 for ( index = 0; index < lutSize; ++index ) |
|
1195 { |
|
1196 value = ( *grayTRC )[index / numPerSample] / KDivisor; |
|
1197 iGrayTRCLut[index] = (TInt32)( value*KSRGBMax + 0.5 ); |
|
1198 } |
|
1199 } |
|
1200 } |
|
1201 } |
|
1202 |
|
1203 TUint16 cutoffIdx = 0; // Cutoff index for linear portion of output LUT |
|
1204 TReal linearSlope = 0.0; // Slope of output LUT in the linear region |
|
1205 TReal normalisation = 0.0; // Scale factor to normalize sRGB linear value to [0,1] |
|
1206 |
|
1207 // Generate the final output LUT for converting linear sRGB to non-linear sRGB. |
|
1208 // Input values are in the range [0,KSRGBMax] and output will be 8-bit [0,255]. |
|
1209 // Conversation values can be obtained in e.g. "JPEG2000 - Image compression |
|
1210 // fundamentals, standards and practice" book by Taubman and Marcellin. |
|
1211 cutoffIdx = (TUint16)( KSRGB_CUTOFF * KSRGBMax ); |
|
1212 linearSlope = 255.0 * KSRGB_SLOPE / KSRGBMax; |
|
1213 normalisation = 1.0 / KSRGBMax; |
|
1214 |
|
1215 iLinearsRGBLut = HBufC8::NewL( KSRGBMaxInt + 1 ); |
|
1216 |
|
1217 // Generate the output lin.sRGB -> non-lin.sRGB LUT |
|
1218 // Linear part |
|
1219 for ( index = 0; index <= cutoffIdx; ++index ) |
|
1220 { |
|
1221 iLinearsRGBLut->Des().Append( (TUint8)( linearSlope * index ) ); |
|
1222 } |
|
1223 |
|
1224 // Non-linear part |
|
1225 for ( ; index <= (TUint32)KSRGBMaxInt; ++index ) |
|
1226 { |
|
1227 gamma = index * normalisation; |
|
1228 Math::Pow( src, gamma , KSRGB_EXPONENT ); |
|
1229 iLinearsRGBLut->Des().Append( (TUint8)( 255 * ( KSRGB_MULTIPLIER * src - KSRGB_SUBTRACT ) ) ); |
|
1230 } |
|
1231 |
|
1232 // We do not need iJ2kInfo.iICCProfile data anymore |
|
1233 delete iJ2kInfo.iICCProfile; |
|
1234 iJ2kInfo.iICCProfile = 0; |
|
1235 |
|
1236 if ( isColor ) |
|
1237 { |
|
1238 CleanupStack::PopAndDestroy( 3 ); |
|
1239 } |
|
1240 else |
|
1241 { |
|
1242 CleanupStack::PopAndDestroy( 1 ); |
|
1243 } |
|
1244 } |
|
1245 |
|
1246 // ----------------------------------------------------------------------------- |
|
1247 // CJ2kImageWriter::InitializeOutputParametersL |
|
1248 // Initialize the output parameters |
|
1249 // (other items were commented in a header). |
|
1250 // ----------------------------------------------------------------------------- |
|
1251 // |
|
1252 void CJ2kImageWriter::InitializeOutputParametersL() |
|
1253 { |
|
1254 CJ2kWriterComponentInfo* component = 0; |
|
1255 TUint16 l = 0; |
|
1256 TUint16 m = 0; |
|
1257 TUint16 tileIndex = 0; |
|
1258 TUint16 tileYIndex = 0; |
|
1259 TPoint tileStart( 0, 0 ); |
|
1260 TUint16 numOfHorizTiles = iImageInfo.NumOfHorizTiles(); |
|
1261 TUint16 numOfVertTiles = iImageInfo.NumOfVertTiles(); |
|
1262 TRect tileCanvas( 0, 0, 0, 0 ); |
|
1263 TRect componentCanvas( 0, 0, 0, 0 ); |
|
1264 const TSizMarker &sizMarker = iImageInfo.SizMarker(); |
|
1265 TInt useHeight = 0; |
|
1266 TInt useWidth = 0; |
|
1267 |
|
1268 // Prepare the tile coordinates for output image |
|
1269 for ( TUint16 compIndex = 0; compIndex < iNumComponents; compIndex++ ) |
|
1270 { |
|
1271 component = iComponents[compIndex]; |
|
1272 |
|
1273 for ( l = 0; l < numOfVertTiles; l++ ) |
|
1274 { |
|
1275 tileYIndex = (TUint16)( l * numOfHorizTiles ); |
|
1276 |
|
1277 for ( m = 0; m < numOfHorizTiles; m++ ) |
|
1278 { |
|
1279 // Tile index |
|
1280 tileIndex = (TUint16)( tileYIndex + m ); |
|
1281 |
|
1282 // Tile canvas |
|
1283 tileCanvas.iTl = TPoint( Max( sizMarker.iXTOsiz + m * sizMarker.iXTsiz, sizMarker.iXOsiz ), |
|
1284 Max( sizMarker.iYTOsiz + l * sizMarker.iYTsiz, sizMarker.iYOsiz ) ); |
|
1285 |
|
1286 tileCanvas.iBr = TPoint( Min( sizMarker.iXTOsiz + ( m + 1 ) * sizMarker.iXTsiz, sizMarker.iXsiz ), |
|
1287 Min( sizMarker.iYTOsiz + ( l + 1 ) * sizMarker.iYTsiz, sizMarker.iYsiz ) ); |
|
1288 // Component canvas |
|
1289 componentCanvas.iTl = TPoint( TJ2kUtils::Ceil( tileCanvas.iTl.iX, sizMarker.iXRsiz[compIndex] ), |
|
1290 TJ2kUtils::Ceil( tileCanvas.iTl.iY, sizMarker.iYRsiz[compIndex] ) ); |
|
1291 |
|
1292 componentCanvas.iBr = TPoint( TJ2kUtils::Ceil( tileCanvas.iBr.iX, sizMarker.iXRsiz[compIndex] ), |
|
1293 TJ2kUtils::Ceil( tileCanvas.iBr.iY, sizMarker.iYRsiz[compIndex] ) ); |
|
1294 |
|
1295 if ( m ) |
|
1296 { |
|
1297 tileStart.iX = component->iTileStartList[tileIndex - 1].iX + useWidth; |
|
1298 } |
|
1299 else |
|
1300 { |
|
1301 tileStart.iX = 0; |
|
1302 } |
|
1303 |
|
1304 // Width to be used on the next horizontal tile |
|
1305 useWidth = componentCanvas.Width(); |
|
1306 |
|
1307 if ( l ) |
|
1308 { |
|
1309 tileStart.iY = component->iTileStartList[tileIndex - 1].iY + useHeight; |
|
1310 useHeight = 0; |
|
1311 } |
|
1312 else |
|
1313 { |
|
1314 tileStart.iY = 0; |
|
1315 } |
|
1316 |
|
1317 User::LeaveIfError( component->iTileStartList.Append( tileStart ) ); |
|
1318 } |
|
1319 // Height to be used on the next vertical tile |
|
1320 useHeight = componentCanvas.Height(); |
|
1321 } |
|
1322 } |
|
1323 } |
|
1324 |
|
1325 // ----------------------------------------------------------------------------- |
|
1326 // CJ2kImageWriter::DoICCConversion |
|
1327 // Perform XYZ to sRGB conversion with the ICC profile. |
|
1328 // (other items were commented in a header). |
|
1329 // ----------------------------------------------------------------------------- |
|
1330 // |
|
1331 void CJ2kImageWriter::DoICCConversion( TInt32 aX, |
|
1332 TInt32 aY, |
|
1333 TInt32 aZ, |
|
1334 TPrecInt& aR, |
|
1335 TPrecInt& aG, |
|
1336 TPrecInt& aB ) |
|
1337 { |
|
1338 TInt32 tmpX = 0; |
|
1339 TInt32 tmpY = 0; |
|
1340 TInt32 tmpZ = 0; |
|
1341 TInt32 tmpR = 0; |
|
1342 TInt32 tmpG = 0; |
|
1343 TInt32 tmpB = 0; |
|
1344 |
|
1345 // First perform the input linearization |
|
1346 tmpX = iRedTRCLut[aX]; |
|
1347 tmpY = iGreenTRCLut[aY]; |
|
1348 tmpZ = iBlueTRCLut[aZ]; |
|
1349 |
|
1350 // Then perform the matrix multiplication to obtain the nonlinear RGB |
|
1351 tmpR = ( iMatrix[0] * tmpX + iMatrix[1] * tmpY + iMatrix[2] * tmpZ ) >> KICCDownshift; //lint !e704 shifting is OK. |
|
1352 tmpG = ( iMatrix[3] * tmpX + iMatrix[4] * tmpY + iMatrix[5] * tmpZ ) >> KICCDownshift; //lint !e704 shifting is OK. |
|
1353 tmpB = ( iMatrix[6] * tmpX + iMatrix[7] * tmpY + iMatrix[8] * tmpZ ) >> KICCDownshift; //lint !e704 shifting is OK. |
|
1354 |
|
1355 // Get rid of values outside the range of legal values |
|
1356 tmpR = CLIP2RANGE( tmpR, 0, KSRGBMaxInt ); |
|
1357 tmpG = CLIP2RANGE( tmpG, 0, KSRGBMaxInt ); |
|
1358 tmpB = CLIP2RANGE( tmpB, 0, KSRGBMaxInt ); |
|
1359 |
|
1360 // De-linearize the output RGB values |
|
1361 aR = ( *iLinearsRGBLut )[tmpR]; |
|
1362 aG = ( *iLinearsRGBLut )[tmpG]; |
|
1363 aB = ( *iLinearsRGBLut )[tmpB]; |
|
1364 } |
|
1365 |
|
1366 // ----------------------------------------------------------------------------- |
|
1367 // CJ2kImageWriter::MapToEightBits |
|
1368 // Map data less than 8 bits to 8 bits data |
|
1369 // (other items were commented in a header). |
|
1370 // ----------------------------------------------------------------------------- |
|
1371 // |
|
1372 void CJ2kImageWriter::MapToEightBits( CJ2kWriterComponentInfo& aComponent, |
|
1373 const TSize& aSize, |
|
1374 TUint16 aBitDepth ) |
|
1375 { |
|
1376 TPrecInt* imageRow; |
|
1377 TInt32 i = 0; |
|
1378 TInt32 j = 0; |
|
1379 |
|
1380 // DC-shift is always non zero, since we map signed data to unsigned |
|
1381 if ( aBitDepth < 8 ) |
|
1382 { |
|
1383 TPrecInt upshift = KByteBits - aBitDepth; |
|
1384 TPrecInt dcShiftUp = 1 << ( KByteBits - 1 ); |
|
1385 |
|
1386 for ( i = aSize.iHeight - 1; i >= 0; i-- ) |
|
1387 { |
|
1388 imageRow = aComponent.Data()[i]; |
|
1389 for ( j = aSize.iWidth - 1; j >= 0; j-- ) |
|
1390 { |
|
1391 imageRow[j] = ( imageRow[j] * ( 1 << upshift ) ) + dcShiftUp; |
|
1392 } |
|
1393 } |
|
1394 } |
|
1395 else // The original bitdepth is more than eight |
|
1396 { |
|
1397 TPrecInt dcShift = 1 << ( aBitDepth - 1 ); |
|
1398 TPrecInt downshift = aBitDepth - KByteBits; |
|
1399 for ( i = aSize.iHeight - 1; i >= 0; --i ) |
|
1400 { |
|
1401 imageRow = aComponent.Data()[i]; |
|
1402 for ( j = aSize.iWidth - 1; j >= 0; j-- ) |
|
1403 { |
|
1404 imageRow[j] = ( imageRow[j] + dcShift ) >> downshift; //lint !e704 shifting is OK. |
|
1405 } |
|
1406 } |
|
1407 } |
|
1408 } |
|
1409 |
|
1410 // ----------------------------------------------------------------------------- |
|
1411 // CJ2kImageWriter::MapComponentsL |
|
1412 // Map data using the component mapping box from JP2 file format |
|
1413 // (other items were commented in a header). |
|
1414 // ----------------------------------------------------------------------------- |
|
1415 // |
|
1416 void CJ2kImageWriter::MapComponentsL( TUint16 aNumCSComp, |
|
1417 TUint16 aReducedLevels, |
|
1418 const TSize& aSize, |
|
1419 CJ2kTileInfo& aTile ) |
|
1420 { |
|
1421 TInt32 i = 0; |
|
1422 TInt32 j = 0; |
|
1423 TInt32 k = 0; // Indices |
|
1424 TInt32 compIndex = 0; // Index of the component in the codestream |
|
1425 TInt32 paletteIndex = 0; // Index of the component in the palette |
|
1426 TInt32 value = 0; |
|
1427 TInt32 dcShift = 0; |
|
1428 TPrecInt*** tempData = 0; // temporary storage for codestream data |
|
1429 TUint8 bitdepth = 0; |
|
1430 |
|
1431 CJ2kWriterComponentInfo* componentFrom = 0; |
|
1432 CJ2kWriterComponentInfo* componentTo = 0; |
|
1433 CJ2kSubband* subband = 0; |
|
1434 |
|
1435 TSize subbandSize( 0, 0 ); |
|
1436 |
|
1437 // First allocate the temporary storage |
|
1438 tempData = STATIC_CAST( TPrecInt***, User::Alloc( aNumCSComp * sizeof( TPrecInt** ) ) ); |
|
1439 if ( !tempData ) |
|
1440 { |
|
1441 User::Leave( KErrNoMemory ); |
|
1442 } |
|
1443 CleanupStack::PushL( tempData ); |
|
1444 for ( i = 0; i < aNumCSComp; i++ ) |
|
1445 { |
|
1446 subband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( (TUint16)i ).SubbandAt( (TUint8)aReducedLevels ) ); |
|
1447 |
|
1448 if( subband->SubbandResLevel() != 0 ) |
|
1449 { |
|
1450 subband = subband->Parent(); |
|
1451 } |
|
1452 subbandSize = subband->SubbandCanvasSize(); |
|
1453 |
|
1454 // Check that this component's size doesn't exceed the output size |
|
1455 if( subbandSize.iWidth > aSize.iWidth ) |
|
1456 { |
|
1457 subbandSize.iWidth = aSize.iWidth; |
|
1458 } |
|
1459 if( subbandSize.iHeight > aSize.iHeight ) |
|
1460 { |
|
1461 subbandSize.iHeight = aSize.iHeight; |
|
1462 } |
|
1463 |
|
1464 // Allocate the temporary storage |
|
1465 tempData[i] = TJ2kUtils::Alloc2DArrayL( subbandSize.iHeight, subbandSize.iWidth ); |
|
1466 CleanupStack::PushL( TCleanupItem( ( TCleanupOperation )&( TJ2kUtils::Free2DArray ), ( TAny* )tempData[i] ) ); |
|
1467 componentFrom = iComponents[i]; |
|
1468 |
|
1469 for ( j = subbandSize.iHeight - 1; j >= 0; j-- ) |
|
1470 { |
|
1471 Mem::Copy( tempData[i][j], componentFrom->Data()[j], subbandSize.iWidth * sizeof( TPrecInt ) ); |
|
1472 } |
|
1473 } |
|
1474 |
|
1475 for ( k = 0; k < iNumComponents; k++ ) |
|
1476 { |
|
1477 // Get the channel in the codestream from which to map |
|
1478 compIndex = iJ2kInfo.iCMPList[k].iCmp; |
|
1479 componentFrom = iComponents[compIndex]; |
|
1480 |
|
1481 subband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( (TUint16)compIndex ).SubbandAt( (TUint8)aReducedLevels ) ); |
|
1482 |
|
1483 if( subband->SubbandResLevel() != 0 ) |
|
1484 { |
|
1485 subband = subband->Parent(); |
|
1486 } |
|
1487 |
|
1488 subbandSize = subband->SubbandCanvasSize(); |
|
1489 |
|
1490 // Check that this component's size doesn't exceed the output size |
|
1491 if( subbandSize.iWidth > aSize.iWidth ) |
|
1492 { |
|
1493 subbandSize.iWidth = aSize.iWidth; |
|
1494 } |
|
1495 if( subbandSize.iHeight > aSize.iHeight ) |
|
1496 { |
|
1497 subbandSize.iHeight = aSize.iHeight; |
|
1498 } |
|
1499 |
|
1500 // Get the output channel |
|
1501 componentTo = iComponents[k]; |
|
1502 |
|
1503 // Check if palette is used for mapping |
|
1504 if ( iJ2kInfo.iCMPList[k].iMtyp == 1 ) |
|
1505 { |
|
1506 // Get the right palette channel for mapping |
|
1507 paletteIndex = iJ2kInfo.iCMPList[k].iPcol; |
|
1508 |
|
1509 // Bitdepth is the lowest seven bits plus one for palettes |
|
1510 bitdepth = (TUint8)( ( iJ2kInfo.iPalette.iBList[paletteIndex] & 0x7f ) + 1 ); |
|
1511 dcShift = 1 << ( bitdepth - 1 ); |
|
1512 |
|
1513 for ( i = 0; i < subbandSize.iHeight; i++ ) |
|
1514 { |
|
1515 for ( j = 0; j < subbandSize.iWidth; j++ ) |
|
1516 { |
|
1517 // Map the input codestream channel into the output component |
|
1518 // using the palette value. |
|
1519 value = tempData[compIndex][i][j] + dcShift; |
|
1520 if ( value < 0 ) |
|
1521 { |
|
1522 value = 0; |
|
1523 } |
|
1524 if ( value >= iJ2kInfo.iPalette.iC2DArray.Count() ) |
|
1525 { |
|
1526 value = iJ2kInfo.iPalette.iC2DArray.Count() - 1; |
|
1527 } |
|
1528 |
|
1529 componentTo->iData[i][j] = ( *iJ2kInfo.iPalette.iC2DArray[value] )[paletteIndex] - dcShift; |
|
1530 } |
|
1531 } |
|
1532 } |
|
1533 else // Direct mapping |
|
1534 { |
|
1535 for ( i = subbandSize.iHeight - 1; i >= 0; --i ) |
|
1536 { |
|
1537 for ( j = subbandSize.iWidth - 1; j >= 0; --j ) |
|
1538 { |
|
1539 // Map the input codestream channel into the output component directly. |
|
1540 componentTo->iData[i][j] = componentFrom->iData[i][j]; |
|
1541 } |
|
1542 } |
|
1543 } |
|
1544 } |
|
1545 |
|
1546 CleanupStack::PopAndDestroy( aNumCSComp + 1 ); |
|
1547 } |
|
1548 |
|
1549 // ----------------------------------------------------------------------------- |
|
1550 // CJ2kImageWriter::WriteOutputFile |
|
1551 // Write the component to the single output file |
|
1552 // (other items were commented in a header). |
|
1553 // ----------------------------------------------------------------------------- |
|
1554 // |
|
1555 void CJ2kImageWriter::WriteOutputFile( CJ2kTileInfo& aTile, |
|
1556 TUint16 aCompIndex, |
|
1557 const TSize& aSize, |
|
1558 TUint16 aBitDepth ) |
|
1559 { |
|
1560 TPrecInt* imageRow = 0; |
|
1561 CJ2kWriterComponentInfo* currentComponent = iComponents[aCompIndex]; |
|
1562 TSize outputSize = aSize; |
|
1563 |
|
1564 TUint16 numLevels = aTile.ComponentAt( aCompIndex ).Levels(); |
|
1565 TInt16 tempNumLevels = (TUint16)( numLevels - iImageInfo.LevelDrop() ); |
|
1566 |
|
1567 TPoint tileStartCoord = currentComponent->TileStartAt( aTile.SotMarker().iIsot ); |
|
1568 currentComponent->UpdateNextTileStartAt( aTile.SotMarker().iIsot, aSize, iImageInfo ); |
|
1569 |
|
1570 if ( tempNumLevels < 0 ) |
|
1571 { |
|
1572 |
|
1573 TInt32 i; |
|
1574 TInt32 stepSize = 1; |
|
1575 |
|
1576 // Compute the output step size, the stepSize indicates how much more |
|
1577 // resolution has to be dropped if the image didn't have enough wavelet |
|
1578 // levels to begin with. One indicates no extra resolution drop (write |
|
1579 // each sample) and for each extra drop skip half of the samples, i.e. |
|
1580 // stepSize is 2^extraLevels in case extra drop is needed. |
|
1581 |
|
1582 // Adjust the tile starting points and the stepSize |
|
1583 for ( i = 0; i < (-tempNumLevels); i++ ) |
|
1584 { |
|
1585 // Double the step size for every extra level dropped. |
|
1586 stepSize *= 2; |
|
1587 } |
|
1588 |
|
1589 // Also take care of next tile's starting position |
|
1590 outputSize.iHeight /= stepSize; |
|
1591 outputSize.iWidth /= stepSize; |
|
1592 iComponents[0]->UpdateNextTileStartAt( aTile.SotMarker().iIsot, outputSize, iImageInfo ); |
|
1593 } |
|
1594 |
|
1595 TInt32 dcShift = 0; |
|
1596 TInt32 j = 0; |
|
1597 if ( aBitDepth == 8 ) |
|
1598 { |
|
1599 if ( !( iImageInfo.SignOfComponent( aCompIndex ) ) ) |
|
1600 { |
|
1601 dcShift = 1 << ( aBitDepth - 1 ); |
|
1602 } |
|
1603 } |
|
1604 |
|
1605 // Convert with an ICC profile if necessary |
|
1606 if( iICCProfile ) |
|
1607 { |
|
1608 TInt32 value = 0; |
|
1609 TInt32 outputValue = 0; |
|
1610 |
|
1611 // Compute the dcShift again, we must have dcShift != 0 for other than 8-bit input. |
|
1612 dcShift = 1 << ( iImageInfo.DepthOfComponent( 0 )-1 ); |
|
1613 |
|
1614 for ( TInt32 i = 0; i < outputSize.iHeight; i++ ) |
|
1615 { |
|
1616 imageRow = currentComponent->Data()[i]; |
|
1617 |
|
1618 SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i ); |
|
1619 for ( j = 0; j < outputSize.iWidth; j++ ) |
|
1620 { |
|
1621 // Use a clipped value of input sample for an index to the grayscale TRC LUT. |
|
1622 value = iGrayTRCLut[CLIPINT( ( imageRow[j]+dcShift ), aBitDepth )]; |
|
1623 |
|
1624 // Get rid of values outside the range of legal values. |
|
1625 value = CLIP2RANGE( value, 0, KSRGBMaxInt ); |
|
1626 |
|
1627 // De-linearize the output values. |
|
1628 outputValue = ( *iLinearsRGBLut )[value]; |
|
1629 |
|
1630 iMonoPixelBlock[j] = (TUint32)( INT2BYTE( outputValue ) ); |
|
1631 } |
|
1632 |
|
1633 // Flush the row of grayscale pixels to image processor |
|
1634 iImageProcessor->SetMonoPixels( iMonoPixelBlock, outputSize.iWidth ); |
|
1635 } |
|
1636 |
|
1637 SetPixelPos( tileStartCoord ); |
|
1638 } |
|
1639 else // No ICC profile was used. |
|
1640 { |
|
1641 |
|
1642 // Take care of bitdepths != 8 |
|
1643 if ( aBitDepth != 8 ) |
|
1644 { |
|
1645 MapToEightBits( *currentComponent, outputSize, aBitDepth ); |
|
1646 } |
|
1647 |
|
1648 SetPixelPos( tileStartCoord ); |
|
1649 |
|
1650 for ( TInt32 i = 0; i < outputSize.iHeight; i++ ) |
|
1651 { |
|
1652 imageRow = currentComponent->Data()[i]; |
|
1653 |
|
1654 |
|
1655 SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i ); |
|
1656 |
|
1657 for ( j = 0; j < outputSize.iWidth; j++ ) |
|
1658 { |
|
1659 // Store the value in the RGB "block" |
|
1660 iMonoPixelBlock[j] = (TUint32)( INT2BYTE( ( imageRow[j] + dcShift ) ) ); |
|
1661 } |
|
1662 |
|
1663 // Flush the row of grayscale pixels to image processor |
|
1664 iImageProcessor->SetMonoPixels( iMonoPixelBlock, outputSize.iWidth ); |
|
1665 } |
|
1666 |
|
1667 SetPixelPos( tileStartCoord ); |
|
1668 } |
|
1669 } |
|
1670 |
|
1671 // ----------------------------------------------------------------------------- |
|
1672 // CJ2kImageWriter::CombineOutputFile |
|
1673 // Write all components of the tile to the single output file |
|
1674 // (other items were commented in a header). |
|
1675 // ----------------------------------------------------------------------------- |
|
1676 // |
|
1677 void CJ2kImageWriter::CombineOutputFile( CJ2kTileInfo& aTile, const TSize& aSize ) |
|
1678 { |
|
1679 TInt32 i = 0; |
|
1680 TInt32 j = 0; |
|
1681 TUint16 numLevels = aTile.ComponentAt( 0 ).Levels(); |
|
1682 TInt16 tempNumLevels = (TUint16)( numLevels - iImageInfo.LevelDrop() ); |
|
1683 |
|
1684 TSize outputSize = aSize; |
|
1685 TPoint& tileStartCoord = iComponents[0]->TileStartAt( aTile.SotMarker().iIsot ); |
|
1686 iComponents[0]->UpdateNextTileStartAt( aTile.SotMarker().iIsot, outputSize, iImageInfo ); |
|
1687 |
|
1688 if ( tempNumLevels < 0 ) |
|
1689 { |
|
1690 TInt32 stepSize = 1; |
|
1691 |
|
1692 // Compute the output step size, the stepSize indicates how much more |
|
1693 // resolution has to be dropped if the image didn't have enough wavelet |
|
1694 // levels to begin with. One indicates no extra resolution drop (write |
|
1695 // each sample) and for each extra drop skip half of the samples, i.e. |
|
1696 // stepSize is 2^extraLevels in case extra drop is needed. |
|
1697 |
|
1698 // Adjust the tile starting points and the stepSize |
|
1699 for ( i = 0; i < (-tempNumLevels); i++ ) |
|
1700 { |
|
1701 // Double the step size for every extra level dropped. |
|
1702 stepSize *= 2; |
|
1703 } |
|
1704 |
|
1705 // Also take care of next tile's starting position |
|
1706 outputSize.iHeight /= stepSize; |
|
1707 outputSize.iWidth /= stepSize; |
|
1708 iComponents[0]->UpdateNextTileStartAt( aTile.SotMarker().iIsot, outputSize, iImageInfo ); |
|
1709 |
|
1710 tempNumLevels = 0; |
|
1711 } |
|
1712 |
|
1713 TInt32 dcShift = 0; |
|
1714 if ( iImageInfo.DepthOfComponent( 0 ) == 8 ) |
|
1715 { |
|
1716 if ( !( iImageInfo.SignOfComponent( 0 ) ) ) |
|
1717 { |
|
1718 dcShift = 1 << ( iImageInfo.DepthOfComponent( 0 ) - 1 ); |
|
1719 } |
|
1720 } |
|
1721 |
|
1722 TSize subSamplingSize( 0, 0 ); |
|
1723 |
|
1724 // Due to subsampling we might have one more sample than the result of |
|
1725 // height/2 or width/2 will give thus we have to check whether we an |
|
1726 // extra row/column . |
|
1727 // |
|
1728 if ( iImageInfo.NumOfComponents() == 3 && iJ2kInfo.iEnumCS == 18 ) |
|
1729 { |
|
1730 CJ2kSubband* subband = CONST_CAST( CJ2kSubband*, aTile.ComponentAt( 1 ).SubbandAt( (TUint8)tempNumLevels ) ); |
|
1731 |
|
1732 if ( subband->SubbandResLevel() != 0 ) |
|
1733 { |
|
1734 subband = subband->Parent(); |
|
1735 } |
|
1736 |
|
1737 subSamplingSize = subband->SubbandCanvasSize(); |
|
1738 |
|
1739 if ( subSamplingSize.iWidth ) |
|
1740 { |
|
1741 --subSamplingSize.iWidth; |
|
1742 } |
|
1743 |
|
1744 if ( subSamplingSize.iHeight ) |
|
1745 { |
|
1746 --subSamplingSize.iHeight; |
|
1747 } |
|
1748 } |
|
1749 |
|
1750 TPrecInt** c1 = iComponents[0]->Data(); |
|
1751 TPrecInt** c2 = iComponents[1]->Data(); |
|
1752 TPrecInt** c3 = iComponents[2]->Data(); |
|
1753 |
|
1754 TPrecInt* c1Row = c1[0]; |
|
1755 TPrecInt* c2Row = c2[0]; |
|
1756 TPrecInt* c3Row = c3[0]; |
|
1757 |
|
1758 // For taking care of channel definition box order |
|
1759 if ( iJ2kInfo.iCNList.Count() > 0 ) |
|
1760 { |
|
1761 for ( i = 0; i < 3; i++ ) |
|
1762 { |
|
1763 if ( iJ2kInfo.iCNList[i].iAsoc == 1 ) |
|
1764 { |
|
1765 c1 = iComponents[i]->Data(); |
|
1766 } |
|
1767 else if ( iJ2kInfo.iCNList[i].iAsoc == 2 ) |
|
1768 { |
|
1769 c2 = iComponents[i]->Data(); |
|
1770 } |
|
1771 else if( iJ2kInfo.iCNList[i].iAsoc == 3 ) |
|
1772 { |
|
1773 c3 = iComponents[i]->Data(); |
|
1774 } |
|
1775 } //lint !e961 no else is needed here at the end of if...else if |
|
1776 } |
|
1777 |
|
1778 // If dithering is needed the following lines should be used: |
|
1779 // TInt32 A = KDitherCoeffcient11 + dcShift; |
|
1780 // TInt32 B = KDitherCoeffcient12 + dcShift; |
|
1781 // TInt32 C = KDitherCoeffcient21 + dcShift; |
|
1782 // TInt32 D = KDitherCoeffcient22 + dcShift; |
|
1783 // Without dithering, use dcShift only. |
|
1784 // |
|
1785 TInt32 ditherA = dcShift; |
|
1786 TInt32 ditherB = dcShift; |
|
1787 TInt32 ditherC = dcShift; |
|
1788 TInt32 ditherD = dcShift; |
|
1789 |
|
1790 TUint8 values[6]; |
|
1791 |
|
1792 // Convert with the ICC profile values if necessary. |
|
1793 if( iICCProfile ) |
|
1794 { |
|
1795 TInt32 x = 0; |
|
1796 TInt32 y = 0; |
|
1797 TInt32 z = 0; |
|
1798 TPrecInt sR = 0; |
|
1799 TPrecInt sG = 0; |
|
1800 TPrecInt sB = 0; |
|
1801 TInt32 maxValue = 0; |
|
1802 |
|
1803 // Compute the dcShift again, we must have dcShift != 0 for other than 8-bit input. |
|
1804 dcShift = 1 << ( iImageInfo.DepthOfComponent( 0 ) - 1 ); |
|
1805 maxValue = ( 1 << iImageInfo.DepthOfComponent( 0 ) ) - 1; // Maximum value for this bitdepth |
|
1806 |
|
1807 for( i = 0; i < outputSize.iHeight; i++ ) |
|
1808 { |
|
1809 |
|
1810 // Set the current coordinate in the output image |
|
1811 SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i ); |
|
1812 |
|
1813 for( j = 0; j < outputSize.iWidth; j++ ) |
|
1814 { |
|
1815 x = CLIP2BITDEPTH( ( c1[i][j] + dcShift ),maxValue ); |
|
1816 y = CLIP2BITDEPTH( ( c2[i][j] + dcShift ),maxValue ); |
|
1817 z = CLIP2BITDEPTH( ( c3[i][j] + dcShift ),maxValue ); |
|
1818 |
|
1819 DoICCConversion( x,y,z,sR,sG,sB ); |
|
1820 |
|
1821 values[0] = INT2BYTE( sB ); |
|
1822 values[1] = INT2BYTE( sG ); |
|
1823 values[2]= INT2BYTE( sR ); |
|
1824 |
|
1825 WritePixel( values[2], values[1], values[0] ); |
|
1826 } |
|
1827 } |
|
1828 |
|
1829 // Set the current coordinate in the output image |
|
1830 SetPixelPos( tileStartCoord ); |
|
1831 } |
|
1832 else |
|
1833 { |
|
1834 |
|
1835 // To speed up output writing (for subsampled samples), compute the number of half the samples |
|
1836 TInt32 halfOfWidth = outputSize.iWidth / 2; |
|
1837 |
|
1838 // If the bitdepth is not eight, shift values so that output is unsigned eight bit |
|
1839 for ( i = 0; i < iImageInfo.NumOfComponents(); i++ ) |
|
1840 { |
|
1841 if ( iImageInfo.DepthOfComponent( ( TUint16 )i ) != 8 ) |
|
1842 { |
|
1843 MapToEightBits( *iComponents[i], outputSize, iImageInfo.DepthOfComponent( (TUint16)i ) ); |
|
1844 } |
|
1845 } |
|
1846 |
|
1847 // Do the YUV to RGB conversion if needed |
|
1848 if ( iJ2kInfo.iEnumCS == 18 ) |
|
1849 { |
|
1850 TPrecInt y1 = 0; |
|
1851 TPrecInt y2 = 0; |
|
1852 TPrecInt u = 0; |
|
1853 TPrecInt v = 0; |
|
1854 TPrecInt r = 0; |
|
1855 TPrecInt g = 0; |
|
1856 TPrecInt b = 0; |
|
1857 TPrecInt r1 = 0; |
|
1858 TPrecInt g1 = 0; |
|
1859 TPrecInt b1 = 0; |
|
1860 TPrecInt r2 = 0; |
|
1861 TPrecInt g2 = 0; |
|
1862 TPrecInt b2 = 0; |
|
1863 |
|
1864 if ( iFileType == KYUV420 ) // YUV 4:2:0 |
|
1865 { |
|
1866 |
|
1867 TPrecInt* c1EvenRow = c1[0]; |
|
1868 TPrecInt* c1OddRow = c1[0]; |
|
1869 TPrecInt y3 = 0; |
|
1870 TPrecInt y4 = 0; |
|
1871 TPrecInt r3 = 0; |
|
1872 TPrecInt g3 = 0; |
|
1873 TPrecInt b3 = 0; |
|
1874 TPrecInt r4 = 0; |
|
1875 TPrecInt g4 = 0; |
|
1876 TPrecInt b4 = 0; |
|
1877 |
|
1878 for ( i = 0; i < outputSize.iHeight / 2; i++ ) |
|
1879 { |
|
1880 SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + 2 * i ) ); |
|
1881 |
|
1882 c1EvenRow = c1[2 * i]; |
|
1883 c1OddRow = c1[2 * i + 1]; |
|
1884 c2Row = c2[i]; |
|
1885 c3Row = c3[i]; |
|
1886 |
|
1887 for ( j = 0; j < halfOfWidth; j++ ) |
|
1888 { |
|
1889 y1 = *c1EvenRow++; |
|
1890 y2 = *c1EvenRow++; |
|
1891 y3 = *c1OddRow++; |
|
1892 y4 = *c1OddRow++; |
|
1893 u = *c2Row++; |
|
1894 v = *c3Row++; |
|
1895 |
|
1896 InverseICTTransform(y1,y2,y3,y4,u,v,r1,g1,b1,r2,g2,b2,r3,g3,b3,r4,g4,b4); |
|
1897 |
|
1898 // Even rows, even columns |
|
1899 values[0] = INT2BYTE( ( r1 + ditherA ) ); |
|
1900 values[1] = INT2BYTE( ( g1 + ditherA ) ); |
|
1901 values[2] = INT2BYTE( ( b1 + ditherA ) ); |
|
1902 |
|
1903 // Even rows, odd columns: |
|
1904 values[3] = INT2BYTE( ( r2 + ditherB ) ); |
|
1905 values[4] = INT2BYTE( ( g2 + ditherB ) ); |
|
1906 values[5] = INT2BYTE( ( b2 + ditherB ) ); |
|
1907 |
|
1908 // Store the values in the RGB "block" |
|
1909 iColorPixelBlock[2 * j] = TRgb( values[0], values[1], values[2] ); |
|
1910 iColorPixelBlock[2 * j + 1] = TRgb( values[3], values[4], values[5] ); |
|
1911 |
|
1912 // Now the odd row: |
|
1913 // Odd rows, even column |
|
1914 values[0] = INT2BYTE( ( r3 + ditherC ) ); |
|
1915 values[1] = INT2BYTE( ( g3 + ditherC ) ); |
|
1916 values[2] = INT2BYTE( ( b3 + ditherC ) ); |
|
1917 |
|
1918 // Odd rows, odd columns: |
|
1919 values[3] = INT2BYTE( ( r4 + ditherD ) ); |
|
1920 values[4] = INT2BYTE( ( g4 + ditherD ) ); |
|
1921 values[5] = INT2BYTE( ( b4 + ditherD ) ); |
|
1922 |
|
1923 // Store the values in the RGB "block" |
|
1924 iColorPixelBlock[KPixelsBlock + 2 * j] = TRgb( values[0], values[1], values[2] ); |
|
1925 iColorPixelBlock[KPixelsBlock + 2 * j + 1] = TRgb( values[3], values[4], values[5] ); |
|
1926 } |
|
1927 |
|
1928 if ( outputSize.iWidth & 1 ) // If the width is odd: |
|
1929 { |
|
1930 // The even row: |
|
1931 y1 = c1[2 * i][outputSize.iWidth - 1]; |
|
1932 // And the odd row: |
|
1933 y2 = c1[2 * i + 1][outputSize.iWidth - 1]; |
|
1934 u = c2[i][subSamplingSize.iWidth]; |
|
1935 v = c3[i][subSamplingSize.iWidth]; |
|
1936 |
|
1937 InverseICTTransform(y1,y2,u,v,r1,g1,b1,r2,g2,b2); |
|
1938 |
|
1939 values[0] = INT2BYTE( ( r1 + ditherA ) ); |
|
1940 values[1] = INT2BYTE( ( g1 + ditherA ) ); |
|
1941 values[2] = INT2BYTE( ( b1 + ditherA ) ); |
|
1942 |
|
1943 // Store the value in the RGB "block" |
|
1944 iColorPixelBlock[outputSize.iWidth - 1] = TRgb( values[0], values[1], values[2] ); |
|
1945 |
|
1946 values[0] = INT2BYTE( ( r2 + ditherC ) ); |
|
1947 values[1] = INT2BYTE( ( g2 + ditherC ) ); |
|
1948 values[2] = INT2BYTE( ( b2 + ditherC ) ); |
|
1949 |
|
1950 // Store the value in the RGB "block" |
|
1951 iColorPixelBlock[KPixelsBlock + outputSize.iWidth - 1] = TRgb( values[0], values[1], values[2] ); |
|
1952 } |
|
1953 |
|
1954 // Flush the row of color pixels to image processor |
|
1955 iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth ); |
|
1956 |
|
1957 // Duplicated processing for the odd rows |
|
1958 SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + 2 * i + 1 ) ); |
|
1959 |
|
1960 // Flush the row of color pixels to image processor |
|
1961 iImageProcessor->SetPixels( (iColorPixelBlock + KPixelsBlock), outputSize.iWidth ); |
|
1962 |
|
1963 } // End of loop on rows |
|
1964 |
|
1965 if ( outputSize.iHeight & 1 ) // If the height is odd: |
|
1966 { |
|
1967 SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + outputSize.iHeight - 1 ) ); |
|
1968 |
|
1969 c1Row = c1[outputSize.iHeight - 1]; |
|
1970 c2Row = c2[subSamplingSize.iHeight]; |
|
1971 c3Row = c3[subSamplingSize.iHeight]; |
|
1972 |
|
1973 for ( i = 0; i < halfOfWidth; i++ ) |
|
1974 { |
|
1975 y1 = *c1Row++; |
|
1976 y2 = *c1Row++; |
|
1977 u = *c2Row++; |
|
1978 v = *c3Row++; |
|
1979 |
|
1980 InverseICTTransform(y1,y2,u,v,r1,g1,b1,r2,g2,b2); |
|
1981 |
|
1982 values[0] = INT2BYTE( ( r1 + ditherA ) ); |
|
1983 values[1] = INT2BYTE( ( g1 + ditherA ) ); |
|
1984 values[2] = INT2BYTE( ( b1 + ditherA ) ); |
|
1985 |
|
1986 values[3] = INT2BYTE( ( r2 + ditherB ) ); |
|
1987 values[4] = INT2BYTE( ( g2 + ditherB ) ); |
|
1988 values[5] = INT2BYTE( ( b2 + ditherB ) ); |
|
1989 |
|
1990 // Store the value in the RGB "block" |
|
1991 iColorPixelBlock[2 * i] = TRgb( values[0], values[1], values[2] ); |
|
1992 iColorPixelBlock[2 * i + 1] = TRgb( values[3], values[4], values[5] ); |
|
1993 } |
|
1994 |
|
1995 if ( outputSize.iWidth & 1 ) // if the width is odd: |
|
1996 { |
|
1997 y1 = c1[outputSize.iHeight - 1][outputSize.iWidth - 1]; |
|
1998 u = c2[subSamplingSize.iHeight][subSamplingSize.iWidth]; |
|
1999 v = c3[subSamplingSize.iHeight][subSamplingSize.iWidth]; |
|
2000 |
|
2001 InverseICTTransform( y1, u, v, r, g, b ); |
|
2002 values[0] = INT2BYTE( ( r + ditherA ) ); |
|
2003 values[1] = INT2BYTE( ( g + ditherA ) ); |
|
2004 values[2] = INT2BYTE( ( b + ditherA ) ); |
|
2005 |
|
2006 // Store the value in the RGB "block" |
|
2007 iColorPixelBlock[outputSize.iWidth - 1] = TRgb( values[0], values[1], values[2] ); |
|
2008 } |
|
2009 |
|
2010 // Flush the row of color pixels to image processor |
|
2011 iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth ); |
|
2012 |
|
2013 } |
|
2014 |
|
2015 SetPixelPos( tileStartCoord ); |
|
2016 } |
|
2017 else if ( iFileType == KYUV422 ) |
|
2018 { |
|
2019 |
|
2020 for ( i = 0; i < outputSize.iHeight; i++ ) |
|
2021 { |
|
2022 SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + 2 * i ) ); |
|
2023 |
|
2024 c1Row = c1[i]; |
|
2025 c2Row = c2[i]; |
|
2026 c3Row = c3[i]; |
|
2027 |
|
2028 for ( j = 0; j < halfOfWidth; j++ ) |
|
2029 { |
|
2030 y1 = *c1Row++; |
|
2031 y2 = *c1Row++; |
|
2032 u = c2Row[j]; |
|
2033 v = c3Row[j]; |
|
2034 |
|
2035 InverseICTTransform(y1,y2,u,v,r1,g1,b1,r2,g2,b2); |
|
2036 |
|
2037 values[0] = INT2BYTE( ( r1 + dcShift ) ); |
|
2038 values[1] = INT2BYTE( ( g1 + dcShift ) ); |
|
2039 values[2] = INT2BYTE( ( b1 + dcShift ) ); |
|
2040 |
|
2041 values[3] = INT2BYTE( ( r2 + dcShift ) ); |
|
2042 values[4] = INT2BYTE( ( g2 + dcShift ) ); |
|
2043 values[5] = INT2BYTE( ( b2 + dcShift ) ); |
|
2044 |
|
2045 // Store the value in the RGB "block" |
|
2046 iColorPixelBlock[j] = TRgb( values[0], values[1], values[2] ); |
|
2047 iColorPixelBlock[j+1] = TRgb( values[3], values[4], values[5] ); |
|
2048 } |
|
2049 |
|
2050 if ( outputSize.iWidth & 1 ) // if the width is odd: |
|
2051 { |
|
2052 y1 = c1Row[outputSize.iWidth - 1]; |
|
2053 u = c2Row[subSamplingSize.iWidth]; |
|
2054 v = c3Row[subSamplingSize.iWidth]; |
|
2055 |
|
2056 InverseICTTransform( y1, u, v, r, g, b ); |
|
2057 |
|
2058 values[0] = INT2BYTE( ( r + dcShift ) ); |
|
2059 values[1] = INT2BYTE( ( g + dcShift ) ); |
|
2060 values[2] = INT2BYTE( ( b + dcShift ) ); |
|
2061 |
|
2062 // Store the value in the RGB "block" |
|
2063 iColorPixelBlock[outputSize.iWidth-1] = TRgb( values[0], values[1], values[2] ); |
|
2064 } |
|
2065 |
|
2066 // Flush the row of color pixels to image processor |
|
2067 iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth ); |
|
2068 } |
|
2069 |
|
2070 SetPixelPos( tileStartCoord ); |
|
2071 } |
|
2072 else // To take care of YUV 4:4:4 |
|
2073 { |
|
2074 |
|
2075 for ( i = 0; i < outputSize.iHeight; i++ ) |
|
2076 { |
|
2077 SetPixelPos( tileStartCoord.iX, ( tileStartCoord.iY + i ) ); |
|
2078 |
|
2079 c1Row = c1[i]; |
|
2080 c2Row = c2[i]; |
|
2081 c3Row = c3[i]; |
|
2082 |
|
2083 for ( j = 0; j < outputSize.iWidth; j++ ) |
|
2084 { |
|
2085 y1 = *c1Row++; |
|
2086 u = *c2Row++; |
|
2087 v = *c3Row++; |
|
2088 |
|
2089 InverseICTTransform( y1, u, v, r, g, b ); |
|
2090 |
|
2091 values[0] = INT2BYTE( ( r + dcShift ) ); |
|
2092 values[1] = INT2BYTE( ( g + dcShift ) ); |
|
2093 values[2] = INT2BYTE( ( b + dcShift ) ); |
|
2094 |
|
2095 // Store the value in the RGB "block" |
|
2096 iColorPixelBlock[j] = TRgb( values[0], values[1], values[2] ); |
|
2097 } |
|
2098 |
|
2099 // Flush the row of color pixels to image processor |
|
2100 iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth ); |
|
2101 } |
|
2102 |
|
2103 SetPixelPos( tileStartCoord ); |
|
2104 } |
|
2105 } |
|
2106 else // RGB |
|
2107 { |
|
2108 TInt32 r = 0; |
|
2109 TInt32 g = 0; |
|
2110 TInt32 b = 0; |
|
2111 |
|
2112 for ( i = 0; i < outputSize.iHeight; i++ ) |
|
2113 { |
|
2114 |
|
2115 SetPixelPos( tileStartCoord.iX, tileStartCoord.iY + i ); |
|
2116 |
|
2117 c1Row = c1[i]; |
|
2118 c2Row = c2[i]; |
|
2119 c3Row = c3[i]; |
|
2120 |
|
2121 for ( j = 0; j < outputSize.iWidth; j++ ) |
|
2122 { |
|
2123 r = *c1Row++; |
|
2124 g = *c2Row++; |
|
2125 b = *c3Row++; |
|
2126 |
|
2127 values[0] = INT2BYTE( r + dcShift ); |
|
2128 values[1] = INT2BYTE( g + dcShift ); |
|
2129 values[2] = INT2BYTE( b + dcShift ); |
|
2130 |
|
2131 // Store the value in the RGB "block" |
|
2132 iColorPixelBlock[j] = TRgb( values[0], values[1], values[2] ); |
|
2133 } |
|
2134 |
|
2135 // Flush the row of color pixels to image processor |
|
2136 iImageProcessor->SetPixels( iColorPixelBlock, outputSize.iWidth ); |
|
2137 } |
|
2138 |
|
2139 SetPixelPos( tileStartCoord ); |
|
2140 } |
|
2141 } |
|
2142 } |
|
2143 |
|
2144 // ----------------------------------------------------------------------------- |
|
2145 // CJ2kImageWriter::WritePixel |
|
2146 // Write out a color pixel |
|
2147 // (other items were commented in a header). |
|
2148 // ----------------------------------------------------------------------------- |
|
2149 // |
|
2150 void CJ2kImageWriter::WritePixel( TUint8 aR, TUint8 aG, TUint8 aB ) |
|
2151 { |
|
2152 iImageProcessor->SetPixel( TRgb( aR, aG, aB ) ); |
|
2153 } |
|
2154 |
|
2155 // ----------------------------------------------------------------------------- |
|
2156 // CJ2kImageWriter::WritePixel |
|
2157 // Write out a grayscale pixel |
|
2158 // (other items were commented in a header). |
|
2159 // ----------------------------------------------------------------------------- |
|
2160 // |
|
2161 void CJ2kImageWriter::WritePixel( TUint8 aGray256 ) |
|
2162 { |
|
2163 iImageProcessor->SetMonoPixel( aGray256 ); |
|
2164 } |
|
2165 |
|
2166 // ----------------------------------------------------------------------------- |
|
2167 // CJ2kImageWriter::SetPixelPos |
|
2168 // Set the position of the pixel |
|
2169 // (other items were commented in a header). |
|
2170 // ----------------------------------------------------------------------------- |
|
2171 // |
|
2172 void CJ2kImageWriter::SetPixelPos( const TPoint& aPosition ) |
|
2173 { |
|
2174 iImageProcessor->SetPos( aPosition ); |
|
2175 } |
|
2176 |
|
2177 // ----------------------------------------------------------------------------- |
|
2178 // CJ2kImageWriter::SetPixelPos |
|
2179 // Set the position of the pixel |
|
2180 // (other items were commented in a header). |
|
2181 // ----------------------------------------------------------------------------- |
|
2182 // |
|
2183 void CJ2kImageWriter::SetPixelPos( const TInt aX, const TInt aY ) |
|
2184 { |
|
2185 iImageProcessor->SetPos( TPoint( aX, aY ) ); |
|
2186 } |
|
2187 |