Windows Forms: То, чтобы заставлять курсор побитово отобразить частично прозрачный

CPAN является, вероятно, лучшим способом пойти. Смотрите на Термин:: Screen:Uni:

require Term::Screen::Uni;
my $scr = new Term::Screen::Uni;

$scr->clrscr()

8
задан Pedery 13 November 2011 в 17:39
поделиться

5 ответов

GDI + имеет ряд проблем, связанных с альфа-смешиванием при взаимодействии с GDI (и Win32). В этом случае вызов bmp. GetHbitmap () смешает ваше изображение с черным фоном. Статья на CodeProject дает более подробную информацию о проблеме и решении, которое использовалось для добавления изображений в список изображений.

Вы должны иметь возможность использовать аналогичный код, чтобы заставить HBITMAP использовать для маска:

[DllImport("kernel32.dll")]
public static extern bool RtlMoveMemory(IntPtr dest, IntPtr source, int dwcount);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDIBSection(IntPtr hdc, [In, MarshalAs(UnmanagedType.LPStruct)]BITMAPINFO pbmi, uint iUsage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);

public static IntPtr GetBlendedHBitmap(Bitmap bitmap)
{
    BITMAPINFO bitmapInfo = new BITMAPINFO();
    bitmapInfo.biSize = 40;
    bitmapInfo.biBitCount = 32;
    bitmapInfo.biPlanes = 1;

    bitmapInfo.biWidth = bitmap.Width;
    bitmapInfo.biHeight = -bitmap.Height;

    IntPtr pixelData;
    IntPtr hBitmap = CreateDIBSection(
        IntPtr.Zero, bitmapInfo, 0, out pixelData, IntPtr.Zero, 0);

    Rectangle bounds = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
    BitmapData bitmapData = bitmap.LockBits(
        bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb );
    RtlMoveMemory(
        pixelData, bitmapData.Scan0, bitmap.Height * bitmapData.Stride);

    bitmap.UnlockBits(bitmapData);
    return hBitmap;
}
6
ответ дан 5 December 2019 в 19:02
поделиться

Когда я запускаю ваш код для изменения изображения в графическом блоке с помощью фоновой сетки, я получаю желаемый эффект, не меняя код. Возможно, ваше изображение нарисовано поверх чего-то темного ...

0
ответ дан 5 December 2019 в 19:02
поделиться

попробуйте понизить Значение синего равно 0,7 или .6 и посмотрите, ближе ли оно к тому, что вы хотите.

Вот хороший сайт, объясняющий ColorMatrix :

0
ответ дан 5 December 2019 в 19:02
поделиться

Простите меня, если мое предложение слишком упрощенное (я все еще новичок в C #), но я нашел это на сайте MSDN и, возможно, этот может указать вам на правильное направление?

/ матовый

0
ответ дан 5 December 2019 в 19:02
поделиться

Недавно я прочитал, что эта проблема возникает из-за требования предварительно умноженных альфа-каналов в растровых изображениях. Я не уверен, была ли это проблема с курсорами Windows или GDI, и, хоть убей, я не могу найти документацию по этому поводу. Итак, хотя это объяснение может быть правильным, а может и нет, следующий код действительно делает то, что вы хотите, используя предварительно умноженный альфа-канал в битовой карте курсора.

public class CustomCursor
{
  // alphaLevel is a value between 0 and 255. For 50% transparency, use 128.
  public Cursor CreateCursorFromBitmap(Bitmap bitmap, byte alphaLevel, Point hotSpot)
  {
    Bitmap cursorBitmap = null;
    External.ICONINFO iconInfo = new External.ICONINFO();
    Rectangle rectangle = new Rectangle(0, 0, bitmap.Width, bitmap.Height);

    try
    {
      // Here, the premultiplied alpha channel is specified
      cursorBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppPArgb);

      // I'm assuming the source bitmap can be locked in a 24 bits per pixel format
      BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
      BitmapData cursorBitmapData = cursorBitmap.LockBits(rectangle, ImageLockMode.WriteOnly, cursorBitmap.PixelFormat);

      // Use either SafeCopy() or UnsafeCopy() to set the bitmap contents
      SafeCopy(bitmapData, cursorBitmapData, alphaLevel);
      //UnsafeCopy(bitmapData, cursorBitmapData, alphaLevel);

      cursorBitmap.UnlockBits(cursorBitmapData);
      bitmap.UnlockBits(bitmapData);

      if (!External.GetIconInfo(cursorBitmap.GetHicon(), out iconInfo))
        throw new Exception("GetIconInfo() failed.");

      iconInfo.xHotspot = hotSpot.X;
      iconInfo.yHotspot = hotSpot.Y;
      iconInfo.IsIcon = false;

      IntPtr cursorPtr = External.CreateIconIndirect(ref iconInfo);
      if (cursorPtr == IntPtr.Zero)
        throw new Exception("CreateIconIndirect() failed.");

      return (new Cursor(cursorPtr));
    }
    finally
    {
      if (cursorBitmap != null)
        cursorBitmap.Dispose();
      if (iconInfo.ColorBitmap != IntPtr.Zero)
        External.DeleteObject(iconInfo.ColorBitmap);
      if (iconInfo.MaskBitmap != IntPtr.Zero)
        External.DeleteObject(iconInfo.MaskBitmap);
    }
  }

  private void SafeCopy(BitmapData srcData, BitmapData dstData, byte alphaLevel)
  {
    for (int y = 0; y < srcData.Height; y++)
      for (int x = 0; x < srcData.Width; x++)
      {
        byte b = Marshal.ReadByte(srcData.Scan0, y * srcData.Stride + x * 3);
        byte g = Marshal.ReadByte(srcData.Scan0, y * srcData.Stride + x * 3 + 1);
        byte r = Marshal.ReadByte(srcData.Scan0, y * srcData.Stride + x * 3 + 2);

        Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4, b);
        Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4 + 1, g);
        Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4 + 2, r);
        Marshal.WriteByte(dstData.Scan0, y * dstData.Stride + x * 4 + 3, alphaLevel);
      }
  }

  private unsafe void UnsafeCopy(BitmapData srcData, BitmapData dstData, byte alphaLevel)
  {
    for (int y = 0; y < srcData.Height; y++)
    {
      byte* srcRow = (byte*)srcData.Scan0 + (y * srcData.Stride);
      byte* dstRow = (byte*)dstData.Scan0 + (y * dstData.Stride);

      for (int x = 0; x < srcData.Width; x++)
      {
        dstRow[x * 4] = srcRow[x * 3];
        dstRow[x * 4 + 1] = srcRow[x * 3 + 1];
        dstRow[x * 4 + 2] = srcRow[x * 3 + 2];
        dstRow[x * 4 + 3] = alphaLevel;
      }
    }
  }
}

Объявления pinvoke находятся в классе External, показанном здесь:

public class External
{
  [StructLayout(LayoutKind.Sequential)]
  public struct ICONINFO
  {
    public bool IsIcon;
    public int xHotspot;
    public int yHotspot;
    public IntPtr MaskBitmap;
    public IntPtr ColorBitmap;
  };

  [DllImport("user32.dll")]
  public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);

  [DllImport("user32.dll")]
  public static extern IntPtr CreateIconIndirect([In] ref ICONINFO piconinfo);

  [DllImport("gdi32.dll")]
  public static extern bool DeleteObject(IntPtr hObject);

  [DllImport("gdi32.dll")]
  public static extern IntPtr CreateBitmap(int nWidth, int nHeight, uint cPlanes, uint cBitsPerPel, IntPtr lpvBits);
}

Несколько примечаний к коду:

  1. Чтобы использовать небезопасный метод UnsafeCopy (), вы должны скомпилировать с флагом / unsafe.
  2. Методы копирования растровых изображений уродливы, особенно безопасный метод, который использует Marshal .ReadByte () / Marshal.WriteByte () вызывает. Должен быть более быстрый способ копирования данных растрового изображения с одновременной вставкой альфа-байтов.
  3. Я предполагаю, что исходное растровое изображение может быть заблокировано в формате 24 бита на пиксель. Однако это не должно быть проблемой.
3
ответ дан 5 December 2019 в 19:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: