วิธีการวาด BMP แบบโปร่งใสด้วย GDI+

ขณะนี้ฉันกำลังแก้ไขโค้ด GDI เก่าเพื่อใช้ GDI+ และประสบปัญหาในการวาดไฟล์ BMP ที่มีพื้นหลังโปร่งใส รหัส GDI แบบเก่าไม่ได้ใช้โค้ดพิเศษใดๆ ที่ชัดเจนในการวาดพื้นหลังแบบโปร่งใส ดังนั้นฉันจึงสงสัยว่าจะใช้ GDI+ ได้อย่างไร

รหัสปัจจุบันของฉันมีลักษณะเช่นนี้

HINSTANCE hinstance = GetModuleHandle(NULL);
bmp = Gdiplus::Bitmap::FromResource(hinstance, MAKEINTRESOURCEW(IDB_BMP));
Gdiplus::Graphics graphics(pDC->m_hDC);
graphics.DrawImage(&bmp, posX, posY);

ฉันยังพยายามสร้างบิตแมปใหม่จากทรัพยากรโดยใช้วิธีการโคลนและโดยการวาดบิตแมปไปยังบิตแมปที่สร้างขึ้นใหม่ แต่ก็ไม่ได้ช่วยอะไร ทั้งสองครั้งที่ฉันใช้ PixelFormat32bppPARGB

จากนั้น ฉันลองใช้การผสมผสานแบบอัลฟ่า แต่วิธีนี้ทำให้ภาพทั้งหมดมีความโปร่งใส และไม่ใช่แค่พื้นหลังเท่านั้น:

Gdiplus::ColorMatrix clrMatrix = { 
    1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 0.5f, 0.0f,
    0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};

Gdiplus::ImageAttributes imgAttr;
imgAttr.SetColorMatrix(&clrMatrix);

graphics.DrawImage(&bmp, destRect, 0, 0, width(), height(), Gdiplus::UnitPixel, &imgAttr);

ข้อมูลความโปร่งใสมีอยู่แล้วในภาพ แต่ฉันไม่รู้ว่าจะนำไปใช้อย่างไรเมื่อวาดภาพ เราจะบรรลุเป้าหมายนี้ได้อย่างไร?


person sigy    schedule 27.07.2012    source แหล่งที่มา


คำตอบ (3)


วิธีแก้ปัญหาที่ง่ายที่สุดคือใช้รูปแบบอื่นที่ไม่ใช่ BMP

คุณต้องมีบิตเพื่อให้มีข้อมูลอัลฟ่า และคุณต้องให้บิตแมปอยู่ในรูปแบบที่มีข้อมูลอัลฟ่า เมื่อคุณโหลด BMP ด้วย GDI+ มันจะใช้รูปแบบที่ไม่มีอัลฟ่าเสมอ แม้ว่า BMP จะมีช่องอัลฟ่าก็ตาม ฉันเชื่อว่าข้อมูลอยู่ในบิตของรูปภาพ แต่ไม่ได้ถูกนำมาใช้

ปัญหาเมื่อคุณโคลนหรือวาดเป็นบิตแมป PixelFormat32bppPARGB ก็คือ GDI+ จะแปลงข้อมูลรูปภาพเป็นรูปแบบใหม่ ซึ่งหมายถึงการละทิ้งข้อมูลอัลฟ่า

สมมติว่ากำลังโหลดบิตอย่างถูกต้อง สิ่งที่คุณต้องทำคือคัดลอกบิตโดยตรงไปยังบิตแมปอื่นด้วยรูปแบบที่ถูกต้อง คุณสามารถทำได้ด้วย Bitmap::LockBits และ บิตแมป::UnlockBits . (ตรวจสอบให้แน่ใจว่าคุณล็อคแต่ละบิตแมปด้วยรูปแบบพิกเซลดั้งเดิม ดังนั้นจึงไม่มีการแปลงเกิดขึ้น)

person Esme Povirk    schedule 28.07.2012
comment
ตกลง ดูเหมือนว่า GDI แบบเก่าจะสามารถวาดภาพดังกล่าวได้โดยไม่ต้องมีโค้ดเพิ่มเติมใดๆ และ GDI+ ใหม่จะไม่สามารถทำแบบเดียวกันได้หากไม่มีการทำงานพิเศษหนักๆ....น่าเศร้าแต่จริง - person sigy; 30.07.2012
comment
ตามคำตอบที่ระบุไว้ GDI+ สามารถทำได้ เช่นกัน คุณเพียงแค่ต้องใช้รูปแบบภาพที่รองรับช่องอัลฟ่า (เช่น PNG) [ฉันไม่สงสัยเลยว่าคุณ สามารถ จัดเก็บข้อมูลอัลฟ่าเป็นไฟล์ BMP ได้ แต่คุณไม่ควรทำเช่นนั้น นั่นไม่ใช่เรื่องปกติ ถ้ามันใช้งานได้ มันก็ใช้งานได้เพราะมีข้อบกพร่องใน GDI และคุณไม่ควรเชื่อถือสิ่งนั้น] - person BrainSlugs83; 13.01.2015

คำตอบล่าช้า แต่:

ImageAttributes imAtt;    
imAtt.SetColorKey(Color(255,255,255), Color(255,255,255), ColorAdjustTypeBitmap);  

จะทำให้ white (255,255,255) โปร่งใสบนบิตแมปใดๆ ที่คุณใช้แอตทริบิวต์รูปภาพนี้ด้วย

person Evan Carslake    schedule 09.06.2015
comment
วิธีใช้สิ่งนี้บนบิตแมป? - person Paul; 25.01.2019
comment
ส่งผ่านออบเจ็กต์ ImageAttributes นั้นไปยัง Graphics.DrawImage เวอร์ชันโอเวอร์โหลด - person Gautam Jain; 22.02.2021

ฉันมีปัญหาเดียวกัน. BMP แบบโปร่งใสไม่ได้แสดงอย่างถูกต้อง และน่าเสียดายที่ไม่สามารถโหลด PNG จากแหล่งข้อมูลได้โดยตรง (ยกเว้นโดยการเพิ่มโค้ดจำนวนเล็กน้อยเพื่อคัดลอกลงในสตรีมและโหลดจากสตรีม) ฉันต้องการหลีกเลี่ยงโค้ดนี้
บิตแมปที่ฉันใช้ยังใช้เพียงสองสีเท่านั้น (พื้นหลังและโลโก้) การมีช่องอัลฟ่าหมายความว่าฉันจะต้องบันทึกช่องเหล่านั้นด้วยความลึกของสีที่สูงกว่ามาก แทนที่จะเป็นความลึกของสีเพียง 2 บิต

คำตอบของ Evan คือฉันกำลังมองหา :-)

แทนที่จะเป็นสีขาว ฉันใช้สีของพิกเซลซ้ายบนเป็นสีโปร่งใส:

Gdiplus::Color ColourOfTopLeftPixel;
Gdiplus::Status eStatus = m_pBitmap->GetPixel(0, 0, &ColourOfTopLeftPixel);
_ASSERTE(eStatus == Gdiplus::Ok);

// The following makes every pixel with the same colour as the top left pixel (ColourOfTopLeftPixel) transparent.
Gdiplus::ImageAttributes ImgAtt;
ImgAtt.SetColorKey(ColourOfTopLeftPixel, ColourOfTopLeftPixel, Gdiplus::ColorAdjustTypeBitmap);
person Dirksche    schedule 08.10.2015