@@ -500,83 +500,71 @@ Future<void> _decodeImageFromListAsync(Uint8List list, ImageDecoderCallback call
500
500
final FrameInfo frameInfo = await codec.getNextFrame ();
501
501
callback (frameInfo.image);
502
502
}
503
-
504
- // Encodes the input pixels into a BMP file that supports transparency.
505
- //
506
- // The `pixels` should be the scanlined raw pixels, 4 bytes per pixel, from left
507
- // to right, then from top to down. The order of the 4 bytes of pixels is
508
- // decided by `format`.
509
503
Future <Codec > _createBmp (
510
504
Uint8List pixels,
511
505
int width,
512
506
int height,
513
507
int rowBytes,
514
508
PixelFormat format,
515
509
) {
516
- late bool swapRedBlue;
517
- switch (format) {
518
- case PixelFormat .bgra8888:
519
- swapRedBlue = true ;
520
- break ;
521
- case PixelFormat .rgba8888:
522
- swapRedBlue = false ;
523
- break ;
524
- }
525
-
526
510
// See https://en.wikipedia.org/wiki/BMP_file_format for format examples.
527
- // The header is in the 108-byte BITMAPV4HEADER format, or as called by
528
- // Chromium, WindowsV4. Do not use the 56-byte or 52-byte Adobe formats, since
529
- // they're not supported.
530
- const int dibSize = 0x6C /* 108: BITMAPV4HEADER */ ;
531
- const int headerSize = dibSize + 0x0E ;
532
- final int bufferSize = headerSize + (width * height * 4 );
511
+ final int bufferSize = 0x36 + (width * height * 4 );
533
512
final ByteData bmpData = ByteData (bufferSize);
534
513
// 'BM' header
535
- bmpData.setUint16 (0x00 , 0x424D , Endian .big);
514
+ bmpData.setUint8 (0x00 , 0x42 );
515
+ bmpData.setUint8 (0x01 , 0x4D );
536
516
// Size of data
537
517
bmpData.setUint32 (0x02 , bufferSize, Endian .little);
538
518
// Offset where pixel array begins
539
- bmpData.setUint32 (0x0A , headerSize , Endian .little);
519
+ bmpData.setUint32 (0x0A , 0x36 , Endian .little);
540
520
// Bytes in DIB header
541
- bmpData.setUint32 (0x0E , dibSize , Endian .little);
542
- // Width
521
+ bmpData.setUint32 (0x0E , 0x28 , Endian .little);
522
+ // width
543
523
bmpData.setUint32 (0x12 , width, Endian .little);
544
- // Height
524
+ // height
545
525
bmpData.setUint32 (0x16 , height, Endian .little);
546
- // Color panes (always 1)
526
+ // Color panes
547
527
bmpData.setUint16 (0x1A , 0x01 , Endian .little);
548
- // bpp: 32
549
- bmpData.setUint16 (0x1C , 32 , Endian .little);
550
- // Compression method is BITFIELDS to enable bit fields
551
- bmpData.setUint32 (0x1E , 3 , Endian .little);
552
- // Raw bitmap data size
528
+ // 32 bpp
529
+ bmpData.setUint16 (0x1C , 0x20 , Endian .little);
530
+ // no compression
531
+ bmpData.setUint32 (0x1E , 0x00 , Endian .little);
532
+ // raw bitmap data size
553
533
bmpData.setUint32 (0x22 , width * height, Endian .little);
554
- // Print DPI width
534
+ // print DPI width
555
535
bmpData.setUint32 (0x26 , width, Endian .little);
556
- // Print DPI height
536
+ // print DPI height
557
537
bmpData.setUint32 (0x2A , height, Endian .little);
558
- // Colors in the palette
538
+ // colors in the palette
559
539
bmpData.setUint32 (0x2E , 0x00 , Endian .little);
560
- // Important colors
540
+ // important colors
561
541
bmpData.setUint32 (0x32 , 0x00 , Endian .little);
562
- // Bitmask R
563
- bmpData.setUint32 (0x36 , swapRedBlue ? 0x00FF0000 : 0x000000FF , Endian .little);
564
- // Bitmask G
565
- bmpData.setUint32 (0x3A , 0x0000FF00 , Endian .little);
566
- // Bitmask B
567
- bmpData.setUint32 (0x3E , swapRedBlue ? 0x000000FF : 0x00FF0000 , Endian .little);
568
- // Bitmask A
569
- bmpData.setUint32 (0x42 , 0xFF000000 , Endian .little);
570
-
571
- int destinationByte = headerSize;
572
- final Uint32List combinedPixels = Uint32List .sublistView (pixels);
573
- // BMP is scanlined from bottom to top. Rearrange here.
574
- for (int rowCount = height - 1 ; rowCount >= 0 ; rowCount -= 1 ) {
575
- int sourcePixel = rowCount * rowBytes;
576
- for (int colCount = 0 ; colCount < width; colCount += 1 ) {
577
- bmpData.setUint32 (destinationByte, combinedPixels[sourcePixel], Endian .little);
578
- destinationByte += 4 ;
579
- sourcePixel += 1 ;
542
+
543
+
544
+ int pixelDestinationIndex = 0 ;
545
+ late bool swapRedBlue;
546
+ switch (format) {
547
+ case PixelFormat .bgra8888:
548
+ swapRedBlue = true ;
549
+ break ;
550
+ case PixelFormat .rgba8888:
551
+ swapRedBlue = false ;
552
+ break ;
553
+ }
554
+ for (int pixelSourceIndex = 0 ; pixelSourceIndex < pixels.length; pixelSourceIndex += 4 ) {
555
+ final int r = swapRedBlue ? pixels[pixelSourceIndex + 2 ] : pixels[pixelSourceIndex];
556
+ final int b = swapRedBlue ? pixels[pixelSourceIndex] : pixels[pixelSourceIndex + 2 ];
557
+ final int g = pixels[pixelSourceIndex + 1 ];
558
+ final int a = pixels[pixelSourceIndex + 3 ];
559
+
560
+ // Set the pixel past the header data.
561
+ bmpData.setUint8 (pixelDestinationIndex + 0x36 , r);
562
+ bmpData.setUint8 (pixelDestinationIndex + 0x37 , g);
563
+ bmpData.setUint8 (pixelDestinationIndex + 0x38 , b);
564
+ bmpData.setUint8 (pixelDestinationIndex + 0x39 , a);
565
+ pixelDestinationIndex += 4 ;
566
+ if (rowBytes != width && pixelSourceIndex % width == 0 ) {
567
+ pixelSourceIndex += rowBytes - width;
580
568
}
581
569
}
582
570
@@ -815,3 +803,4 @@ class FragmentProgram {
815
803
required Float32List floatUniforms,
816
804
}) => throw UnsupportedError ('FragmentProgram is not supported for the CanvasKit or HTML renderers.' );
817
805
}
806
+
0 commit comments