@@ -56,6 +56,11 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
56
56
/// </summary>
57
57
private const int ColorPaletteSize4Bit = 64 ;
58
58
59
+ /// <summary>
60
+ /// The color palette for an 1 bit image will have 2 entry's with 4 bytes for each entry.
61
+ /// </summary>
62
+ private const int ColorPaletteSize1Bit = 8 ;
63
+
59
64
/// <summary>
60
65
/// Used for allocating memory during processing operations.
61
66
/// </summary>
@@ -79,7 +84,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
79
84
private readonly bool writeV4Header ;
80
85
81
86
/// <summary>
82
- /// The quantizer for reducing the color count for 8-Bit images.
87
+ /// The quantizer for reducing the color count for 8-Bit, 4-Bit and 1-Bit images.
83
88
/// </summary>
84
89
private readonly IQuantizer quantizer ;
85
90
@@ -93,7 +98,7 @@ public BmpEncoderCore(IBmpEncoderOptions options, MemoryAllocator memoryAllocato
93
98
this . memoryAllocator = memoryAllocator ;
94
99
this . bitsPerPixel = options . BitsPerPixel ;
95
100
this . writeV4Header = options . SupportTransparency ;
96
- this . quantizer = options . Quantizer ?? KnownQuantizers . Octree ;
101
+ this . quantizer = options . Quantizer ?? KnownQuantizers . Wu ;
97
102
}
98
103
99
104
/// <summary>
@@ -180,6 +185,10 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
180
185
{
181
186
colorPaletteSize = ColorPaletteSize4Bit ;
182
187
}
188
+ else if ( this . bitsPerPixel == BmpBitsPerPixel . Pixel1 )
189
+ {
190
+ colorPaletteSize = ColorPaletteSize1Bit ;
191
+ }
183
192
184
193
var fileHeader = new BmpFileHeader (
185
194
type : BmpConstants . TypeMarkers . Bitmap ,
@@ -241,6 +250,10 @@ private void WriteImage<TPixel>(Stream stream, ImageFrame<TPixel> image)
241
250
case BmpBitsPerPixel . Pixel4 :
242
251
this . Write4BitColor ( stream , image ) ;
243
252
break ;
253
+
254
+ case BmpBitsPerPixel . Pixel1 :
255
+ this . Write1BitColor ( stream , image ) ;
256
+ break ;
244
257
}
245
258
}
246
259
@@ -325,7 +338,7 @@ private void Write16Bit<TPixel>(Stream stream, Buffer2D<TPixel> pixels)
325
338
}
326
339
327
340
/// <summary>
328
- /// Writes an 8 Bit image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
341
+ /// Writes an 8 bit image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
329
342
/// </summary>
330
343
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
331
344
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
@@ -349,7 +362,7 @@ private void Write8Bit<TPixel>(Stream stream, ImageFrame<TPixel> image)
349
362
}
350
363
351
364
/// <summary>
352
- /// Writes an 8 Bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
365
+ /// Writes an 8 bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
353
366
/// </summary>
354
367
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
355
368
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
@@ -377,7 +390,7 @@ private void Write8BitColor<TPixel>(Stream stream, ImageFrame<TPixel> image, Spa
377
390
}
378
391
379
392
/// <summary>
380
- /// Writes an 8 Bit gray image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
393
+ /// Writes an 8 bit gray image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
381
394
/// </summary>
382
395
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
383
396
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
@@ -415,7 +428,7 @@ private void Write8BitGray<TPixel>(Stream stream, ImageFrame<TPixel> image, Span
415
428
}
416
429
417
430
/// <summary>
418
- /// Writes an 4 Bit color image with a color palette. The color palette has 16 entry's with 4 bytes for each entry.
431
+ /// Writes an 4 bit color image with a color palette. The color palette has 16 entry's with 4 bytes for each entry.
419
432
/// </summary>
420
433
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
421
434
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
@@ -458,6 +471,52 @@ private void Write4BitColor<TPixel>(Stream stream, ImageFrame<TPixel> image)
458
471
}
459
472
}
460
473
474
+ /// <summary>
475
+ /// Writes a 1 bit image with a color palette. The color palette has 2 entry's with 4 bytes for each entry.
476
+ /// </summary>
477
+ /// <typeparam name="TPixel">The type of the pixel.</typeparam>
478
+ /// <param name="stream">The <see cref="Stream"/> to write to.</param>
479
+ /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param>
480
+ private void Write1BitColor < TPixel > ( Stream stream , ImageFrame < TPixel > image )
481
+ where TPixel : unmanaged, IPixel < TPixel >
482
+ {
483
+ using IQuantizer < TPixel > frameQuantizer = this . quantizer . CreatePixelSpecificQuantizer < TPixel > ( this . configuration , new QuantizerOptions ( )
484
+ {
485
+ MaxColors = 2
486
+ } ) ;
487
+ using IndexedImageFrame < TPixel > quantized = frameQuantizer . BuildPaletteAndQuantizeFrame ( image , image . Bounds ( ) ) ;
488
+ using IMemoryOwner < byte > colorPaletteBuffer = this . memoryAllocator . AllocateManagedByteBuffer ( ColorPaletteSize1Bit , AllocationOptions . Clean ) ;
489
+
490
+ Span < byte > colorPalette = colorPaletteBuffer . GetSpan ( ) ;
491
+ ReadOnlySpan < TPixel > quantizedColorPalette = quantized . Palette . Span ;
492
+ this . WriteColorPalette ( stream , quantizedColorPalette , colorPalette ) ;
493
+
494
+ ReadOnlySpan < byte > quantizedPixelRow = quantized . GetPixelRowSpan ( 0 ) ;
495
+ int rowPadding = quantizedPixelRow . Length % 8 != 0 ? this . padding - 1 : this . padding ;
496
+ for ( int y = image . Height - 1 ; y >= 0 ; y -- )
497
+ {
498
+ quantizedPixelRow = quantized . GetPixelRowSpan ( y ) ;
499
+
500
+ int endIdx = quantizedPixelRow . Length % 8 == 0 ? quantizedPixelRow . Length : quantizedPixelRow . Length - 8 ;
501
+ for ( int i = 0 ; i < endIdx ; i += 8 )
502
+ {
503
+ Write1BitPalette ( stream , i , i + 8 , quantizedPixelRow ) ;
504
+ }
505
+
506
+ if ( quantizedPixelRow . Length % 8 != 0 )
507
+ {
508
+ int startIdx = quantizedPixelRow . Length - 7 ;
509
+ endIdx = quantizedPixelRow . Length ;
510
+ Write1BitPalette ( stream , startIdx , endIdx , quantizedPixelRow ) ;
511
+ }
512
+
513
+ for ( int i = 0 ; i < rowPadding ; i ++ )
514
+ {
515
+ stream . WriteByte ( 0 ) ;
516
+ }
517
+ }
518
+ }
519
+
461
520
/// <summary>
462
521
/// Writes the color palette to the stream. The color palette has 4 bytes for each entry.
463
522
/// </summary>
@@ -478,5 +537,25 @@ private void WriteColorPalette<TPixel>(Stream stream, ReadOnlySpan<TPixel> quant
478
537
479
538
stream . Write ( colorPalette ) ;
480
539
}
540
+
541
+ /// <summary>
542
+ /// Writes a 1-bit palette.
543
+ /// </summary>
544
+ /// <param name="stream">The stream to write the palette to.</param>
545
+ /// <param name="startIdx">The start index.</param>
546
+ /// <param name="endIdx">The end index.</param>
547
+ /// <param name="quantizedPixelRow">A quantized pixel row.</param>
548
+ private static void Write1BitPalette ( Stream stream , int startIdx , int endIdx , ReadOnlySpan < byte > quantizedPixelRow )
549
+ {
550
+ int shift = 7 ;
551
+ byte indices = 0 ;
552
+ for ( int j = startIdx ; j < endIdx ; j ++ )
553
+ {
554
+ indices = ( byte ) ( indices | ( ( byte ) ( quantizedPixelRow [ j ] & 1 ) << shift ) ) ;
555
+ shift -- ;
556
+ }
557
+
558
+ stream . WriteByte ( indices ) ;
559
+ }
481
560
}
482
561
}
0 commit comments