@@ -167,11 +167,18 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
167
167
this . byteOrder = reader . ByteOrder ;
168
168
this . isBigTiff = reader . IsBigTiff ;
169
169
170
+ Size ? size = null ;
170
171
uint frameCount = 0 ;
171
172
foreach ( ExifProfile ifd in directories )
172
173
{
173
174
cancellationToken . ThrowIfCancellationRequested ( ) ;
174
- ImageFrame < TPixel > frame = this . DecodeFrame < TPixel > ( ifd , cancellationToken ) ;
175
+ ImageFrame < TPixel > frame = this . DecodeFrame < TPixel > ( ifd , size , cancellationToken ) ;
176
+
177
+ if ( ! size . HasValue )
178
+ {
179
+ size = frame . Size ;
180
+ }
181
+
175
182
frames . Add ( frame ) ;
176
183
framesMetadata . Add ( frame . Metadata ) ;
177
184
@@ -181,19 +188,8 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
181
188
}
182
189
}
183
190
191
+ this . Dimensions = frames [ 0 ] . Size ;
184
192
ImageMetadata metadata = TiffDecoderMetadataCreator . Create ( framesMetadata , this . skipMetadata , reader . ByteOrder , reader . IsBigTiff ) ;
185
-
186
- // TODO: Tiff frames can have different sizes.
187
- ImageFrame < TPixel > root = frames [ 0 ] ;
188
- this . Dimensions = root . Size ( ) ;
189
- foreach ( ImageFrame < TPixel > frame in frames )
190
- {
191
- if ( frame . Size ( ) != root . Size ( ) )
192
- {
193
- TiffThrowHelper . ThrowNotSupported ( "Images with different sizes are not supported" ) ;
194
- }
195
- }
196
-
197
193
return new Image < TPixel > ( this . configuration , metadata , frames ) ;
198
194
}
199
195
catch
@@ -235,25 +231,40 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok
235
231
/// </summary>
236
232
/// <typeparam name="TPixel">The pixel format.</typeparam>
237
233
/// <param name="tags">The IFD tags.</param>
234
+ /// <param name="size">The previously determined root frame size if decoded.</param>
238
235
/// <param name="cancellationToken">The token to monitor cancellation.</param>
239
236
/// <returns>The tiff frame.</returns>
240
- private ImageFrame < TPixel > DecodeFrame < TPixel > ( ExifProfile tags , CancellationToken cancellationToken )
237
+ private ImageFrame < TPixel > DecodeFrame < TPixel > ( ExifProfile tags , Size ? size , CancellationToken cancellationToken )
241
238
where TPixel : unmanaged, IPixel < TPixel >
242
239
{
243
240
ImageFrameMetadata imageFrameMetaData = this . CreateFrameMetadata ( tags ) ;
244
241
bool isTiled = this . VerifyAndParse ( tags , imageFrameMetaData . GetTiffMetadata ( ) ) ;
245
242
246
243
int width = GetImageWidth ( tags ) ;
247
244
int height = GetImageHeight ( tags ) ;
248
- ImageFrame < TPixel > frame = new ( this . configuration , width , height , imageFrameMetaData ) ;
245
+
246
+ // If size has a value and the width/height off the tiff is smaller we much capture the delta.
247
+ if ( size . HasValue )
248
+ {
249
+ if ( size . Value . Width < width || size . Value . Height < height )
250
+ {
251
+ TiffThrowHelper . ThrowNotSupported ( "Images with frames of size greater than the root frame are not supported." ) ;
252
+ }
253
+ }
254
+ else
255
+ {
256
+ size = new Size ( width , height ) ;
257
+ }
258
+
259
+ ImageFrame < TPixel > frame = new ( this . configuration , size . Value . Width , size . Value . Height , imageFrameMetaData ) ;
249
260
250
261
if ( isTiled )
251
262
{
252
- this . DecodeImageWithTiles ( tags , frame , cancellationToken ) ;
263
+ this . DecodeImageWithTiles ( tags , frame , width , height , cancellationToken ) ;
253
264
}
254
265
else
255
266
{
256
- this . DecodeImageWithStrips ( tags , frame , cancellationToken ) ;
267
+ this . DecodeImageWithStrips ( tags , frame , width , height , cancellationToken ) ;
257
268
}
258
269
259
270
return frame ;
@@ -278,8 +289,10 @@ private ImageFrameMetadata CreateFrameMetadata(ExifProfile tags)
278
289
/// <typeparam name="TPixel">The pixel format.</typeparam>
279
290
/// <param name="tags">The IFD tags.</param>
280
291
/// <param name="frame">The image frame to decode into.</param>
292
+ /// <param name="width">The width in px units of the frame data.</param>
293
+ /// <param name="height">The height in px units of the frame data.</param>
281
294
/// <param name="cancellationToken">The token to monitor cancellation.</param>
282
- private void DecodeImageWithStrips < TPixel > ( ExifProfile tags , ImageFrame < TPixel > frame , CancellationToken cancellationToken )
295
+ private void DecodeImageWithStrips < TPixel > ( ExifProfile tags , ImageFrame < TPixel > frame , int width , int height , CancellationToken cancellationToken )
283
296
where TPixel : unmanaged, IPixel < TPixel >
284
297
{
285
298
int rowsPerStrip ;
@@ -302,6 +315,8 @@ private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel>
302
315
{
303
316
this . DecodeStripsPlanar (
304
317
frame ,
318
+ width ,
319
+ height ,
305
320
rowsPerStrip ,
306
321
stripOffsets ,
307
322
stripByteCounts ,
@@ -311,6 +326,8 @@ private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel>
311
326
{
312
327
this . DecodeStripsChunky (
313
328
frame ,
329
+ width ,
330
+ height ,
314
331
rowsPerStrip ,
315
332
stripOffsets ,
316
333
stripByteCounts ,
@@ -324,13 +341,13 @@ private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel>
324
341
/// <typeparam name="TPixel">The pixel format.</typeparam>
325
342
/// <param name="tags">The IFD tags.</param>
326
343
/// <param name="frame">The image frame to decode into.</param>
344
+ /// <param name="width">The width in px units of the frame data.</param>
345
+ /// <param name="height">The height in px units of the frame data.</param>
327
346
/// <param name="cancellationToken">The token to monitor cancellation.</param>
328
- private void DecodeImageWithTiles < TPixel > ( ExifProfile tags , ImageFrame < TPixel > frame , CancellationToken cancellationToken )
347
+ private void DecodeImageWithTiles < TPixel > ( ExifProfile tags , ImageFrame < TPixel > frame , int width , int height , CancellationToken cancellationToken )
329
348
where TPixel : unmanaged, IPixel < TPixel >
330
349
{
331
350
Buffer2D < TPixel > pixels = frame . PixelBuffer ;
332
- int width = pixels . Width ;
333
- int height = pixels . Height ;
334
351
335
352
if ( ! tags . TryGetValue ( ExifTag . TileWidth , out IExifValue < Number > valueWidth ) )
336
353
{
@@ -384,11 +401,20 @@ private void DecodeImageWithTiles<TPixel>(ExifProfile tags, ImageFrame<TPixel> f
384
401
/// </summary>
385
402
/// <typeparam name="TPixel">The pixel format.</typeparam>
386
403
/// <param name="frame">The image frame to decode data into.</param>
404
+ /// <param name="width">The width in px units of the frame data.</param>
405
+ /// <param name="height">The height in px units of the frame data.</param>
387
406
/// <param name="rowsPerStrip">The number of rows per strip of data.</param>
388
407
/// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param>
389
408
/// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param>
390
409
/// <param name="cancellationToken">The token to monitor cancellation.</param>
391
- private void DecodeStripsPlanar < TPixel > ( ImageFrame < TPixel > frame , int rowsPerStrip , Span < ulong > stripOffsets , Span < ulong > stripByteCounts , CancellationToken cancellationToken )
410
+ private void DecodeStripsPlanar < TPixel > (
411
+ ImageFrame < TPixel > frame ,
412
+ int width ,
413
+ int height ,
414
+ int rowsPerStrip ,
415
+ Span < ulong > stripOffsets ,
416
+ Span < ulong > stripByteCounts ,
417
+ CancellationToken cancellationToken )
392
418
where TPixel : unmanaged, IPixel < TPixel >
393
419
{
394
420
int stripsPerPixel = this . BitsPerSample . Channels ;
@@ -403,18 +429,18 @@ private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
403
429
{
404
430
for ( int stripIndex = 0 ; stripIndex < stripBuffers . Length ; stripIndex ++ )
405
431
{
406
- int uncompressedStripSize = this . CalculateStripBufferSize ( frame . Width , rowsPerStrip , stripIndex ) ;
432
+ int uncompressedStripSize = this . CalculateStripBufferSize ( width , rowsPerStrip , stripIndex ) ;
407
433
stripBuffers [ stripIndex ] = this . memoryAllocator . Allocate < byte > ( uncompressedStripSize ) ;
408
434
}
409
435
410
- using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( frame . Width , bitsPerPixel ) ;
436
+ using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( width , bitsPerPixel ) ;
411
437
TiffBasePlanarColorDecoder < TPixel > colorDecoder = this . CreatePlanarColorDecoder < TPixel > ( ) ;
412
438
413
439
for ( int i = 0 ; i < stripsPerPlane ; i ++ )
414
440
{
415
441
cancellationToken . ThrowIfCancellationRequested ( ) ;
416
442
417
- int stripHeight = i < stripsPerPlane - 1 || frame . Height % rowsPerStrip == 0 ? rowsPerStrip : frame . Height % rowsPerStrip ;
443
+ int stripHeight = i < stripsPerPlane - 1 || height % rowsPerStrip == 0 ? rowsPerStrip : height % rowsPerStrip ;
418
444
419
445
int stripIndex = i ;
420
446
for ( int planeIndex = 0 ; planeIndex < stripsPerPixel ; planeIndex ++ )
@@ -430,7 +456,7 @@ private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
430
456
stripIndex += stripsPerPlane ;
431
457
}
432
458
433
- colorDecoder . Decode ( stripBuffers , pixels , 0 , rowsPerStrip * i , frame . Width , stripHeight ) ;
459
+ colorDecoder . Decode ( stripBuffers , pixels , 0 , rowsPerStrip * i , width , stripHeight ) ;
434
460
}
435
461
}
436
462
finally
@@ -447,39 +473,48 @@ private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
447
473
/// </summary>
448
474
/// <typeparam name="TPixel">The pixel format.</typeparam>
449
475
/// <param name="frame">The image frame to decode data into.</param>
476
+ /// <param name="width">The width in px units of the frame data.</param>
477
+ /// <param name="height">The height in px units of the frame data.</param>
450
478
/// <param name="rowsPerStrip">The rows per strip.</param>
451
479
/// <param name="stripOffsets">The strip offsets.</param>
452
480
/// <param name="stripByteCounts">The strip byte counts.</param>
453
481
/// <param name="cancellationToken">The token to monitor cancellation.</param>
454
- private void DecodeStripsChunky < TPixel > ( ImageFrame < TPixel > frame , int rowsPerStrip , Span < ulong > stripOffsets , Span < ulong > stripByteCounts , CancellationToken cancellationToken )
482
+ private void DecodeStripsChunky < TPixel > (
483
+ ImageFrame < TPixel > frame ,
484
+ int width ,
485
+ int height ,
486
+ int rowsPerStrip ,
487
+ Span < ulong > stripOffsets ,
488
+ Span < ulong > stripByteCounts ,
489
+ CancellationToken cancellationToken )
455
490
where TPixel : unmanaged, IPixel < TPixel >
456
491
{
457
492
// If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip.
458
493
if ( rowsPerStrip == TiffConstants . RowsPerStripInfinity )
459
494
{
460
- rowsPerStrip = frame . Height ;
495
+ rowsPerStrip = height ;
461
496
}
462
497
463
- int uncompressedStripSize = this . CalculateStripBufferSize ( frame . Width , rowsPerStrip ) ;
498
+ int uncompressedStripSize = this . CalculateStripBufferSize ( width , rowsPerStrip ) ;
464
499
int bitsPerPixel = this . BitsPerPixel ;
465
500
466
501
using IMemoryOwner < byte > stripBuffer = this . memoryAllocator . Allocate < byte > ( uncompressedStripSize , AllocationOptions . Clean ) ;
467
502
Span < byte > stripBufferSpan = stripBuffer . GetSpan ( ) ;
468
503
Buffer2D < TPixel > pixels = frame . PixelBuffer ;
469
504
470
- using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( frame . Width , bitsPerPixel ) ;
505
+ using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( width , bitsPerPixel ) ;
471
506
TiffBaseColorDecoder < TPixel > colorDecoder = this . CreateChunkyColorDecoder < TPixel > ( ) ;
472
507
473
508
for ( int stripIndex = 0 ; stripIndex < stripOffsets . Length ; stripIndex ++ )
474
509
{
475
510
cancellationToken . ThrowIfCancellationRequested ( ) ;
476
511
477
- int stripHeight = stripIndex < stripOffsets . Length - 1 || frame . Height % rowsPerStrip == 0
512
+ int stripHeight = stripIndex < stripOffsets . Length - 1 || height % rowsPerStrip == 0
478
513
? rowsPerStrip
479
- : frame . Height % rowsPerStrip ;
514
+ : height % rowsPerStrip ;
480
515
481
516
int top = rowsPerStrip * stripIndex ;
482
- if ( top + stripHeight > frame . Height )
517
+ if ( top + stripHeight > height )
483
518
{
484
519
// Make sure we ignore any strips that are not needed for the image (if too many are present).
485
520
break ;
@@ -493,7 +528,7 @@ private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
493
528
stripBufferSpan ,
494
529
cancellationToken ) ;
495
530
496
- colorDecoder . Decode ( stripBufferSpan , pixels , 0 , top , frame . Width , stripHeight ) ;
531
+ colorDecoder . Decode ( stripBufferSpan , pixels , 0 , top , width , stripHeight ) ;
497
532
}
498
533
}
499
534
0 commit comments