инициализировать изображение MFC для сплошного цвета - PullRequest
0 голосов
/ 05 сентября 2018

Я не использую c ++ или MFC / ATL и т. Д., Поэтому предположим, что я ничего не знаю.

Вся картинка в том, что мне нужно принять PNG со слоем прозрачности и записать его в формате JPEG с указанным сжатием для передачи в другую систему.

Что я хотел бы знать здесь, так это как я могу инициализировать целевую структуру CImage сплошным белым цветом?

Я уже сделал это (да, я знаю, что у него есть другие стилистические проблемы)

    void ClipBoardFuncs::savePNGASJPEG(char filePath[256], char errorBuff[256]) {
    int sizeOfErrorBuff = 256;

        CImage imagePNG;
        CImage imageJPG;
        int xPNG, yPNG = 0;
        imagePNG.Load(filePath);

        xPNG = imagePNG.GetWidth();
        yPNG = imagePNG.GetHeight();

        //Create my target JPG same size and bit depth specifiying that there is no alpha channel (dwflag last param)
        imageJPG.Create(xPNG, yPNG, imagePNG.GetBPP(), 0);

        //Let there be white....
        for (int x = 0; x <= xPNG; x++)
        {
            for (int y = 0; y <= yPNG; y++)
            {
                imageJPG.SetPixelRGB(x, y, 255, 255, 255);
            }
        }

        //Copy the image over onto on the white
        //BitBlt copies everything....
        //imagePNG.BitBlt(imageJPG.GetDC(), 0, 0);
        //Draw is more like the C# draw examples I've seen
        imagePNG.Draw(imageJPG.GetDC(), 0, 0);

        imageJPG.ReleaseDC();

        HRESULT hr = NULL;
        hr = imageJPG.Save(filePath, Gdiplus::ImageFormatJPEG);
        imagePNG.Destroy();
        imagePNG.ReleaseGDIPlus();

        imageJPG.Destroy();
        imageJPG.ReleaseGDIPlus();


        LPCTSTR error = _com_error(hr).ErrorMessage();
        strncpy_s(errorBuff, sizeOfErrorBuff, _com_error(hr).ErrorMessage(), _TRUNCATE);

} 

Прекрасные люди на C # имеют такой ответ:

Преобразование прозрачного PNG в JPG с не черным цветом фона

Но мне нужно решение C ++ MFC для использования в качестве экспортируемой функции в DLL.

Под экспортированной функцией я подразумеваю ту же архитектуру, что и в kernel32.dll - извините, я не знаю терминологию, чтобы отличать такого рода DLL от библиотеки с COM-объектами.

Кто-нибудь может предложить более быстрый способ инициализации структуры imageJPEG для сплошного белого цвета, чем вложенные циклы x / y for, которые у меня здесь есть?

Приветствия

4GLGuy

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Инициализация может быть сделана с помощью Rectangle или FillRect (для этого, вероятно, предпочтительнее будет FillRect - Rectangle рисует контур прямоугольника в текущем цвете пера, который мы, вероятно, не хотим ).

Итак, последовательность выглядит примерно так:

CImage png;
png.Load(pDoc->filename);

CRect rect{ 0, 0, png.GetWidth(), png.GetHeight() };

CImage jpeg;
jpeg.Create(rect.Width(), rect.Height(), png.GetBPP());

auto dc = jpeg.GetDC();
HBRUSH white = CreateSolidBrush(RGB(255, 255, 255));
FillRect(dc, &rect, white);

png.Draw(dc, 0, 0);
jpeg.ReleaseDC();

jpeg.Save(L"Insert File name here", Gdiplus::ImageFormatJPEG);

jpeg.Destroy();
jpeg.ReleaseGDIPlus();
png.ReleaseGDIPlus();

GDI + достаточно «умный», поэтому, когда вы делаете .Draw с изображением, имеющим альфа-канал, он учитывает этот канал без необходимости использования TransparentBlt (или чего-либо подобного).

SetTransparentColor будет не работать на то, что вы пытаетесь сделать здесь. SetTransparentColor для изображения, которое не имеет альфа-канал («слой прозрачности»). Затем вы используете его, чтобы выбрать цвет, который будет обрабатываться так, как если бы он был прозрачным, что, безусловно, может быть полезным, но не совсем того, что вам нужно.

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

0 голосов
/ 05 сентября 2018
imagePNG.Draw(imageJPG.GetDC(), 0, 0);

Каждый вызов GetDC должен иметь последующий вызов ReleaseDC. См. Также CImage::GetDC документацию.

CImage::GetDC предоставляет дескриптор контекста устройства памяти. Этот дескриптор можно использовать для рисования с использованием стандартных функций GDI. Позже ручка должна быть очищена с помощью CImage::ReleaseDC.

CImage::Draw может не знать, что такое прозрачный цвет. Вы должны использовать TransparentBlt, чтобы определить прозрачный цвет. Например, заменить красный цвет на белый:

HDC hdc = imageJPG.GetDC();
CDC dc;
dc.Attach(hdc);
CRect rc(0, 0, xPNG, yPNG);
dc.FillSolidRect(&rc, RGB(255, 255, 255));
dc.Detach();

imagePNG.TransparentBlt(hdc, rc, RGB(255, 0, 0));//replace red with white
imageJPG.ReleaseDC();

...
imageJPG.Save(...);

Или просто используйте CImage::SetTransparentColor:

imagePNG.SetTransparentColor(RGB(255, 0, 0));
imagePNG.Draw(hdc, rc);
for (int x = 0; x <= xPNG; x++){...}

Чтобы сделать это с помощью цикла, измените условие в цикле на x < xPNG и x < yPNG.

...