@@ -167,11 +167,18 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
167167 this . byteOrder = reader . ByteOrder ;
168168 this . isBigTiff = reader . IsBigTiff ;
169169
170+ Size ? size = null ;
170171 uint frameCount = 0 ;
171172 foreach ( ExifProfile ifd in directories )
172173 {
173174 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+
175182 frames . Add ( frame ) ;
176183 framesMetadata . Add ( frame . Metadata ) ;
177184
@@ -181,19 +188,8 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
181188 }
182189 }
183190
191+ this . Dimensions = frames [ 0 ] . Size ;
184192 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-
197193 return new Image < TPixel > ( this . configuration , metadata , frames ) ;
198194 }
199195 catch
@@ -235,25 +231,40 @@ protected override ImageInfo Identify(BufferedReadStream stream, CancellationTok
235231 /// </summary>
236232 /// <typeparam name="TPixel">The pixel format.</typeparam>
237233 /// <param name="tags">The IFD tags.</param>
234+ /// <param name="size">The previously determined root frame size if decoded.</param>
238235 /// <param name="cancellationToken">The token to monitor cancellation.</param>
239236 /// <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 )
241238 where TPixel : unmanaged, IPixel < TPixel >
242239 {
243240 ImageFrameMetadata imageFrameMetaData = this . CreateFrameMetadata ( tags ) ;
244241 bool isTiled = this . VerifyAndParse ( tags , imageFrameMetaData . GetTiffMetadata ( ) ) ;
245242
246243 int width = GetImageWidth ( tags ) ;
247244 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 ) ;
249260
250261 if ( isTiled )
251262 {
252- this . DecodeImageWithTiles ( tags , frame , cancellationToken ) ;
263+ this . DecodeImageWithTiles ( tags , frame , width , height , cancellationToken ) ;
253264 }
254265 else
255266 {
256- this . DecodeImageWithStrips ( tags , frame , cancellationToken ) ;
267+ this . DecodeImageWithStrips ( tags , frame , width , height , cancellationToken ) ;
257268 }
258269
259270 return frame ;
@@ -278,8 +289,10 @@ private ImageFrameMetadata CreateFrameMetadata(ExifProfile tags)
278289 /// <typeparam name="TPixel">The pixel format.</typeparam>
279290 /// <param name="tags">The IFD tags.</param>
280291 /// <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>
281294 /// <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 )
283296 where TPixel : unmanaged, IPixel < TPixel >
284297 {
285298 int rowsPerStrip ;
@@ -302,6 +315,8 @@ private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel>
302315 {
303316 this . DecodeStripsPlanar (
304317 frame ,
318+ width ,
319+ height ,
305320 rowsPerStrip ,
306321 stripOffsets ,
307322 stripByteCounts ,
@@ -311,6 +326,8 @@ private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel>
311326 {
312327 this . DecodeStripsChunky (
313328 frame ,
329+ width ,
330+ height ,
314331 rowsPerStrip ,
315332 stripOffsets ,
316333 stripByteCounts ,
@@ -324,13 +341,13 @@ private void DecodeImageWithStrips<TPixel>(ExifProfile tags, ImageFrame<TPixel>
324341 /// <typeparam name="TPixel">The pixel format.</typeparam>
325342 /// <param name="tags">The IFD tags.</param>
326343 /// <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>
327346 /// <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 )
329348 where TPixel : unmanaged, IPixel < TPixel >
330349 {
331350 Buffer2D < TPixel > pixels = frame . PixelBuffer ;
332- int width = pixels . Width ;
333- int height = pixels . Height ;
334351
335352 if ( ! tags . TryGetValue ( ExifTag . TileWidth , out IExifValue < Number > valueWidth ) )
336353 {
@@ -384,11 +401,20 @@ private void DecodeImageWithTiles<TPixel>(ExifProfile tags, ImageFrame<TPixel> f
384401 /// </summary>
385402 /// <typeparam name="TPixel">The pixel format.</typeparam>
386403 /// <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>
387406 /// <param name="rowsPerStrip">The number of rows per strip of data.</param>
388407 /// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param>
389408 /// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param>
390409 /// <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 )
392418 where TPixel : unmanaged, IPixel < TPixel >
393419 {
394420 int stripsPerPixel = this . BitsPerSample . Channels ;
@@ -403,18 +429,18 @@ private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
403429 {
404430 for ( int stripIndex = 0 ; stripIndex < stripBuffers . Length ; stripIndex ++ )
405431 {
406- int uncompressedStripSize = this . CalculateStripBufferSize ( frame . Width , rowsPerStrip , stripIndex ) ;
432+ int uncompressedStripSize = this . CalculateStripBufferSize ( width , rowsPerStrip , stripIndex ) ;
407433 stripBuffers [ stripIndex ] = this . memoryAllocator . Allocate < byte > ( uncompressedStripSize ) ;
408434 }
409435
410- using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( frame . Width , bitsPerPixel ) ;
436+ using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( width , bitsPerPixel ) ;
411437 TiffBasePlanarColorDecoder < TPixel > colorDecoder = this . CreatePlanarColorDecoder < TPixel > ( ) ;
412438
413439 for ( int i = 0 ; i < stripsPerPlane ; i ++ )
414440 {
415441 cancellationToken . ThrowIfCancellationRequested ( ) ;
416442
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 ;
418444
419445 int stripIndex = i ;
420446 for ( int planeIndex = 0 ; planeIndex < stripsPerPixel ; planeIndex ++ )
@@ -430,7 +456,7 @@ private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
430456 stripIndex += stripsPerPlane ;
431457 }
432458
433- colorDecoder . Decode ( stripBuffers , pixels , 0 , rowsPerStrip * i , frame . Width , stripHeight ) ;
459+ colorDecoder . Decode ( stripBuffers , pixels , 0 , rowsPerStrip * i , width , stripHeight ) ;
434460 }
435461 }
436462 finally
@@ -447,39 +473,48 @@ private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
447473 /// </summary>
448474 /// <typeparam name="TPixel">The pixel format.</typeparam>
449475 /// <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>
450478 /// <param name="rowsPerStrip">The rows per strip.</param>
451479 /// <param name="stripOffsets">The strip offsets.</param>
452480 /// <param name="stripByteCounts">The strip byte counts.</param>
453481 /// <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 )
455490 where TPixel : unmanaged, IPixel < TPixel >
456491 {
457492 // If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip.
458493 if ( rowsPerStrip == TiffConstants . RowsPerStripInfinity )
459494 {
460- rowsPerStrip = frame . Height ;
495+ rowsPerStrip = height ;
461496 }
462497
463- int uncompressedStripSize = this . CalculateStripBufferSize ( frame . Width , rowsPerStrip ) ;
498+ int uncompressedStripSize = this . CalculateStripBufferSize ( width , rowsPerStrip ) ;
464499 int bitsPerPixel = this . BitsPerPixel ;
465500
466501 using IMemoryOwner < byte > stripBuffer = this . memoryAllocator . Allocate < byte > ( uncompressedStripSize , AllocationOptions . Clean ) ;
467502 Span < byte > stripBufferSpan = stripBuffer . GetSpan ( ) ;
468503 Buffer2D < TPixel > pixels = frame . PixelBuffer ;
469504
470- using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( frame . Width , bitsPerPixel ) ;
505+ using TiffBaseDecompressor decompressor = this . CreateDecompressor < TPixel > ( width , bitsPerPixel ) ;
471506 TiffBaseColorDecoder < TPixel > colorDecoder = this . CreateChunkyColorDecoder < TPixel > ( ) ;
472507
473508 for ( int stripIndex = 0 ; stripIndex < stripOffsets . Length ; stripIndex ++ )
474509 {
475510 cancellationToken . ThrowIfCancellationRequested ( ) ;
476511
477- int stripHeight = stripIndex < stripOffsets . Length - 1 || frame . Height % rowsPerStrip == 0
512+ int stripHeight = stripIndex < stripOffsets . Length - 1 || height % rowsPerStrip == 0
478513 ? rowsPerStrip
479- : frame . Height % rowsPerStrip ;
514+ : height % rowsPerStrip ;
480515
481516 int top = rowsPerStrip * stripIndex ;
482- if ( top + stripHeight > frame . Height )
517+ if ( top + stripHeight > height )
483518 {
484519 // Make sure we ignore any strips that are not needed for the image (if too many are present).
485520 break ;
@@ -493,7 +528,7 @@ private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
493528 stripBufferSpan ,
494529 cancellationToken ) ;
495530
496- colorDecoder . Decode ( stripBufferSpan , pixels , 0 , top , frame . Width , stripHeight ) ;
531+ colorDecoder . Decode ( stripBufferSpan , pixels , 0 , top , width , stripHeight ) ;
497532 }
498533 }
499534
0 commit comments