3

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

我需要/想要的东西:

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

任何人都知道这样的事情吗?

4

9 回答 9

3

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

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

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

于 2010-01-11T08:15:28.970 回答
2

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

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

于 2010-01-15T16:10:42.653 回答
2

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

http://freeimage.sourceforge.net/

于 2011-07-19T21:54:32.783 回答
1

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

除此之外,您可以尝试直接在位图上工作,根本不需要库。

于 2010-01-11T00:14:11.307 回答
1

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

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

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

于 2010-01-11T00:29:56.380 回答
0

您可以随时尝试gdimage库。我从来没有遇到过任何问题,尽管我使用它所做的工作的迷雾一直是在 PHP 中。

于 2010-01-11T00:17:39.130 回答
0

您可以使用Netpbm等软件转换为 PPM 格式/从PPM 格式转换,无需外部库即可从任何程序中轻松读取/写入

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 ...
于 2010-01-15T16:36:42.833 回答
0

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

于 2010-02-13T20:42:41.730 回答
0

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;
}
于 2020-12-17T12:14:06.577 回答