Я не использую 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 для меня, которые здесь есть?
ура
4GLGuy
Инициализация может быть сделана с 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
будет быстрее).
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
,