简单的图像加载库

发布于 2024-08-17 08:35:26 字数 437 浏览 12 评论 0 原文

我有一个使用这个库的应用程序(实际上是一个直接端口到 D)进行一些图像处理。我正在寻找一些类似风格的其他库来用于加载其他文件类型。

我需要/想要的东西:

  • 无损格式。
  • 简单的 C API。
  • 以原始像素格式将数据加载到缓冲区中。
  • 开源(比如我可以获取源文件并编译它们供我自己使用,除此之外,许可并不重要)

有人知道类似的事情吗?

I have an app that uses this library (actually a direct port to D) for some image processing. I'm looking for some other libraries of a similar style to use to load other file types.

Things I need/want:

  • Loss less format.
  • Simple C API.
  • Loads data into buffers in a raw pixel format.
  • Open source (as in I can get source files and compile them for my own use, aside from that, licensing doesn't matter)

Anyone know of anything like that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

勿忘初心 2024-08-24 08:35:26

PNG:要加载和保存,您可以尝试 LodePNG 库

C/C++: http://members.gamedev.net/lode/projects/LodePNG/

D 端口:www.dsource.org/projects/scrapple/wiki/LodePngLibrary

PNG: for loading and saving you can try LodePNG library

C/C++: http://members.gamedev.net/lode/projects/LodePNG/

D port: www.dsource.org/projects/scrapple/wiki/LodePngLibrary

你没皮卡萌 2024-08-24 08:35:26

devIL 和 SDL_Image 支持多种格式。
Derelict 提供了它们的绑定。

我自己的使用这些代码并具有原始缓冲区的代码:

devIL and SDL_Image supports a good deal of formats.
Derelict provides their bindings.

My own code for using these and have a raw buffer:

枕头说它不想醒 2024-08-24 08:35:26

FreeImage 非常全面,而且非常干净且易于使用。

http://freeimage.sourceforge.net/

FreeImage is pretty comprehensive, and very clean and easy to use.

http://freeimage.sourceforge.net/

誰ツ都不明白 2024-08-24 08:35:26

您可能想尝试 libpng,尽管我并不认为它易于使用。

除此之外,您可以尝试直接处理位图,根本不需要任何库。

You might want to try libpng, although I wouldn't exactly call it easy to use.

Other than that, you might try working directly on bitmaps, with no libraries at all.

梦开始←不甜 2024-08-24 08:35:26

我会考虑使用 imageMagick ( http://www.imagemagick.org/script/index.php )满足您所有的图像加载需求。
它支持多种不同位深度的多种格式,并且可以读取和写入其中的大多数格式。

它的功能可能比您需要的多得多,但它是一个设计精良的库,我已经在几个项目中使用过它。

它与 GPL 兼容。 (我认为商业许可证也是可用的)

I'd consider using imageMagick ( http://www.imagemagick.org/script/index.php ) for all your image loading needs.
It supports a lot of formats in a lot of different bit depths, reading and writing for most of them.

It may do a lot more than you need, but its a very well designed library and I've used it in several projects.

It is GPL compatible. (And I think commercial licenses are available too)

月光色 2024-08-24 08:35:26

您始终可以尝试 gdimage 库。我从来没有遇到过任何问题,尽管我用它所做的大部分工作都是在 PHP 中进行的。

You could always try the gdimage library. I've never had any problems with it, though mist of the work I've done with it has been in PHP.

执妄 2024-08-24 08:35:26

您可以使用 Netpbm 等软件与 PPM 格式,非常容易从任何程序读取/写入,无需外部库。

PPM 文件看起来像这样:

P6
800 600 255
# followed by 800x600x3 bytes of values between 0 and 255, i.e.
\xFF\x00\x00\x80\x80\x00\x00\xFF\x00\x00\x80\x80\x00\x00\xFF...
# but not escaped

或像这样:

P3
800 600 255
# followed by 800x600x3 decimal numbers between 0 and 255, i.e.
255 0 0  128 128 0  0 255 0  0 128 128  0 0 255  ...

You can use software such as Netpbm to convert to/from PPM format, which is extremely easy to read/write from any program without needing external libraries.

A PPM file either looks like this:

P6
800 600 255
# followed by 800x600x3 bytes of values between 0 and 255, i.e.
\xFF\x00\x00\x80\x80\x00\x00\xFF\x00\x00\x80\x80\x00\x00\xFF...
# but not escaped

or like this:

P3
800 600 255
# followed by 800x600x3 decimal numbers between 0 and 255, i.e.
255 0 0  128 128 0  0 255 0  0 128 128  0 0 255  ...
成熟的代价 2024-08-24 08:35:26

我认为 SOIL (简单的 OpenGL 图像库)非常适合您的描述。它有多种格式,iirc jpg 代码甚至是从与您的源相同的源移植的。

I think SOIL (Simple OpenGl Image Library) fits your description nicely. It has many formats, iirc the jpg code is even ported from the same source as yours.

薄荷港 2024-08-24 08:35:26

CAPI 项目现已在 GitHub 上提供,用于图像处理。该库API简单,体积小,兼容性好。目前正在致力于提高速度。已在 Windows 和 Linux 上测试并运行。该库当前支持以下图像格式:

  • BMP(位图)
  • JPG(jpeg)
  • PNG(便携式网络图形)
  • ICO(图标)

在下面的示例中,我将在 Windows 上的 Visual Studio 中使用 C++。

首先,我们需要一些简单的例程来加载和保存文件。为此,我创建了 LoadFile 和 SaveFile 函数。以下是一个示例控制台程序,用于将 .ico 格式的文件转换为 .png 格式的文件。
我们将使用的 CAPI 函数是:

  • capi_LoadImageFromMemory
    • 此函数会检测图像格式并将图像加载为简单的格式以供使用。
  • capi_Create_PNG_ImageToMemory
    • 此函数根据我们加载的图像创建 PNG 格式的图像。

#include <Windows.h>
#include <CAPI.h>

#ifdef  UNICODE
#define app_fopen _wfopen_s
#define app_printf wprintf
#else
#define app_fopen fopen_s
#define app_printf printf
#endif //  UNICODE

void* LoadFile(const STRING* FilePath, U64* pFileSize)
{
    FILE* Stream;
    size_t BufferLength;
    void* pThisFile;
    void* pNewBlock;

    if ((FilePath == 0) || (pFileSize == 0)) return 0;

    *pFileSize = 0;

    if (app_fopen(&Stream, FilePath, STR("rb")) != 0) return 0;
    if (Stream == 0) return 0;

    pThisFile = 0;
    BufferLength = 0;

    do
    {
        BufferLength += 0x1000;

        pNewBlock = capi_realloc(pThisFile, BufferLength);
        if (pNewBlock == 0)
        {
            if (pThisFile != 0) capi_free(pThisFile);
            fclose(Stream);
            return 0;
        }

        pThisFile = pNewBlock;

        *pFileSize += fread(&((U8*)pThisFile)[*pFileSize], 1, 0x1000, Stream);
    } while (!(feof(Stream)));

    fclose(Stream);

    return pThisFile;
}

I32 SaveFile(const STRING* FilePath, void* pFilePointer, U64 FileSize)
{
    FILE* Stream;
    size_t nBytesWrite;
    I32 ErrorCode;

    if ((FilePath == 0) || (pFilePointer == 0) || (FileSize == 0)) return CAPI_ERROR_INVALID_PARAMETER;

    ErrorCode = CAPI_ERROR_NONE;

    if (app_fopen(&Stream, FilePath, STR("w+b")) != 0) return CAPI_ERROR_ACCESS_DENIED;
    if (Stream == 0) return CAPI_ERROR_ACCESS_DENIED;

    nBytesWrite = fwrite(pFilePointer, 1, (size_t)FileSize, Stream);
    if (nBytesWrite != FileSize)
    {
        ErrorCode = CAPI_ERROR_ACCESS_DENIED;
        goto exit_func;
    }

exit_func:
    fclose(Stream);

    return ErrorCode;
}

int main()
{
    IMAGE exampleImage;
    void* myLoadedFile;
    I32 ErrorCode;
    U64 FileSize;
    PNG* myNewFile;
    PNG_PARAMETERS png_params;

    myLoadedFile = LoadFile(STR("C:/Users/Public/myTestImage.ico"), &FileSize);
    if (myLoadedFile == 0)
    {
        app_printf(STR("LoadFile Failed."));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    ErrorCode = capi_LoadImageFromMemory(&exampleImage, 1, myLoadedFile, FileSize);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        app_printf(STR("capi_LoadImageFromMemory Failed. ErrorCode: "));
        app_printf(capi_ErrorCodeToString(ErrorCode));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    png_params.CompressionMethod = 0;
    png_params.Level = Z_DEFAULT_COMPRESSION;
    png_params.FilterMethod = 0;
    png_params.InterlaceMethod = 0;
    png_params.IDAT_Length = 0x20000;

    ErrorCode = capi_Create_PNG_ImageToMemory(&myNewFile, &FileSize, &exampleImage, &png_params);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        app_printf(STR("capi_Create_PNG_ImageToMemory Failed. ErrorCode: "));
        app_printf(capi_ErrorCodeToString(ErrorCode));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    ErrorCode = SaveFile(STR("C:/Users/Public/myTestImage.png"), myNewFile, FileSize);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        app_printf(STR("SaveFile Failed. ErrorCode: "));
        app_printf(capi_ErrorCodeToString(ErrorCode));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    app_printf(STR("Done!"));
    while (true) { Sleep(100); }
}

在下一个示例中,我将创建一个具有双缓冲的简单窗口。
我们将在 Window_Paint_Handler 函数中将测试图像绘制到窗口。
我们将使用的 CAPI 函数是:

  • capi_LoadImageFromMemory
    • 此函数会检测图像格式并将图像加载为简单的格式以供使用。
  • capi_FillImage
    • 此函数用所需的颜色填充图像。在我们的例子中,我们正在填充帧缓冲区。
  • capi_DrawImageA
    • 此函数将一个图像绘制到另一个图像上。在我们的例子中,我们将测试图像绘制到帧缓冲区。

#include <Windows.h>
#include <CAPI.h>

#define WinClassName STR("ExampleProgram")
#define WinTitle STR("Example Program")

#ifdef  UNICODE
#define app_fopen _wfopen_s
#define app_printf wprintf
#define ApplicationEntryPoint wWinMain
#else
#define app_fopen fopen_s
#define app_printf printf
#define ApplicationEntryPoint WinMain
#endif //  UNICODE

static HWND Window_hWnd;
static HDC BufferHDC;
static BITMAPINFO* pDisplayBitmap;
static HBITMAP hBitmap;

static int ClientWidth;
static int ClientHeight;
static IMAGE FrameBuffer;

static IMAGE exampleImage;

void* LoadFile(const STRING* FilePath, U64* pFileSize)
{
    FILE* Stream;
    size_t BufferLength;
    void* pThisFile;
    void* pNewBlock;

    if ((FilePath == 0) || (pFileSize == 0)) return 0;

    *pFileSize = 0;

    if (app_fopen(&Stream, FilePath, STR("rb")) != 0) return 0;
    if (Stream == 0) return 0;

    pThisFile = 0;
    BufferLength = 0;

    do
    {
        BufferLength += 0x1000;

        pNewBlock = capi_realloc(pThisFile, BufferLength);
        if (pNewBlock == 0)
        {
            if (pThisFile != 0) capi_free(pThisFile);
            fclose(Stream);
            return 0;
        }

        pThisFile = pNewBlock;

        *pFileSize += fread(&((U8*)pThisFile)[*pFileSize], 1, 0x1000, Stream);
    } while (!(feof(Stream)));

    fclose(Stream);

    return pThisFile;
}

I32 SaveFile(const STRING* FilePath, void* pFilePointer, U64 FileSize)
{
    FILE* Stream;
    size_t nBytesWrite;
    I32 ErrorCode;

    if ((FilePath == 0) || (pFilePointer == 0) || (FileSize == 0)) return CAPI_ERROR_INVALID_PARAMETER;

    ErrorCode = CAPI_ERROR_NONE;

    if (app_fopen(&Stream, FilePath, STR("w+b")) != 0) return CAPI_ERROR_ACCESS_DENIED;
    if (Stream == 0) return CAPI_ERROR_ACCESS_DENIED;

    nBytesWrite = fwrite(pFilePointer, 1, (size_t)FileSize, Stream);
    if (nBytesWrite != FileSize)
    {
        ErrorCode = CAPI_ERROR_ACCESS_DENIED;
        goto exit_func;
    }

exit_func:
    fclose(Stream);

    return ErrorCode;
}

void FreeSysInternal()
{
    if (BufferHDC != 0)
    {
        DeleteDC(BufferHDC);
        BufferHDC = 0;
    }

    if (pDisplayBitmap != 0)
    {
        capi_free(pDisplayBitmap);
        pDisplayBitmap = 0;
    }

    if (hBitmap != 0)
    {
        DeleteObject(hBitmap);
        hBitmap = 0;
    }
}

U32 SetupWindowFrameBuffer(HDC WindowHDC, RECT* ClientRt)
{
    FreeSysInternal();

    pDisplayBitmap = (BITMAPINFO*)capi_malloc(sizeof(BITMAPINFOHEADER));
    if (pDisplayBitmap == 0) return 1;

    pDisplayBitmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pDisplayBitmap->bmiHeader.biWidth = ClientRt->right;
    pDisplayBitmap->bmiHeader.biHeight = -ClientRt->bottom;
    pDisplayBitmap->bmiHeader.biPlanes = 1;
    pDisplayBitmap->bmiHeader.biBitCount = 32;
    pDisplayBitmap->bmiHeader.biCompression = 0;
    pDisplayBitmap->bmiHeader.biSizeImage = 0;
    pDisplayBitmap->bmiHeader.biXPelsPerMeter = 0;
    pDisplayBitmap->bmiHeader.biYPelsPerMeter = 0;
    pDisplayBitmap->bmiHeader.biClrUsed = 0;
    pDisplayBitmap->bmiHeader.biClrImportant = 0;

    BufferHDC = CreateCompatibleDC(WindowHDC);
    if (BufferHDC == 0)
    {
        capi_free(pDisplayBitmap);
        return 2;
    }

    hBitmap = CreateDIBSection(BufferHDC, pDisplayBitmap, 0,
        (void**)&FrameBuffer.Pixels, 0, 0);

    if (hBitmap == 0)
    {
        DeleteDC(BufferHDC);
        capi_free(pDisplayBitmap);
        return 3;
    }

    GdiFlush();

    FrameBuffer.ScanLine = ClientRt->right;
    FrameBuffer.Width = ClientRt->right;
    FrameBuffer.Height = ClientRt->bottom;

    SelectObject(BufferHDC, hBitmap);

    return 0;
}

void Window_Paint_Handler(IMAGE* pDisplay)
{
    // Fill the background of our window.

    capi_FillImage(pDisplay, COLOR(195, 195, 195, 255));

    // Now we draw our test image.
    // Note: The last parameter (Alpha) must be 255 for the image to be displayed normally.

    capi_DrawImageA(pDisplay, &exampleImage, 0, 0, 255);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC WinDC;
    PAINTSTRUCT ps;
    RECT WinArea;
    RECT ClientArea;
    int BorderWidth;
    int BorderHeight;

    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_ERASEBKGND:
        return TRUE;
    case WM_PAINT:
    {
        WinDC = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &ClientArea);

        if ((ClientArea.right == 0) || (ClientArea.bottom == 0)) goto exit_paint_message;
        if ((ClientArea.right != FrameBuffer.Width) || (ClientArea.bottom != FrameBuffer.Height))
        {
            if (SetupWindowFrameBuffer(WinDC, &ClientArea) != 0) goto exit_paint_message;
        }

        Window_Paint_Handler(&FrameBuffer);

        SetDIBits(BufferHDC, hBitmap, 0,
            pDisplayBitmap->bmiHeader.biHeight, FrameBuffer.Pixels, pDisplayBitmap, 0);
        BitBlt(WinDC, 0, 0, ClientArea.right, ClientArea.bottom, BufferHDC, 0, 0, 0x00CC0020);

    exit_paint_message:
        EndPaint(hWnd, &ps);
        break;
    }
    case WM_CREATE:
    {
        Window_hWnd = hWnd;

        GetWindowRect(hWnd, &WinArea);
        GetClientRect(hWnd, &ClientArea);

        BorderWidth = WinArea.right - ClientArea.right;
        BorderHeight = WinArea.bottom - ClientArea.bottom;

        SetWindowPos(hWnd, NULL,
            0, 0,
            BorderWidth + ClientWidth, BorderHeight + ClientHeight, SWP_NOMOVE | SWP_NOZORDER);

        GetWindowRect(hWnd, &WinArea);

        SetWindowPos(hWnd, NULL,
            (GetSystemMetrics(SM_CXSCREEN) - (WinArea.right - WinArea.left)) / 2,
            (GetSystemMetrics(SM_CYSCREEN) - (WinArea.bottom - WinArea.top)) / 2,
            0, 0, SWP_NOSIZE | SWP_NOZORDER);
        break;
    }
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI ApplicationEntryPoint(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ STRING* pCmdLine, _In_ int nCmdShow)
{
    MSG msg;
    WNDCLASSEX wcex;
    void* myLoadedFile;
    U64 FileSize;
    I32 ErrorCode;

    // Load our image to draw to the window frame buffer.

    myLoadedFile = LoadFile(STR("C:/Users/Public/myTestImage.ico"), &FileSize);
    if (myLoadedFile == 0)
    {
        MessageBox(0, STR("LoadFile Failed."), STR("Error!"), MB_OK);
        return 0;
    }

    ErrorCode = capi_LoadImageFromMemory(&exampleImage, 1, myLoadedFile, FileSize);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        MessageBox(0, STR("capi_LoadImageFromMemory Failed."), STR("Error!"), MB_OK);
        return 0;
    }

    // The client area of our window will be the same size as our test image.

    ClientWidth = exampleImage.Width;
    ClientHeight = exampleImage.Height;

    // Create the display window and enter the thread/window message loop.

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = WinClassName;
    wcex.hIconSm = NULL;

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(0, STR("Failed to register the window class."), STR("Error!"), MB_OK);
        return 0;
    }

    // Note: The 700 (Width) and 500 (Height) values are just dummy values. The Width and Height get set in the WM_CREATE message handler.

    CreateWindowEx(0, WinClassName, WinTitle,
        WS_VISIBLE | WS_CLIPCHILDREN | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX,
        0, 0, 700, 500, NULL, NULL, hInstance, NULL);

    if (!Window_hWnd)
    {
        MessageBox(0, STR("Failed to create the window."), STR("Error!"), MB_OK);
        return 0;
    }

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    FreeSysInternal();

    return 0;
}

The CAPI project is now available on GitHub for image processing. This library has a simple API, is small in size, and has great compatibility. Speed improvements are currently being worked on. Tested and works on Windows and Linux. This library currently supports the following image formats:

  • BMP (bitmap)
  • JPG (jpeg)
  • PNG (Portable Network Graphics)
  • ICO (icon)

In my following examples i will be using C++ in Visual Studio on Windows.

To get started first we need some simple routines for loading and saving files. I have created the functions LoadFile and SaveFile for this purpose. The following is an example console program to convert a .ico formatted file to a .png formatted file.
The CAPI functions we will be using are:

  • capi_LoadImageFromMemory
    • This function detects the image format and loads the image into a simple format to work with.
  • capi_Create_PNG_ImageToMemory
    • This function creates a PNG formatted image from the image we loaded.

#include <Windows.h>
#include <CAPI.h>

#ifdef  UNICODE
#define app_fopen _wfopen_s
#define app_printf wprintf
#else
#define app_fopen fopen_s
#define app_printf printf
#endif //  UNICODE

void* LoadFile(const STRING* FilePath, U64* pFileSize)
{
    FILE* Stream;
    size_t BufferLength;
    void* pThisFile;
    void* pNewBlock;

    if ((FilePath == 0) || (pFileSize == 0)) return 0;

    *pFileSize = 0;

    if (app_fopen(&Stream, FilePath, STR("rb")) != 0) return 0;
    if (Stream == 0) return 0;

    pThisFile = 0;
    BufferLength = 0;

    do
    {
        BufferLength += 0x1000;

        pNewBlock = capi_realloc(pThisFile, BufferLength);
        if (pNewBlock == 0)
        {
            if (pThisFile != 0) capi_free(pThisFile);
            fclose(Stream);
            return 0;
        }

        pThisFile = pNewBlock;

        *pFileSize += fread(&((U8*)pThisFile)[*pFileSize], 1, 0x1000, Stream);
    } while (!(feof(Stream)));

    fclose(Stream);

    return pThisFile;
}

I32 SaveFile(const STRING* FilePath, void* pFilePointer, U64 FileSize)
{
    FILE* Stream;
    size_t nBytesWrite;
    I32 ErrorCode;

    if ((FilePath == 0) || (pFilePointer == 0) || (FileSize == 0)) return CAPI_ERROR_INVALID_PARAMETER;

    ErrorCode = CAPI_ERROR_NONE;

    if (app_fopen(&Stream, FilePath, STR("w+b")) != 0) return CAPI_ERROR_ACCESS_DENIED;
    if (Stream == 0) return CAPI_ERROR_ACCESS_DENIED;

    nBytesWrite = fwrite(pFilePointer, 1, (size_t)FileSize, Stream);
    if (nBytesWrite != FileSize)
    {
        ErrorCode = CAPI_ERROR_ACCESS_DENIED;
        goto exit_func;
    }

exit_func:
    fclose(Stream);

    return ErrorCode;
}

int main()
{
    IMAGE exampleImage;
    void* myLoadedFile;
    I32 ErrorCode;
    U64 FileSize;
    PNG* myNewFile;
    PNG_PARAMETERS png_params;

    myLoadedFile = LoadFile(STR("C:/Users/Public/myTestImage.ico"), &FileSize);
    if (myLoadedFile == 0)
    {
        app_printf(STR("LoadFile Failed."));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    ErrorCode = capi_LoadImageFromMemory(&exampleImage, 1, myLoadedFile, FileSize);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        app_printf(STR("capi_LoadImageFromMemory Failed. ErrorCode: "));
        app_printf(capi_ErrorCodeToString(ErrorCode));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    png_params.CompressionMethod = 0;
    png_params.Level = Z_DEFAULT_COMPRESSION;
    png_params.FilterMethod = 0;
    png_params.InterlaceMethod = 0;
    png_params.IDAT_Length = 0x20000;

    ErrorCode = capi_Create_PNG_ImageToMemory(&myNewFile, &FileSize, &exampleImage, &png_params);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        app_printf(STR("capi_Create_PNG_ImageToMemory Failed. ErrorCode: "));
        app_printf(capi_ErrorCodeToString(ErrorCode));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    ErrorCode = SaveFile(STR("C:/Users/Public/myTestImage.png"), myNewFile, FileSize);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        app_printf(STR("SaveFile Failed. ErrorCode: "));
        app_printf(capi_ErrorCodeToString(ErrorCode));
        app_printf(STR("\n"));
        while (true) { Sleep(100); }
    }

    app_printf(STR("Done!"));
    while (true) { Sleep(100); }
}

In this next example i will be creating a simple window that has double buffering.
We will draw our test image to the window in our Window_Paint_Handler function.
The CAPI functions we will be using are:

  • capi_LoadImageFromMemory
    • This function detects the image format and loads the image into a simple format to work with.
  • capi_FillImage
    • This function fills an image with the desired color. In our case we are filling the frame buffer.
  • capi_DrawImageA
    • This function draws an image onto another image. In our case we are drawing our test image to the frame buffer.

#include <Windows.h>
#include <CAPI.h>

#define WinClassName STR("ExampleProgram")
#define WinTitle STR("Example Program")

#ifdef  UNICODE
#define app_fopen _wfopen_s
#define app_printf wprintf
#define ApplicationEntryPoint wWinMain
#else
#define app_fopen fopen_s
#define app_printf printf
#define ApplicationEntryPoint WinMain
#endif //  UNICODE

static HWND Window_hWnd;
static HDC BufferHDC;
static BITMAPINFO* pDisplayBitmap;
static HBITMAP hBitmap;

static int ClientWidth;
static int ClientHeight;
static IMAGE FrameBuffer;

static IMAGE exampleImage;

void* LoadFile(const STRING* FilePath, U64* pFileSize)
{
    FILE* Stream;
    size_t BufferLength;
    void* pThisFile;
    void* pNewBlock;

    if ((FilePath == 0) || (pFileSize == 0)) return 0;

    *pFileSize = 0;

    if (app_fopen(&Stream, FilePath, STR("rb")) != 0) return 0;
    if (Stream == 0) return 0;

    pThisFile = 0;
    BufferLength = 0;

    do
    {
        BufferLength += 0x1000;

        pNewBlock = capi_realloc(pThisFile, BufferLength);
        if (pNewBlock == 0)
        {
            if (pThisFile != 0) capi_free(pThisFile);
            fclose(Stream);
            return 0;
        }

        pThisFile = pNewBlock;

        *pFileSize += fread(&((U8*)pThisFile)[*pFileSize], 1, 0x1000, Stream);
    } while (!(feof(Stream)));

    fclose(Stream);

    return pThisFile;
}

I32 SaveFile(const STRING* FilePath, void* pFilePointer, U64 FileSize)
{
    FILE* Stream;
    size_t nBytesWrite;
    I32 ErrorCode;

    if ((FilePath == 0) || (pFilePointer == 0) || (FileSize == 0)) return CAPI_ERROR_INVALID_PARAMETER;

    ErrorCode = CAPI_ERROR_NONE;

    if (app_fopen(&Stream, FilePath, STR("w+b")) != 0) return CAPI_ERROR_ACCESS_DENIED;
    if (Stream == 0) return CAPI_ERROR_ACCESS_DENIED;

    nBytesWrite = fwrite(pFilePointer, 1, (size_t)FileSize, Stream);
    if (nBytesWrite != FileSize)
    {
        ErrorCode = CAPI_ERROR_ACCESS_DENIED;
        goto exit_func;
    }

exit_func:
    fclose(Stream);

    return ErrorCode;
}

void FreeSysInternal()
{
    if (BufferHDC != 0)
    {
        DeleteDC(BufferHDC);
        BufferHDC = 0;
    }

    if (pDisplayBitmap != 0)
    {
        capi_free(pDisplayBitmap);
        pDisplayBitmap = 0;
    }

    if (hBitmap != 0)
    {
        DeleteObject(hBitmap);
        hBitmap = 0;
    }
}

U32 SetupWindowFrameBuffer(HDC WindowHDC, RECT* ClientRt)
{
    FreeSysInternal();

    pDisplayBitmap = (BITMAPINFO*)capi_malloc(sizeof(BITMAPINFOHEADER));
    if (pDisplayBitmap == 0) return 1;

    pDisplayBitmap->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pDisplayBitmap->bmiHeader.biWidth = ClientRt->right;
    pDisplayBitmap->bmiHeader.biHeight = -ClientRt->bottom;
    pDisplayBitmap->bmiHeader.biPlanes = 1;
    pDisplayBitmap->bmiHeader.biBitCount = 32;
    pDisplayBitmap->bmiHeader.biCompression = 0;
    pDisplayBitmap->bmiHeader.biSizeImage = 0;
    pDisplayBitmap->bmiHeader.biXPelsPerMeter = 0;
    pDisplayBitmap->bmiHeader.biYPelsPerMeter = 0;
    pDisplayBitmap->bmiHeader.biClrUsed = 0;
    pDisplayBitmap->bmiHeader.biClrImportant = 0;

    BufferHDC = CreateCompatibleDC(WindowHDC);
    if (BufferHDC == 0)
    {
        capi_free(pDisplayBitmap);
        return 2;
    }

    hBitmap = CreateDIBSection(BufferHDC, pDisplayBitmap, 0,
        (void**)&FrameBuffer.Pixels, 0, 0);

    if (hBitmap == 0)
    {
        DeleteDC(BufferHDC);
        capi_free(pDisplayBitmap);
        return 3;
    }

    GdiFlush();

    FrameBuffer.ScanLine = ClientRt->right;
    FrameBuffer.Width = ClientRt->right;
    FrameBuffer.Height = ClientRt->bottom;

    SelectObject(BufferHDC, hBitmap);

    return 0;
}

void Window_Paint_Handler(IMAGE* pDisplay)
{
    // Fill the background of our window.

    capi_FillImage(pDisplay, COLOR(195, 195, 195, 255));

    // Now we draw our test image.
    // Note: The last parameter (Alpha) must be 255 for the image to be displayed normally.

    capi_DrawImageA(pDisplay, &exampleImage, 0, 0, 255);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC WinDC;
    PAINTSTRUCT ps;
    RECT WinArea;
    RECT ClientArea;
    int BorderWidth;
    int BorderHeight;

    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_ERASEBKGND:
        return TRUE;
    case WM_PAINT:
    {
        WinDC = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &ClientArea);

        if ((ClientArea.right == 0) || (ClientArea.bottom == 0)) goto exit_paint_message;
        if ((ClientArea.right != FrameBuffer.Width) || (ClientArea.bottom != FrameBuffer.Height))
        {
            if (SetupWindowFrameBuffer(WinDC, &ClientArea) != 0) goto exit_paint_message;
        }

        Window_Paint_Handler(&FrameBuffer);

        SetDIBits(BufferHDC, hBitmap, 0,
            pDisplayBitmap->bmiHeader.biHeight, FrameBuffer.Pixels, pDisplayBitmap, 0);
        BitBlt(WinDC, 0, 0, ClientArea.right, ClientArea.bottom, BufferHDC, 0, 0, 0x00CC0020);

    exit_paint_message:
        EndPaint(hWnd, &ps);
        break;
    }
    case WM_CREATE:
    {
        Window_hWnd = hWnd;

        GetWindowRect(hWnd, &WinArea);
        GetClientRect(hWnd, &ClientArea);

        BorderWidth = WinArea.right - ClientArea.right;
        BorderHeight = WinArea.bottom - ClientArea.bottom;

        SetWindowPos(hWnd, NULL,
            0, 0,
            BorderWidth + ClientWidth, BorderHeight + ClientHeight, SWP_NOMOVE | SWP_NOZORDER);

        GetWindowRect(hWnd, &WinArea);

        SetWindowPos(hWnd, NULL,
            (GetSystemMetrics(SM_CXSCREEN) - (WinArea.right - WinArea.left)) / 2,
            (GetSystemMetrics(SM_CYSCREEN) - (WinArea.bottom - WinArea.top)) / 2,
            0, 0, SWP_NOSIZE | SWP_NOZORDER);
        break;
    }
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI ApplicationEntryPoint(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ STRING* pCmdLine, _In_ int nCmdShow)
{
    MSG msg;
    WNDCLASSEX wcex;
    void* myLoadedFile;
    U64 FileSize;
    I32 ErrorCode;

    // Load our image to draw to the window frame buffer.

    myLoadedFile = LoadFile(STR("C:/Users/Public/myTestImage.ico"), &FileSize);
    if (myLoadedFile == 0)
    {
        MessageBox(0, STR("LoadFile Failed."), STR("Error!"), MB_OK);
        return 0;
    }

    ErrorCode = capi_LoadImageFromMemory(&exampleImage, 1, myLoadedFile, FileSize);
    if (ErrorCode != CAPI_ERROR_NONE)
    {
        MessageBox(0, STR("capi_LoadImageFromMemory Failed."), STR("Error!"), MB_OK);
        return 0;
    }

    // The client area of our window will be the same size as our test image.

    ClientWidth = exampleImage.Width;
    ClientHeight = exampleImage.Height;

    // Create the display window and enter the thread/window message loop.

    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = WinClassName;
    wcex.hIconSm = NULL;

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(0, STR("Failed to register the window class."), STR("Error!"), MB_OK);
        return 0;
    }

    // Note: The 700 (Width) and 500 (Height) values are just dummy values. The Width and Height get set in the WM_CREATE message handler.

    CreateWindowEx(0, WinClassName, WinTitle,
        WS_VISIBLE | WS_CLIPCHILDREN | WS_BORDER | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX,
        0, 0, 700, 500, NULL, NULL, hInstance, NULL);

    if (!Window_hWnd)
    {
        MessageBox(0, STR("Failed to create the window."), STR("Error!"), MB_OK);
        return 0;
    }

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    FreeSysInternal();

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文