Я не могу преобразовать растровое изображение GDI + в base 64 в C ++ (Microsoft Visual C ++) - PullRequest
0 голосов
/ 28 февраля 2020

Я не могу преобразовать растровое изображение GDI + в базу 64 в C ++

. У меня есть:

  1. Скачал и включил эту библиотеку: https://github.com/ReneNyffenegger/cpp-base64

  2. Напишите функцию, которую вы можете увидеть ниже.

  3. Вызывается ее, передавая растровое изображение, которое, я знаю, содержит данные. Я знаю, что растровое изображение содержит данные, потому что я использую другую функцию, вызываемую сразу после этой.

Проблема состоит в том, что массив charPixels всегда полон нулей.

Во-вторых, пожалуйста, объясните мне, каков безопасный способ разблокировки битов. Я боюсь, что если я просто сделаю это в конечном итоге, если биты на самом деле не заблокированы в этой точке, я получу исключение.

Stride - положительное число, это: 1280.

Также у меня есть доступ к 'finally', потому что это расширение MS для C ++.

[Примечание: код обновлен, потому что я вставил неправильный код по ошибке]

 std::string GdiBitmapToBase64(Gdiplus::Bitmap* gdiBitmap, int width, int height)
{
    unsigned char* charPixels = nullptr;

    try
    {

        Gdiplus::Rect rect = Gdiplus::Rect(0, 0, width, height);

        Gdiplus::BitmapData gdiBitmapData;
        gdiBitmap->LockBits(&rect, Gdiplus::ImageLockMode::ImageLockModeRead, PixelFormat32bppARGB, &gdiBitmapData);

        auto stride = gdiBitmapData.Stride;
        if (stride < 0) stride = -stride;

        charPixels = new unsigned char[height * stride];

        memset(charPixels, 0, height * stride);

        memcpy(charPixels, gdiBitmapData.Scan0, stride);

        std::string ret = base64_encode(charPixels, stride);
        gdiBitmap->UnlockBits(&gdiBitmapData);
        return ret;
    }
    finally
    {
        if(charPixels != nullptr)
        {
            delete[] charPixels;
        }
    }
}

Здесь это код, который вызывает этот метод. Это может помочь:

void CLIScumm::Wrapper::ScreenUpdated(const void* buf, int pitch, int x, int y, int w, int h, PalletteColor* color)
{
    const unsigned char* bufCounter = static_cast<const unsigned char*>(buf);
    for (int hightCounter = 0; hightCounter < h; hightCounter++, bufCounter = bufCounter + pitch)
    {
        for (int widthCounter = 0; widthCounter < w; widthCounter++)
        {
            PalletteColor currentColor = *(color + *(bufCounter + widthCounter));
            gdiBitmap->SetPixel(x + widthCounter, y + hightCounter, Gdiplus::Color(currentColor.r, currentColor.g, currentColor.b));
        }
    }
    _screenUpdated->Invoke(gcnew System::String(GdiBitmapToBase64(gdiBitmap, DISPLAY_DEFAULT_WIDTH, DISPLAY_DEFAULT_HEIGHT).c_str()));
}

И декларации:

namespace CLIScumm {
    public ref class Wrapper {
    ...
    private:
         ...
        Gdiplus::Graphics* gdiGraphics;
        Gdiplus::Bitmap* gdiBitmap;
         ...
    };


And the initialization:
void CLIScumm::Wrapper::init()
{
    if (!hasStarted)
    {
        try
        {
            if (!hasStarted)
            {
                ...

                Gdiplus::GdiplusStartupInput gdiplusStartupInput;
                Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

(malloc(sizeof(100000) * DISPLAY_DEFAULT_HEIGHT * DISPLAY_DEFAULT_WIDTH));
                gdiBitmap = new Gdiplus::Bitmap(DISPLAY_DEFAULT_WIDTH, DISPLAY_DEFAULT_HEIGHT, PixelFormat32bppARGB);
                gdiGraphics = new Gdiplus::Graphics(gdiBitmap);
                InitImage();
                            ...
            }
        }
        ...
    }
}

1 Ответ

0 голосов
/ 29 февраля 2020

Спасибо всем за помощь, но я решил свою собственную проблему.

Я путал данные растрового пикселя с действительными байтами растрового изображения, и Scan0 является первым. Причина, по которой я получал только нули, состоит в том, что первые несколько кадров были черными.

Я следовал примеру с C ++ gdi :: Bitmap to PNG Image в памяти , чтобы получить действительные биты растрового изображения.

Я изменил пример функции на:

bool SavePngMemory(Gdiplus::Bitmap* gdiBitmap, std::vector<BYTE>& data)
{
    //write to IStream
    IStream* istream = nullptr;
    CreateStreamOnHGlobal(NULL, TRUE, &istream);

    CLSID clsid_bmp;
    CLSIDFromString(L"{557cf400-1a04-11d3-9a73-0000f81ef32e}", &clsid_bmp);
    Gdiplus::Status status = gdiBitmap->Save(istream, &clsid_bmp);
    if (status != Gdiplus::Status::Ok)
        return false;

    //get memory handle associated with istream
    HGLOBAL hg = NULL;
    GetHGlobalFromStream(istream, &hg);

    //copy IStream to buffer
    int bufsize = GlobalSize(hg);
    data.resize(bufsize);

    //lock & unlock memory
    LPVOID pimage = GlobalLock(hg);
    memcpy(&data[0], pimage, bufsize);
    GlobalUnlock(hg);

    istream->Release();
    return true;
}

Затем я смог преобразовать данные в base64, вызвав:

base64_encode(&data[0], data.size());

Я не могу поручиться за качество кода, потому что я не понимаю, как все работает.

...