2017-12-25 9 views
1

Ich habe eine Anwendung, die ein Bild mit einem transparenten Hintergrund lädt, dann benutze ich StretchBlt, um es auf die gewünschte Größe zu ändern, mit set mit SetStretchBltMode (Ich versuchte mit anderen Modi, während die Transparenz intakt, machte auch das skalierte Bild 'hässlich').
Allerdings ersetzt StretchBlt den transparenten Hintergrund durch eine Farbe (schwarz), die nicht zum Hintergrund des Fensters passt, auf dem das Bild angezeigt wird. So

Ich habe zwei Möglichkeiten:
1) Ersetzen Sie den transparenten Hintergrund des Bildes mit der Hintergrundfarbe des Fensters, dann StretchBlt
2 mit Größe ändern) Resize es, während die Transparenz Hintergrund hält (bevorzugte Option)

Ich habe versucht, nach WinAPI-Funktion zu suchen, die beide Funktionen bieten würde, aber ich habe keine gefunden.

Wie mache ich eine dieser Optionen (ersetzen Sie die Transparenz oder ändern Sie die Größe, während Sie es beibehalten) mit einfachen WinAPI?Größe ändern HBITMAP bei transparentem Hintergrund

+0

"transparenter Hintergrund" ist sehr unspezifisch - bitte teilen Sie uns das genaue Bildformat mit, z. G. "32 bpp ARGB mit vormultiplexiertem Alpha". Auch das Anzeigen Ihres aktuellen Codes wäre hilfreich. – zett42

+0

Es ist eine GDI-Funktion, GDI hängt bei 24bpp fest und unterstützt keine 32bpp-Bildformate. Betrachten Sie GDI +, gdiplus.h Header-Datei. –

+0

Werfen Sie einen Blick auf die [WIC API] (https://msdn.microsoft.com/en-us/library/windows/desktop/ee719655 (v = vs.85) .aspx). GDI ist in diesen Tagen nicht viel (und GDI + ist eher langsam). –

Antwort

1

Zuerst BitBlt, StretchBlt und TransparentBlt unterstützen nicht die Alpha-Kanal ..

TransparentBlt Werke, indem sie alles, was Farbe angegeben Sie wollen, transparent.

Wenn Sie Alpha-Kanal und Blending-Unterstützung möchten, benötigen Sie: AlphaBlend.

Sie können folgendes tun:

BLENDFUNCTION fnc; 
fnc.BlendOp = AC_SRC_OVER; 
fnc.BlendFlags = 0; 
fnc.SourceConstantAlpha = 0xFF; 
fnc.AlphaFormat = AC_SRC_ALPHA; 

//You need to create a memDC.. and an HBITMAP.. 

//Select the hBitmap into the memDC. 
HGDIOBJ obj = SelectObject(memDC, hBmp); 

//Render with alpha blending.. 
AlphaBlend(DC, rect.X, rect.Y, rect.Width, rect.Height, memDC, 0, 0, Width, Height, fnc); 

//Restore the memDC to original state.. 
SelectObject(memDC, obj); 

OR tun Sie Ihre eigenen Pre-multiplizierten alpha-Wiedergabe durch den Kanal Farben selbst Berechnung ..

Alternativ können Sie GDI + versuchen und sehen, wie das klappt :

ULONG_PTR GdiImage::GDIToken = 0; 
Gdiplus::GdiplusStartupInput GdiImage::GDIStartInput = NULL; 
Gdiplus::GdiplusStartup(&GdiImage::GDIToken, &GdiImage::GDIStartInput, NULL); 

Gdiplus::Image* Img = Gdiplus::Image::FromFile(L"PathToImage.ext"); //where ext can be png, bmp, etc.. 

Gdiplus::Graphics graphics(DC); 
//graphics.SetSmoothingMode(SmoothingModeHighSpeed); 
graphics.SetInterpolationMode(Gdiplus:: InterpolationModeBilinear); //InterpolationModeNearestNeighbor 
//graphics.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHalf); 
graphics.DrawImage(Img, x, y, w, h); 

delete Img; 
Gdiplus::GdiplusShutdown(GdiImage::GDIToken); 
GdiImage::GDIStartInput = NULL; 
GdiImage::GDIToken = 0; 
+1

Das funktioniert, aber das resultierende Bild ist hässlich wie bei 'StretchBlt', ohne' HALTFONE' zu verwenden, wie in meiner Frage beschrieben. –

+0

Nun ich bin mir nicht sicher, was Sie mit "sieht hässlich" meinen. Sie möchten nicht "HALFTONE" verwenden, aber Sie möchten skalieren. Haben Sie vorher und nachher Bilder? (vor Skalierung, Skalierung mit Halbton, Skalierung ohne Halbton). – Brandon

+0

@ あ ぶ ら こ こ; Ich habe "GDIPlus" hinzugefügt, nur für den Fall, dass Sie das versuchen wollen. 'GDIPlus' kann Transparente Bitmaps, PNG, etc. unterstützen. Es hat auch Interpolation, Glättung, Halbton und andere Effekte und Transformationen. – Brandon

1

ich für WinAPI Funktion versucht suchen, bieten würde entweder Funktionalität, aber ich habe keine gefunden.

Obwohl andere haben bereits ein paar Vorschläge, meines Wissens keine der zur Zeit (12/2017) verfügbar native OS APIs bieten hochwertige Bild Resampling.

Es gibt viele Bibliotheken von Drittanbietern für das Resampling. Viele (die meisten?) Von ihnen sind ziemlich kompliziert und wahrscheinlich zu viel, wenn die Bildverarbeitung nicht die Hauptaufgabe Ihrer Anwendung ist.

Im folgenden Beispiel verwende ich die Public-Domain, Single-Header-Datei, keine externe Abhängigkeiten "stb_image_resize.h" Bibliothek. Just #include es in Ihrem Projekt und damit fertig sein. Die Bibliothek ist nicht die schnellste, aber ich würde sie nicht besonders langsam nennen. Wo es glänzt, ist Benutzerfreundlichkeit und Vielseitigkeit. Es ist auch einfach zu erweitern, wenn Sie zusätzliche Filter wie Lanczos haben möchten (für die ich Code bereitstellen kann, wenn es Interesse gibt). Obwohl die eingebauten Filter bereits viel besser sind als die der OS APIs.

Das folgende Beispielprogramm erwartet in der Datei "flower.bmp" des aktuellen Verzeichnisses eine 32-Bit-Bitmap mit einem Alpha-Kanal (nicht vorgemischt). Das Image wird mit der OS-API LoadImageW() geladen, unter Verwendung von stbir_resize_uint8() auf ein Drittel der ursprünglichen Abmessungen neu abgetastet und unter Verwendung von GDI + im aktuellen Verzeichnis als "flower_resized.bmp" gespeichert.

#include <Windows.h> 
#include <iostream> 
#include <gdiplus.h> 
#pragma comment(lib, "gdiplus") 
namespace gp = Gdiplus; 

#define STB_IMAGE_RESIZE_IMPLEMENTATION 
#include "stb_image_resize.h" 

int main() 
{ 
    // Using LR_CREATEDIBSECTION flag to get direct access to the bitmap's pixel data. 
    HBITMAP hBmpIn = reinterpret_cast<HBITMAP>(
     LoadImageW(NULL, L"flower.bmp", IMAGE_BITMAP, 0, 0, 
        LR_LOADFROMFILE | LR_CREATEDIBSECTION)); 
    if(!hBmpIn) 
    { 
     std::cout << "Failed to load bitmap.\n"; 
     return 1; 
    } 

    // Getting bitmap information including a pointer to the bitmap's pixel data 
    // in infoIn.dsBm.bmBits. 
    // This will fail if hBmpIn is not a DIB. In this case you may call GetDIBits() 
    // to get a copy of the bitmap's pixel data instead. 
    DIBSECTION infoIn{}; 
    if(!GetObject(hBmpIn, sizeof(infoIn), &infoIn)) 
    { 
     std::cout << "Bitmap is not a DIB.\n"; 
     return 1; 
    } 

    // Some sanity checks of the input image. 
    if(infoIn.dsBm.bmBitsPixel != 32 || infoIn.dsBm.bmPlanes != 1 || 
     infoIn.dsBmih.biCompression != BI_RGB) 
    { 
     std::cout << "Bitmap is not 32 bpp uncompressed.\n"; 
     return 1; 
    } 

    // Create a DIB for the output. We receive a HBITMAP aswell as a writable 
    // pointer to the bitmap pixel data. 
    int out_w = infoIn.dsBm.bmWidth/3, out_h = infoIn.dsBm.bmHeight/3; 
    BITMAPINFO infoOut{}; 
    auto& hdr = infoOut.bmiHeader; 
    hdr.biSize = sizeof(hdr); 
    hdr.biBitCount = 32; 
    hdr.biCompression = BI_RGB; 
    hdr.biWidth = out_w; 
    hdr.biHeight = out_h; // negate the value to create top-down bitmap 
    hdr.biPlanes = 1; 
    unsigned char* pOutPixels = nullptr; 
    HBITMAP hBmpOut = CreateDIBSection(NULL, &infoOut, DIB_RGB_COLORS, 
     reinterpret_cast<void**>(&pOutPixels), NULL, 0); 
    if(!hBmpOut) 
    { 
     std::cout << "Could not create output bitmap.\n"; 
     return 1; 
    } 

    // Resample the input bitmap using the simplest API. 
    // These functions use a "default" resampling filter defined at compile time 
    // (currently "Mitchell" for downsampling and "Catmull-Rom" for upsampling). 
    // To change the filter, you can change the compile-time defaults 
    // by #defining STBIR_DEFAULT_FILTER_UPSAMPLE and STBIR_DEFAULT_FILTER_DOWNSAMPLE, 
    // or you can use the medium-complexity API. 
    // Consult "stb_image_resize.h" which contains the documentation. 

    stbir_resize_uint8( 
     reinterpret_cast< unsigned char const* >(infoIn.dsBm.bmBits), 
     infoIn.dsBm.bmWidth, 
     infoIn.dsBm.bmHeight, 
     0, // input_stride_in_bytes, 0 = packed continously in memory 
     pOutPixels, 
     out_w, 
     out_h, 
     0, // output_stride_in_bytes, 0 = packed continously in memory 
     4 // num_channels 
    ); 

    // Use GDI+ for saving the resized image to disk. 

    gp::GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR gdipToken = 0; 
    gp::GdiplusStartup(&gdipToken, &gdiplusStartupInput, nullptr); 

    { 
     gp::Bitmap bmpOut(hBmpOut, nullptr); 
     // I'm taking a shortcut here by hardcoding the encoder CLSID. Check MSDN to do it by-the-book: 
     // https://msdn.microsoft.com/en-us/library/windows/desktop/ms533843(v=vs.85).aspx 
     class __declspec(uuid("{557cf400-1a04-11d3-9a73-0000f81ef32e}")) BmpEncoderId; 
     bmpOut.Save(L"flower_resized.bmp", &__uuidof(BmpEncoderId)); 
    } 

    // Cleanup 
    gp::GdiplusShutdown(gdipToken); 
    DeleteObject(hBmpIn); 
    DeleteObject(hBmpOut); 

    std::cout << "All done.\n"; 

    return 0; 
} 

Hinweise:

Wenn transparente Bilder Resampling, es ist in der Regel ratsam, eine premultiplied alpha channel zu verwenden. Andernfalls kann das neu abgetastete Bild Artefakte aufweisen, die im Allgemeinen entlang der Kanten von Formen erkennbar sind. STBIR verwendet "Alpha-Weighted Resampling" (effektives Premultipling, Resampling und dann Premultipling), es sei denn, Sie geben das STBIR_FLAG_ALPHA_PREMULTIPLIED Flag an. So erhalten Sie Leistungsvorteile, wenn Sie nach dem Laden eines Bildes manuell einmal multiplizieren. Die meisten Windows-APIs (z. B. AlphaBlend), die transparente Bilder anzeigen können, erwarten, dass der Alphakanal ohnehin vorgemultipliziert wird.

Verwandte Themen