screen_capturer icon indicating copy to clipboard operation
screen_capturer copied to clipboard

CaptureMode.screen now working on Windows 10

Open apoleo88 opened this issue 1 year ago • 6 comments

All the other CaptureMode works, but CaptureMode.screen doesn't.

The CapturedData? capturedData will return null, and if the path is specified no file is created.

No error is showing.

apoleo88 avatar Nov 01 '24 16:11 apoleo88

i have the same issue and i need a solution

Marco-Nagy avatar Nov 03 '24 14:11 Marco-Nagy

+1

sbamniya avatar Dec 14 '24 18:12 sbamniya

+1

pravindodia avatar Mar 06 '25 09:03 pravindodia

i have the same problem

danteCarvalho avatar Apr 04 '25 04:04 danteCarvalho

I might be able to suggest a PR

galaxy-s10 avatar Aug 07 '25 07:08 galaxy-s10

This is an issue with the plugin, and while I was working on it, I created some custom script that worked for me. It captures the image in bmp format, and then in the dart code, I convert it to png file to the given path.

screenshot.cc

#include <windows.h>
#include <fstream>
#include <iostream>

extern "C" __declspec(dllexport) void CaptureScreenshot() {
    std::cout << "Starting screenshot capture..." << std::endl;

    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);
    std::cout << "Screen dimensions: " << width << "x" << height << std::endl;

    HDC hdcDesktop = GetDC(NULL); // Get desktop DC
    HDC hdcCompatible = CreateCompatibleDC(hdcDesktop);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdcDesktop, width, height);

    SelectObject(hdcCompatible, hBitmap);

    if (!BitBlt(hdcCompatible, 0, 0, width, height, hdcDesktop, 0, 0, SRCCOPY)) {
        std::cerr << "Failed to perform BitBlt operation." << std::endl;
        DeleteDC(hdcCompatible);
        ReleaseDC(NULL, hdcDesktop);
        return;
    }

    // Prepare bitmap headers
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;

    BITMAP bmp;
    GetObject(hBitmap, sizeof(BITMAP), &bmp);

    int rowSize = ((bmp.bmWidth * 24 + 31) / 32) * 4; // Rows must be padded to 4 bytes
    int imageSize = rowSize * bmp.bmHeight;

    fileHeader.bfType = 0x4D42; // 'BM' for Bitmap
    fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + imageSize;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    infoHeader.biSize = sizeof(BITMAPINFOHEADER);
    infoHeader.biWidth = bmp.bmWidth;
    infoHeader.biHeight = -bmp.bmHeight; // Negative for top-down DIB
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 24; // Assuming 24-bit color depth
    infoHeader.biCompression = BI_RGB;
    infoHeader.biSizeImage = imageSize;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed = 0;
    infoHeader.biClrImportant = 0;

    // Create file and write headers and pixel data
    std::ofstream outFile("screenshot.bmp", std::ios::binary);
    if (!outFile) {
        std::cerr << "Failed to create file." << std::endl;
        DeleteDC(hdcCompatible);
        DeleteObject(hBitmap);
        ReleaseDC(NULL, hdcDesktop);
        return;
    }

    // Write BMP headers
    outFile.write(reinterpret_cast<char*>(&fileHeader), sizeof(fileHeader));
    outFile.write(reinterpret_cast<char*>(&infoHeader), sizeof(infoHeader));

    // Write pixel data
    BYTE* buffer = new BYTE[imageSize];
    GetDIBits(hdcCompatible, hBitmap, 0, bmp.bmHeight, buffer, reinterpret_cast<BITMAPINFO*>(&infoHeader), DIB_RGB_COLORS);
    outFile.write(reinterpret_cast<char*>(buffer), imageSize);

    // Cleanup
    delete[] buffer;
    outFile.close();

    DeleteDC(hdcCompatible);
    DeleteObject(hBitmap);
    ReleaseDC(NULL, hdcDesktop);

    std::cout << "Screenshot captured and saved as 'screenshot.bmp'." << std::endl;
}

screen_capture_service.dart

import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data';
import 'package:image/image.dart' as img;

class ScreenCaptureService {
  Future<void> captureScreenshot(String path) async {
    try {
      print('capture screenshot: native.dll');
      final DynamicLibrary nativeLib = DynamicLibrary.open('native.dll');
      final captureScreenshot =
          nativeLib.lookupFunction<Void Function(), void Function()>(
        'CaptureScreenshot',
      );
      print('capturing');
      captureScreenshot();
      await _convertBmpToPng('screenshot.bmp', path);
      print('Screenshot captured successfully');
    } catch (e) {
      print("Failed to capture screenshot: $e");
    }
  }

  Future<void> _convertBmpToPng(String bmpPath, String pngPath) async {
    // Read the BMP file
    final File bmpFile = File(bmpPath);
    final Uint8List bmpBytes = await bmpFile.readAsBytes();
    img.Image? image = img.decodeImage(bmpBytes);

    if (image != null) {
      // Convert to PNG
      List<int> pngBytes = img.encodePng(image);

      // Save the PNG to a specific file location
      final File pngFile = File(pngPath);
      await pngFile.writeAsBytes(pngBytes);
      print('Screenshot converted to PNG and saved successfully');
    } else {
      print('Failed to decode BMP image');
    }
  }
}

native.dll is compiled version of screenshot.cc.

capture.dart

if (Platform.isWindows) {
  final ScreenCaptureService _screenCaptureService = ScreenCaptureService();
  await _screenCaptureService.captureScreenshot("$path/$key.png");
  print('saved file to $path/$key.png');
} else {
  await ScreenCapturer.instance.capture(
      mode: CaptureMode.screen,
      imagePath: "$path/$key.png",
      silent: true,
      copyToClipboard: false);
}

sbamniya avatar Aug 07 '25 09:08 sbamniya