【问题标题】:Simple image loading libraries简单的图像加载库
【发布时间】:2010-01-11 00:06:37
【问题描述】:

我有一个应用程序使用this library(实际上是direct port to D)进行一些图像处理。我正在寻找一些其他类似风格的库来加载其他文件类型。

我需要/想要的东西:

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

有人知道这样的事吗?

【问题讨论】:

    标签: c d image-loading


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • SDL_Image 为您与 libpng、libjpeg 和 libtiff 对话。
      【解决方案3】:

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

      http://freeimage.sourceforge.net/

      【讨论】:

        【解决方案4】:

        你可能想试试 libpng,虽然我不认为它好用。

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

        【讨论】:

        • 关于如何从文件中提取数据的任何提示? (我愿意假设文件以 24 位颜色编码)
        • 也许这段代码会有所帮助:doryen.eptalys.net/svn-libtcod/trunk/src/sys_sdl_img_png.c --- 它有很好的文档记录并以可读的方式编写。它来自我朋友维护的图书馆。基本上,这两个函数的作用是将 png 图像从文件导入到 SDL 表面,然后分别将其导出。
        • 你可能还想看看这个:libpng.org/pub/png/book/chapter13.html
        • 抱歉,应该是:关于如何从 Bitmap 文件中提取数据的任何提示?
        • 哦,对不起。好吧,位图是原始像素颜色数据。您只需一一读取 R、G、B 值。你只需要弄清楚文件头在哪里结束并从那里开始读取。
        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

          您可以随时尝试gdimage 库。我从来没有遇到过任何问题,虽然我用它完成的工作的迷雾是在 PHP 中。

          【讨论】:

            【解决方案7】:

            您可以使用诸如Netpbm 之类的软件与PPM format 进行转换,这非常可以轻松地从任何程序读取/写入,而无需外部库。

            PPM 文件如下所示:

            P6 800 600 255 # 后跟 800x600x3 字节的 0 到 255 之间的值,即 \xFF\x00\x00\x80\x80\x00\x00\xFF\x00\x00\x80\x80\x00\x00\xFF... # 但没有转义

            或者像这样:

            P3 800 600 255 # 后跟 0 到 255 之间的 800x600x3 十进制数,即 255 0 0 128 128 0 0 255 0 0 128 128 0 0 255 ...

            【讨论】:

              【解决方案8】:

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

              【讨论】:

                【解决方案9】:

                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;
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2015-06-23
                  • 2017-03-05
                  • 1970-01-01
                  • 2023-03-21
                  • 2011-02-13
                  • 1970-01-01
                  • 2011-07-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多