3

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?

BCS
  • 75,627
  • 68
  • 187
  • 294

9 Answers9

3

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

Michal Minich
  • 2,387
  • 1
  • 22
  • 30
2

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:

ponce
  • 919
  • 5
  • 15
2

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

http://freeimage.sourceforge.net/

sidewinderguy
  • 2,394
  • 4
  • 24
  • 24
1

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.

mingos
  • 23,778
  • 12
  • 70
  • 107
  • Any tips on how to extract the data from the file? (I'm willing to assume that the file is encoded in 24bit color) – BCS Jan 11 '10 at 00:26
  • Maybe this code will be of some help: http://doryen.eptalys.net/svn-libtcod/trunk/src/sys_sdl_img_png.c --- it's well documented and written in a readable manner. It's from a library that a friend of mine maintains. Basically, what these two functions do is importing a png image from file to a SDL surface and exporting it back, respectively. – mingos Jan 11 '10 at 01:03
  • You might also want to have look at this: http://www.libpng.org/pub/png/book/chapter13.html – mingos Jan 11 '10 at 01:06
  • Sorry, that should have been: Any tips on how to extract the data from the **Bitmap** file? – BCS Jan 12 '10 at 05:28
  • Oh, sorry. Well, bitmaps are raw pixel colour data. You just read the R,G,B values one by one. You just have to figure out where the file header ends and start reading from there. – mingos Jan 12 '10 at 07:31
  • Cool. I guess a little fun with mspaint and a hex vewier would let me find that. – BCS Jan 12 '10 at 21:08
  • Yeah, I guess. You can have a look at the format specification too: http://www.fileformat.info/format/bmp/corion.htm - Hope it's of use to you. Have fun! – mingos Jan 12 '10 at 21:30
1

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)

Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
0

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.

amphetamachine
  • 27,620
  • 12
  • 60
  • 72
0

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  ...
ephemient
  • 198,619
  • 38
  • 280
  • 391
0

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.

Lutger
  • 962
  • 1
  • 6
  • 10
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;
}
b.sullender
  • 163
  • 1
  • 16