@@ -10,97 +10,103 @@ static class PngNormalizer
1010
1111 public static void Normalize ( Stream source , Stream target )
1212 {
13- using var buffer = new MemoryStream ( ) ;
14- source . CopyTo ( buffer ) ;
15- Normalize ( buffer . GetBuffer ( ) , ( int ) buffer . Length , target ) ;
16- }
13+ var header = new byte [ 8 ] ;
14+ source . ReadExactly ( header , 0 , 8 ) ;
15+ target . Write ( pngSignature ) ;
1716
18- public static async Task NormalizeAsync ( Stream source , Stream target , Cancel cancel )
19- {
20- using var buffer = new MemoryStream ( ) ;
21- await source . CopyToAsync ( buffer , cancel ) ;
22- Normalize ( buffer . GetBuffer ( ) , ( int ) buffer . Length , target ) ;
17+ using var idatData = new MemoryStream ( ) ;
18+ var flushedIdat = false ;
19+
20+ while ( true )
21+ {
22+ source . ReadExactly ( header , 0 , 8 ) ;
23+ var chunkLength = BinaryPrimitives . ReadInt32BigEndian ( header . AsSpan ( 0 , 4 ) ) ;
24+
25+ var body = new byte [ chunkLength + 4 ] ;
26+ source . ReadExactly ( body , 0 , body . Length ) ;
27+
28+ if ( ProcessChunk ( header , body , chunkLength , target , idatData , ref flushedIdat ) )
29+ {
30+ break ;
31+ }
32+ }
2333 }
2434
25- static void Normalize ( byte [ ] data , int dataLength , Stream target )
35+ public static async Task NormalizeAsync ( Stream source , Stream target , Cancel cancel )
2636 {
37+ var header = new byte [ 8 ] ;
38+ await source . ReadExactlyAsync ( header , 0 , 8 , cancel ) ;
2739 target . Write ( pngSignature ) ;
2840
29- var idatData = new MemoryStream ( ) ;
30- var preIdatChunks = new List < byte [ ] > ( ) ;
31- var postIdatChunks = new List < byte [ ] > ( ) ;
32- var seenIdat = false ;
33- var offset = 8 ;
41+ using var idatData = new MemoryStream ( ) ;
42+ var flushedIdat = false ;
3443
35- while ( offset + 12 <= dataLength )
44+ while ( true )
3645 {
37- var chunkLength = BinaryPrimitives . ReadInt32BigEndian ( data . AsSpan ( offset ) ) ;
38- var totalChunkSize = 4 + 4 + chunkLength + 4 ;
46+ await source . ReadExactlyAsync ( header , 0 , 8 , cancel ) ;
47+ var chunkLength = BinaryPrimitives . ReadInt32BigEndian ( header . AsSpan ( 0 , 4 ) ) ;
3948
40- var isIdat = data [ offset + 4 ] == 'I' &&
41- data [ offset + 5 ] == 'D' &&
42- data [ offset + 6 ] == 'A' &&
43- data [ offset + 7 ] == 'T' ;
49+ var body = new byte [ chunkLength + 4 ] ;
50+ await source . ReadExactlyAsync ( body , 0 , body . Length , cancel ) ;
4451
45- if ( isIdat )
52+ if ( ProcessChunk ( header , body , chunkLength , target , idatData , ref flushedIdat ) )
4653 {
47- seenIdat = true ;
48- idatData . Write ( data , offset + 8 , chunkLength ) ;
54+ break ;
4955 }
50- else
51- {
52- var rawChunk = new byte [ totalChunkSize ] ;
53- Buffer . BlockCopy ( data , offset , rawChunk , 0 , totalChunkSize ) ;
54-
55- if ( seenIdat )
56- {
57- postIdatChunks . Add ( rawChunk ) ;
58- }
59- else
60- {
61- preIdatChunks . Add ( rawChunk ) ;
62- }
63- }
64-
65- offset += totalChunkSize ;
6656 }
57+ }
6758
68- foreach ( var chunk in preIdatChunks )
59+ static bool ProcessChunk ( byte [ ] header , byte [ ] body , int chunkLength , Stream target , MemoryStream idatData , ref bool flushedIdat )
60+ {
61+ var isIdat = header [ 4 ] == 'I' && header [ 5 ] == 'D' &&
62+ header [ 6 ] == 'A' && header [ 7 ] == 'T' ;
63+ var isIend = header [ 4 ] == 'I' && header [ 5 ] == 'E' &&
64+ header [ 6 ] == 'N' && header [ 7 ] == 'D' ;
65+
66+ if ( isIdat )
6967 {
70- target . Write ( chunk ) ;
68+ idatData . Write ( body , 0 , chunkLength ) ;
7169 }
72-
73- if ( idatData . Length > 0 )
70+ else
7471 {
75- var zlibBytes = idatData . ToArray ( ) ;
76-
77- byte [ ] decompressed ;
78- using ( var zlibInput = new MemoryStream ( zlibBytes ) )
79- using ( var zlibStream = new ZLibStream ( zlibInput , CompressionMode . Decompress ) )
80- using ( var decompressedStream = new MemoryStream ( ) )
72+ if ( ! flushedIdat && idatData . Length > 0 )
8173 {
82- zlibStream . CopyTo ( decompressedStream ) ;
83- decompressed = decompressedStream . ToArray ( ) ;
74+ flushedIdat = true ;
75+ WriteNormalizedIdat ( target , idatData ) ;
8476 }
8577
86- byte [ ] newIdatData ;
87- using ( var compressOutput = new MemoryStream ( ) )
88- {
89- using ( var zlibStream = new ZLibStream ( compressOutput , CompressionLevel . Optimal , leaveOpen : true ) )
90- {
91- zlibStream . Write ( decompressed ) ;
92- }
78+ target . Write ( header ) ;
79+ target . Write ( body ) ;
80+ }
9381
94- newIdatData = compressOutput . ToArray ( ) ;
95- }
82+ return isIend ;
83+ }
9684
97- WriteChunk ( target , idatType , newIdatData ) ;
85+ static void WriteNormalizedIdat ( Stream target , MemoryStream idatData )
86+ {
87+ var zlibBytes = idatData . ToArray ( ) ;
88+
89+ byte [ ] decompressed ;
90+ using ( var zlibInput = new MemoryStream ( zlibBytes ) )
91+ using ( var zlibStream = new ZLibStream ( zlibInput , CompressionMode . Decompress ) )
92+ using ( var decompressedStream = new MemoryStream ( ) )
93+ {
94+ zlibStream . CopyTo ( decompressedStream ) ;
95+ decompressed = decompressedStream . ToArray ( ) ;
9896 }
9997
100- foreach ( var chunk in postIdatChunks )
98+ byte [ ] newIdatData ;
99+ using ( var compressOutput = new MemoryStream ( ) )
101100 {
102- target . Write ( chunk ) ;
101+ using ( var zlibStream = new ZLibStream ( compressOutput , CompressionLevel . Optimal , leaveOpen : true ) )
102+ {
103+ zlibStream . Write ( decompressed ) ;
104+ }
105+
106+ newIdatData = compressOutput . ToArray ( ) ;
103107 }
108+
109+ WriteChunk ( target , idatType , newIdatData ) ;
104110 }
105111
106112 static void WriteChunk ( Stream target , byte [ ] type , byte [ ] data )
0 commit comments