33
44using System . Buffers ;
55using System . Buffers . Binary ;
6+ using System . IO ;
67using System . Runtime . InteropServices ;
78using SixLabors . ImageSharp . Advanced ;
89using SixLabors . ImageSharp . Common . Helpers ;
1112using SixLabors . ImageSharp . PixelFormats ;
1213using SixLabors . ImageSharp . Processing ;
1314using SixLabors . ImageSharp . Processing . Processors . Quantization ;
15+ using static System . Net . Mime . MediaTypeNames ;
1416
1517namespace SixLabors . ImageSharp . Formats . Bmp ;
1618
@@ -92,6 +94,15 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
9294 /// </summary>
9395 private readonly IPixelSamplingStrategy pixelSamplingStrategy ;
9496
97+ /// <inheritdoc cref="BmpDecoderOptions.ProcessedAlphaMask"/>
98+ private readonly bool processedAlphaMask ;
99+
100+ /// <inheritdoc cref="BmpDecoderOptions.SkipFileHeader"/>
101+ private readonly bool skipFileHeader ;
102+
103+ /// <inheritdoc cref="BmpDecoderOptions.UseDoubleHeight"/>
104+ private readonly bool isDoubleHeight ;
105+
95106 /// <summary>
96107 /// Initializes a new instance of the <see cref="BmpEncoderCore"/> class.
97108 /// </summary>
@@ -104,6 +115,9 @@ public BmpEncoderCore(BmpEncoder encoder, MemoryAllocator memoryAllocator)
104115 this . quantizer = encoder . Quantizer ?? KnownQuantizers . Octree ;
105116 this . pixelSamplingStrategy = encoder . PixelSamplingStrategy ;
106117 this . infoHeaderType = encoder . SupportTransparency ? BmpInfoHeaderType . WinVersion4 : BmpInfoHeaderType . WinVersion3 ;
118+ this . processedAlphaMask = encoder . ProcessedAlphaMask ;
119+ this . skipFileHeader = encoder . SkipFileHeader ;
120+ this . isDoubleHeight = encoder . UseDoubleHeight ;
107121 }
108122
109123 /// <summary>
@@ -154,11 +168,23 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
154168 _ => BmpInfoHeader . SizeV3
155169 } ;
156170
157- BmpInfoHeader infoHeader = this . CreateBmpInfoHeader ( image . Width , image . Height , infoHeaderSize , bpp , bytesPerLine , metadata , iccProfileData ) ;
171+ // for ico/cur encoder.
172+ int height = image . Height ;
173+ if ( this . isDoubleHeight )
174+ {
175+ height <<= 1 ;
176+ }
177+
178+ BmpInfoHeader infoHeader = this . CreateBmpInfoHeader ( image . Width , height , infoHeaderSize , bpp , bytesPerLine , metadata , iccProfileData ) ;
158179
159180 Span < byte > buffer = stackalloc byte [ infoHeaderSize ] ;
160181
161- WriteBitmapFileHeader ( stream , infoHeaderSize , colorPaletteSize , iccProfileSize , infoHeader , buffer ) ;
182+ // for ico/cur encoder.
183+ if ( ! this . skipFileHeader )
184+ {
185+ WriteBitmapFileHeader ( stream , infoHeaderSize , colorPaletteSize , iccProfileSize , infoHeader , buffer ) ;
186+ }
187+
162188 this . WriteBitmapInfoHeader ( stream , infoHeader , buffer , infoHeaderSize ) ;
163189 this . WriteImage ( configuration , stream , image ) ;
164190 WriteColorProfile ( stream , iccProfileData , buffer ) ;
@@ -455,6 +481,11 @@ private void Write8BitPixelData<TPixel>(Configuration configuration, Stream stre
455481 {
456482 this . Write8BitColor ( configuration , stream , image , colorPalette ) ;
457483 }
484+
485+ if ( this . processedAlphaMask )
486+ {
487+ ProcessedAlphaMask ( stream , image ) ;
488+ }
458489 }
459490
460491 /// <summary>
@@ -572,6 +603,11 @@ private void Write4BitPixelData<TPixel>(Configuration configuration, Stream stre
572603 stream . WriteByte ( 0 ) ;
573604 }
574605 }
606+
607+ if ( this . processedAlphaMask )
608+ {
609+ ProcessedAlphaMask ( stream , image ) ;
610+ }
575611 }
576612
577613 /// <summary>
@@ -629,6 +665,11 @@ private void Write2BitPixelData<TPixel>(Configuration configuration, Stream stre
629665 stream . WriteByte ( 0 ) ;
630666 }
631667 }
668+
669+ if ( this . processedAlphaMask )
670+ {
671+ ProcessedAlphaMask ( stream , image ) ;
672+ }
632673 }
633674
634675 /// <summary>
@@ -679,6 +720,11 @@ private void Write1BitPixelData<TPixel>(Configuration configuration, Stream stre
679720 stream . WriteByte ( 0 ) ;
680721 }
681722 }
723+
724+ if ( this . processedAlphaMask )
725+ {
726+ ProcessedAlphaMask ( stream , image ) ;
727+ }
682728 }
683729
684730 /// <summary>
@@ -722,4 +768,35 @@ private static void Write1BitPalette(Stream stream, int startIdx, int endIdx, Re
722768
723769 stream . WriteByte ( indices ) ;
724770 }
771+
772+ private static void ProcessedAlphaMask < TPixel > ( Stream stream , Image < TPixel > image )
773+ where TPixel : unmanaged, IPixel < TPixel >
774+ {
775+ Rgba32 rgba = default ;
776+ int arrayWidth = image . Width / 8 ;
777+ int padding = arrayWidth % 4 ;
778+ if ( padding is not 0 )
779+ {
780+ padding = 4 - padding ;
781+ }
782+
783+ Span < byte > mask = stackalloc byte [ arrayWidth ] ;
784+ for ( int y = image . Height - 1 ; y >= 0 ; y -- )
785+ {
786+ mask . Clear ( ) ;
787+ for ( int x = 0 ; x < image . Width ; x ++ )
788+ {
789+ int bit = x % 8 ;
790+ int i = x / 8 ;
791+ TPixel pixel = image [ x , y ] ;
792+ pixel . ToRgba32 ( ref rgba ) ;
793+ if ( rgba . A is not 0 )
794+ {
795+ mask [ i ] &= unchecked ( ( byte ) ( 0b10000000 >> bit ) ) ;
796+ }
797+ }
798+
799+ stream . Write ( mask ) ;
800+ }
801+ }
725802}
0 commit comments