c++ - How to construct a GDI+ Bitmap object from a Device-Dependent HBITMAP -
i want use gdi+ method image::save()
save ddb file in following scenario:
hbitmap hbitmap = createcompatiblebitmap(hdc, 200, 200) ; ... //hbitmap ddb need pass hpalette gdiplus::bitmap(hbitmap, ???hpalette??? ).save(l"file.png", ...) ;
the problem bitmap
constructor asks hpalette
when bitmap not device-independent bitmap.
where necessary hpalette from?
followup:
1 of answers suggests passing null hpalette
parameter.
here working example so. result purely black , white image colors lost.
#include <windows.h> #include <gdiplus.h> int main(){ using namespace gdiplus ; gdiplusstartupinput gdiplusstartupinput ; ulong_ptr gdiplustoken ; gdiplusstartup(&gdiplustoken, &gdiplusstartupinput, null) ; clsid pngencoder = {0x557cf406, 0x1a04, 0x11d3, {0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} } ; hdc dchndl = createcompatibledc(null) ; hbitmap hbitmap = createcompatiblebitmap(dchndl, 200, 200) ; selectobject(dchndl, hbitmap) ; bitblt(dchndl, 0,0, 200,200, getdc(null), 0,0, srccopy|captureblt) ; bitmap(hbitmap, null).save(l"file.png", &pngencoder) ; }
as createcompatiblebitmap remarks sate if dealing color bitmaps can assume hdc
nonmemory device context (because memory device context create monochrome bitmaps) , color palette used bitmap same color palette used device context. can query using getcurrentobject
method. remarks bitmap.bitmap(hbitmap, hpalette)
constructor state:
do not pass gdi+ bitmap::bitmap constructor gdi bitmap or gdi palette (or previously) selected device context.
so can not used current device context palette directly , need create copy of instead.
/// <returns> /// handle palette selected device context without granting ownership. /// </returns> _check_return_ ::hpalette fetch_currentpalette(_in_ ::hdc const h_dc) { assert(h_dc); ::hgdiobj const h_palette_object{::getcurrentobject(h_dc, obj_pal)}; // not owned assert(h_palette_object); assert(obj_pal == ::getobjecttype(h_palette_object)); // perform unchecked conversion of generic gdi object descriptor gdi palette descriptor. ::hpalette h_current_palette{}; // not owned { static_assert(sizeof(h_palette_object) == sizeof(h_current_palette), "wat"); ::memcpy ( ::std::addressof(h_current_palette) , ::std::addressof(h_palette_object) , sizeof(h_current_palette) ); } return(h_current_palette); } /// <returns> /// handle palette copy granting ownership. /// </returns> _check_return_ ::hpalette make_palettecopy(_in_ ::hpalette const h_palette) { assert(h_palette); ::uint const first_entry_index{}; ::uint entries_count{}; ::lppaletteentry p_entries{}; // figure out how many entries palette contains. entries_count = ::getpaletteentries(h_palette, first_entry_index, entries_count, p_entries); assert(1 < entries_count); assert(entries_count <= ::std::numeric_limits< decltype(logpalette::palnumentries) >::max()); // buffer hold palette description contains first paletteentry last field. // followed rest of paletteentry items. ::std::unique_ptr< ::std::uint8_t[] > const p_buffer { new ::std::uint8_t[sizeof(::logpalette) + (sizeof(::paletteentry) * (entries_count - 1u))] }; // perform unchecked conversion of buffer pointer palette description pointer. ::logpalette * p_description{}; { ::std::uint8_t * const p_buffer_bytes{p_buffer.get()}; static_assert(sizeof(p_buffer_bytes) == sizeof(p_description), "wat"); ::memcpy ( ::std::addressof(p_description) , ::std::addressof(p_buffer_bytes) , sizeof(p_description) ); } // copy palette entries buffer. p_entries = static_cast< ::lppaletteentry >(p_description->palpalentry); ::uint const copied_entries_count { ::getpaletteentries(h_palette, first_entry_index, entries_count, p_entries) }; assert(copied_entries_count == entries_count); // create palette copy. p_description->palversion = 0x300; // magic p_description->palnumentries = static_cast< ::word >(copied_entries_count); ::hpalette const h_copied_palette{::createpalette(p_description)}; // owned assert(h_copied_palette); return(h_copied_palette); } ::hpalette const hpal{make_palettecopy(fetch_currentpalette(hdc))}; // owned assert(hpal); ::hbitmap const hbitmap{::createcompatiblebitmap(hdc, 200, 200)}; // owned assert(hbitmap); { ::gdiplus::bitmap bmp{hbitmap, hpal}; assert(::gdiplus::status::ok == bmp.getlaststatus()); // something... } // delete palette , bitmap after gdi+ bitmap object went out of scope. if(false == ::deleteobject(hpal)) { assert(false); } if(false == ::deleteobject(hbitmap)) { assert(false); }
Comments
Post a Comment