Как обернуть существующий буфер памяти как DC для GDI

У меня есть буфер памяти, соответствующий разрешению моего экрана (1280x800 при 24 битах на пиксель), который содержит содержимое моего экрана при 24bpp. Я хочу преобразовать это в 8-битный пиксель (т.е. цветовую палитру полутонов в Windows). Сейчас я делаю это: 1. Используйте CreateDIBSection для выделения нового 24-битного буфера 1280x800 и доступа к нему как к DC, а также к простому буферу памяти. 2. Используйте memcpy для копирования из моего исходного буфера в этот новый буфер с шага 1. 3. Используйте BitBlt, чтобы позволить GDI выполнить преобразование цвета.

Я хочу избежать лишнего memcpy на шаге 2. Для этого я могу придумать два подхода:

а. Оберните мой исходный буфер памяти в DC, чтобы выполнить BitBlt прямо из него

б. Напишите свое собственное преобразование цвета с 24 бит на пиксель в 8 бит. Я не могу найти никакой информации о том, как Windows реализует это преобразование цвета полутонов. Кроме того, даже если я узнаю, я не буду использовать ускоренные функции GDI, к которым у BitBlt есть доступ.

Итак, как мне сделать (а) или (б)?

Благодарность!

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
2 803
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Хорошо, чтобы решить две части проблемы.

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

    private void LockUnlockBitsExample(PaintEventArgs e)
    {
    
       // Create a new bitmap.
       Bitmap bmp = new Bitmap("c:\fakePhoto.jpg");
    
       // Lock the bitmap's bits.  
       Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
       System.Drawing.Imaging.BitmapData bmpData =
             bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
             bmp.PixelFormat);
    
       // Get the address of the first line.
       IntPtr ptr = bmpData.Scan0;
    
       // Declare an array to hold the bytes of the bitmap.
       int bytes  = bmpData.Stride * bmp.Height;
       byte[] rgbValues = new byte[bytes];
    
       // Copy the RGB values into the array.
       System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
    
       // Set every third value to 255. A 24bpp bitmap will look red.  
       for (int counter = 2; counter < rgbValues.Length; counter += 3)
           rgbValues[counter] = 255;
    
       // Copy the RGB values back to the bitmap
       System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
    
       // Unlock the bits.
       bmp.UnlockBits(bmpData);
    
       // Draw the modified image.
       e.Graphics.DrawImage(bmp, 0, 150);
    }
    

Чтобы преобразовать содержимое в 8bpp, вы захотите использовать класс System.Drawing.Imaging.ColorMatrix. У меня нет под рукой правильных значений матрицы для полутонов, но этот пример оттенков серого и корректировка значений должны дать вам представление об эффекте:

Graphics g = e.Graphics;
Bitmap bmp = new Bitmap("sample.jpg");
g.FillRectangle(Brushes.White, this.ClientRectangle);

// Create a color matrix
// The value 0.6 in row 4, column 4 specifies the alpha value
float[][] matrixItems = {
                            new float[] {1, 0, 0, 0, 0},
                            new float[] {0, 1, 0, 0, 0},
                            new float[] {0, 0, 1, 0, 0},
                            new float[] {0, 0, 0, 0.6f, 0}, 
                            new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(matrixItems);

// Create an ImageAttributes object and set its color matrix
ImageAttributes imageAtt = new ImageAttributes();
imageAtt.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

// Now draw the semitransparent bitmap image.
g.DrawImage(bmp, this.ClientRectangle, 0.0f, 0.0f, bmp.Width, bmp.Height, 
            GraphicsUnit.Pixel, imageAtt);

imageAtt.Dispose();

Я постараюсь позже обновить значения матрицы для полутона, вероятно, там будет много значений 0,5 или 0,333!

Можно ли передать Scan0 в неуправляемый код для работы?

Dmitri Nesteruk 03.04.2009 23:03

Я так считаю, пока вы не снимаете блокировку, она фиксируется сборщиком мусора.

Ray Hayes 04.04.2009 17:23

Используйте CreateDIBitmap вместо CreateDIBSection.

Если вы хотите удалить копию (шаг 2), просто используйте CreateDIBSection, чтобы в первую очередь создать исходный буфер памяти. Затем вы можете просто создать совместимый контроллер домена для этого растрового изображения и использовать его в качестве источника для операции BitBlt.

Т.е. нет необходимости копировать память из буфера «простой памяти» в битовую карту CreateDIBSection перед копированием, если вы в первую очередь используете битовую карту CreateDIBSection вместо буфера «простой памяти».

В конце концов, буфер, выделенный с помощью CreateDIBSection, по сути, является просто буфером «простой памяти», совместимым с CreateCompatibleDC, что вы и ищете.

Описание процедуры CreateDIBSection в томе 3 Справочника программиста Win32 полностью неверно. Правильное описание см. На веб-сайте. docs.microsoft.com/en-us/windows/desktop/api/wingdi/…

user2707695 06.06.2019 11:53

Как вы вообще поместили содержимое экрана в этот буфер памяти 24bpp?

Очевидный способ избежать ненужного memcpy - это разрушить исходный снимок экрана, сначала создав 24bpp DIBSection и передав его функции screengrab в качестве целевого буфера.

Если это невозможно, вы все равно можете попытаться заставить GDI выполнить жесткую работу, создав BITMAPINFOHEADER, описывающий формат буфера памяти, и просто вызовите StretchDIBits, чтобы перенести его на свой 8bpp DIBSection.

Другие вопросы по теме