Compare commits
8 Commits
e64cbfdcf2
...
e0e7fad858
Author | SHA1 | Date |
---|---|---|
Simon Bruder | e0e7fad858 | |
Simon Bruder | dc04c458b5 | |
Simon Bruder | 9528d09748 | |
Simon Bruder | de2f76192c | |
Simon Bruder | 05749e4e8c | |
Simon Bruder | 0df0772d0b | |
Simon Bruder | 13d157b5a6 | |
Simon Bruder | 8d4cf138e1 |
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
set -euo pipefail
|
||||||
|
dir="$1"
|
||||||
|
if [ ! -d "$dir" ]; then
|
||||||
|
echo "first argument must be a directory, e.g. u02" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
out="/tmp/ecg-${dir}-simon-bruder.zip"
|
||||||
|
git archive --format=zip master "$dir" -o "$out"
|
||||||
|
echo "$out"
|
|
@ -4,6 +4,6 @@ set -euo pipefail
|
||||||
export FILTER_BRANCH_SQUELCH_WARNING=1
|
export FILTER_BRANCH_SQUELCH_WARNING=1
|
||||||
git branch -D filtered
|
git branch -D filtered
|
||||||
git switch -c filtered
|
git switch -c filtered
|
||||||
git filter-branch -f --tree-filter "rm -f $(rg --files-without-match 'SPDX-License-Identifier: (L)?GPL-3.0-or-later' -g '/u??/**/*' | tr '\n' ' ')" HEAD
|
git filter-branch -f --tree-filter "rm -f $(rg --files-without-match 'SPDX-License-Identifier: ((L)?GPL-3.0-or-later|MIT)' -g '/u??/**/*' | tr '\n' ' ')" HEAD
|
||||||
git push -f -u filtered filtered
|
git push -f -u filtered filtered
|
||||||
git switch -
|
git switch -
|
||||||
|
|
11
flake.nix
11
flake.nix
|
@ -41,6 +41,17 @@
|
||||||
})
|
})
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
|
u03 = pkgs.callPackage
|
||||||
|
({ stdenv, cmake, freeglut, libGL, libGLU }: stdenv.mkDerivation {
|
||||||
|
name = "ecg-u03";
|
||||||
|
|
||||||
|
src = ./u03;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ cmake ];
|
||||||
|
buildInputs = [ freeglut libGL libGLU ];
|
||||||
|
})
|
||||||
|
{ };
|
||||||
|
|
||||||
u01-nocheck = mkNocheck u01;
|
u01-nocheck = mkNocheck u01;
|
||||||
u02-nocheck = mkNocheck u02;
|
u02-nocheck = mkNocheck u02;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
#ifndef _BMP_H_
|
||||||
|
#define _BMP_H_
|
||||||
|
|
||||||
|
#pragma warning(disable:4996)
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
|
||||||
|
QDBMP - Quick n' Dirty BMP
|
||||||
|
|
||||||
|
v1.0.0 - 2007-04-07
|
||||||
|
http://qdbmp.sourceforge.net
|
||||||
|
|
||||||
|
|
||||||
|
The library supports the following BMP variants:
|
||||||
|
1. Uncompressed 32 BPP (alpha values are ignored)
|
||||||
|
2. Uncompressed 24 BPP
|
||||||
|
3. Uncompressed 8 BPP (indexed color)
|
||||||
|
|
||||||
|
QDBMP is free and open source software, distributed
|
||||||
|
under the MIT licence.
|
||||||
|
|
||||||
|
Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
**************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Type definitions */
|
||||||
|
#ifndef UINT
|
||||||
|
#define UINT unsigned long int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USHORT
|
||||||
|
#define USHORT unsigned short
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UCHAR
|
||||||
|
#define UCHAR unsigned char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Version */
|
||||||
|
#define QDBMP_VERSION_MAJOR 1
|
||||||
|
#define QDBMP_VERSION_MINOR 0
|
||||||
|
#define QDBMP_VERSION_PATCH 1
|
||||||
|
|
||||||
|
|
||||||
|
/* Error codes */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BMP_OK = 0, /* No error */
|
||||||
|
BMP_ERROR, /* General error */
|
||||||
|
BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */
|
||||||
|
BMP_IO_ERROR, /* General input/output error */
|
||||||
|
BMP_FILE_NOT_FOUND, /* File not found */
|
||||||
|
BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */
|
||||||
|
BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */
|
||||||
|
BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */
|
||||||
|
BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */
|
||||||
|
BMP_ERROR_NUM
|
||||||
|
} BMP_STATUS;
|
||||||
|
|
||||||
|
|
||||||
|
/* Bitmap image */
|
||||||
|
typedef struct _BMP BMP;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************** Public methods **********************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* Construction/destruction */
|
||||||
|
BMP* BMP_Create ( UINT width, UINT height, USHORT depth );
|
||||||
|
void BMP_Free ( BMP* bmp );
|
||||||
|
|
||||||
|
|
||||||
|
/* I/O */
|
||||||
|
BMP* BMP_ReadFile ( const char* filename );
|
||||||
|
void BMP_WriteFile ( BMP* bmp, const char* filename );
|
||||||
|
|
||||||
|
|
||||||
|
/* Meta info */
|
||||||
|
UINT BMP_GetWidth ( BMP* bmp );
|
||||||
|
UINT BMP_GetHeight ( BMP* bmp );
|
||||||
|
USHORT BMP_GetDepth ( BMP* bmp );
|
||||||
|
|
||||||
|
|
||||||
|
/* Pixel access */
|
||||||
|
void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b );
|
||||||
|
void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b );
|
||||||
|
void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val );
|
||||||
|
void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val );
|
||||||
|
unsigned char* BMP_GetImageData ( BMP *bmp );
|
||||||
|
|
||||||
|
|
||||||
|
/* Palette handling */
|
||||||
|
void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b );
|
||||||
|
void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b );
|
||||||
|
|
||||||
|
|
||||||
|
/* Error handling */
|
||||||
|
BMP_STATUS BMP_GetError ();
|
||||||
|
const char* BMP_GetErrorDescription ();
|
||||||
|
|
||||||
|
|
||||||
|
/* Useful macro that may be used after each BMP operation to check for an error */
|
||||||
|
#define BMP_CHECK_ERROR( output_file, return_value ) \
|
||||||
|
if ( BMP_GetError() != BMP_OK ) \
|
||||||
|
{ \
|
||||||
|
fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \
|
||||||
|
return( return_value ); \
|
||||||
|
} \
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,825 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
#include "qdbmp.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Bitmap header */
|
||||||
|
typedef struct _BMP_Header
|
||||||
|
{
|
||||||
|
USHORT Magic; /* Magic identifier: "BM" */
|
||||||
|
UINT FileSize; /* Size of the BMP file in bytes */
|
||||||
|
USHORT Reserved1; /* Reserved */
|
||||||
|
USHORT Reserved2; /* Reserved */
|
||||||
|
UINT DataOffset; /* Offset of image data relative to the file's start */
|
||||||
|
UINT HeaderSize; /* Size of the header in bytes */
|
||||||
|
UINT Width; /* Bitmap's width */
|
||||||
|
UINT Height; /* Bitmap's height */
|
||||||
|
USHORT Planes; /* Number of color planes in the bitmap */
|
||||||
|
USHORT BitsPerPixel; /* Number of bits per pixel */
|
||||||
|
UINT CompressionType; /* Compression type */
|
||||||
|
UINT ImageDataSize; /* Size of uncompressed image's data */
|
||||||
|
UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */
|
||||||
|
UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */
|
||||||
|
UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */
|
||||||
|
UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */
|
||||||
|
} BMP_Header;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data structure */
|
||||||
|
struct _BMP
|
||||||
|
{
|
||||||
|
BMP_Header Header;
|
||||||
|
UCHAR* Palette;
|
||||||
|
UCHAR* Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Holds the last error code */
|
||||||
|
static BMP_STATUS BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
|
||||||
|
/* Error description strings */
|
||||||
|
static const char* BMP_ERROR_STRING[] =
|
||||||
|
{
|
||||||
|
"No error",
|
||||||
|
"General error",
|
||||||
|
"Could not allocate enough memory to complete the operation",
|
||||||
|
"File input/output error",
|
||||||
|
"File not found",
|
||||||
|
"File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)",
|
||||||
|
"File is not a valid BMP image",
|
||||||
|
"An argument is invalid or out of range",
|
||||||
|
"The requested action is not compatible with the BMP's type"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Size of the palette data for 8 BPP bitmaps */
|
||||||
|
#define BMP_PALETTE_SIZE ( 256 * 4 )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************** Forward declarations **********************************/
|
||||||
|
int ReadHeader ( BMP* bmp, FILE* f );
|
||||||
|
int WriteHeader ( BMP* bmp, FILE* f );
|
||||||
|
|
||||||
|
int ReadUINT ( UINT* x, FILE* f );
|
||||||
|
int ReadUSHORT ( USHORT *x, FILE* f );
|
||||||
|
|
||||||
|
int WriteUINT ( UINT x, FILE* f );
|
||||||
|
int WriteUSHORT ( USHORT x, FILE* f );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************** Public methods **********************************/
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Creates a blank BMP image with the specified dimensions
|
||||||
|
and bit depth.
|
||||||
|
**************************************************************/
|
||||||
|
BMP* BMP_Create( UINT width, UINT height, USHORT depth )
|
||||||
|
{
|
||||||
|
BMP* bmp;
|
||||||
|
int bytes_per_pixel = depth >> 3;
|
||||||
|
UINT bytes_per_row;
|
||||||
|
|
||||||
|
if ( height <= 0 || width <= 0 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( depth != 8 && depth != 24 && depth != 32 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate the bitmap data structure */
|
||||||
|
bmp = (BMP*)calloc( 1, sizeof( BMP ) );
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set header' default values */
|
||||||
|
bmp->Header.Magic = 0x4D42;
|
||||||
|
bmp->Header.Reserved1 = 0;
|
||||||
|
bmp->Header.Reserved2 = 0;
|
||||||
|
bmp->Header.HeaderSize = 40;
|
||||||
|
bmp->Header.Planes = 1;
|
||||||
|
bmp->Header.CompressionType = 0;
|
||||||
|
bmp->Header.HPixelsPerMeter = 0;
|
||||||
|
bmp->Header.VPixelsPerMeter = 0;
|
||||||
|
bmp->Header.ColorsUsed = 0;
|
||||||
|
bmp->Header.ColorsRequired = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* Calculate the number of bytes used to store a single image row. This is always
|
||||||
|
rounded up to the next multiple of 4. */
|
||||||
|
bytes_per_row = width * bytes_per_pixel;
|
||||||
|
bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 );
|
||||||
|
|
||||||
|
|
||||||
|
/* Set header's image specific values */
|
||||||
|
bmp->Header.Width = width;
|
||||||
|
bmp->Header.Height = height;
|
||||||
|
bmp->Header.BitsPerPixel = depth;
|
||||||
|
bmp->Header.ImageDataSize = bytes_per_row * height;
|
||||||
|
bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
|
||||||
|
bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 );
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate palette */
|
||||||
|
if ( bmp->Header.BitsPerPixel == 8 )
|
||||||
|
{
|
||||||
|
bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) );
|
||||||
|
if ( bmp->Palette == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bmp->Palette = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate pixels */
|
||||||
|
bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) );
|
||||||
|
if ( bmp->Data == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||||
|
free( bmp->Palette );
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
return bmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Frees all the memory used by the specified BMP image.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_Free( BMP* bmp )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bmp->Palette != NULL )
|
||||||
|
{
|
||||||
|
free( bmp->Palette );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bmp->Data != NULL )
|
||||||
|
{
|
||||||
|
free( bmp->Data );
|
||||||
|
}
|
||||||
|
|
||||||
|
free( bmp );
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Reads the specified BMP image file.
|
||||||
|
**************************************************************/
|
||||||
|
BMP* BMP_ReadFile( const char* filename )
|
||||||
|
{
|
||||||
|
BMP* bmp;
|
||||||
|
FILE* f;
|
||||||
|
|
||||||
|
if ( filename == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate */
|
||||||
|
bmp = (BMP*)calloc( 1, sizeof( BMP ) );
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Open file */
|
||||||
|
f = fopen( filename, "rb" );
|
||||||
|
if ( f == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read header */
|
||||||
|
if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
|
||||||
|
fclose( f );
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Verify that the bitmap variant is supported */
|
||||||
|
if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 )
|
||||||
|
|| bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED;
|
||||||
|
fclose( f );
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate and read palette */
|
||||||
|
if ( bmp->Header.BitsPerPixel == 8 )
|
||||||
|
{
|
||||||
|
bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) );
|
||||||
|
if ( bmp->Palette == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||||
|
fclose( f );
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
|
||||||
|
fclose( f );
|
||||||
|
free( bmp->Palette );
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* Not an indexed image */
|
||||||
|
{
|
||||||
|
bmp->Palette = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate memory for image data */
|
||||||
|
bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize );
|
||||||
|
if ( bmp->Data == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY;
|
||||||
|
fclose( f );
|
||||||
|
free( bmp->Palette );
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read image data */
|
||||||
|
if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_FILE_INVALID;
|
||||||
|
fclose( f );
|
||||||
|
free( bmp->Data );
|
||||||
|
free( bmp->Palette );
|
||||||
|
free( bmp );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fclose( f );
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
return bmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Writes the BMP image to the specified file.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_WriteFile( BMP* bmp, const char* filename )
|
||||||
|
{
|
||||||
|
FILE* f;
|
||||||
|
|
||||||
|
if ( filename == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Open file */
|
||||||
|
f = fopen( filename, "wb" );
|
||||||
|
if ( f == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write header */
|
||||||
|
if ( WriteHeader( bmp, f ) != BMP_OK )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
|
||||||
|
fclose( f );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write palette */
|
||||||
|
if ( bmp->Palette )
|
||||||
|
{
|
||||||
|
if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
|
||||||
|
fclose( f );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write data */
|
||||||
|
if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_IO_ERROR;
|
||||||
|
fclose( f );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
fclose( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Returns the image's width.
|
||||||
|
**************************************************************/
|
||||||
|
UINT BMP_GetWidth( BMP* bmp )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
return ( bmp->Header.Width );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Returns the image's height.
|
||||||
|
**************************************************************/
|
||||||
|
UINT BMP_GetHeight( BMP* bmp )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
return ( bmp->Header.Height );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Returns the image's color depth (bits per pixel).
|
||||||
|
**************************************************************/
|
||||||
|
USHORT BMP_GetDepth( BMP* bmp )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
return ( bmp->Header.BitsPerPixel );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Populates the arguments with the specified pixel's RGB
|
||||||
|
values.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b )
|
||||||
|
{
|
||||||
|
UCHAR* pixel;
|
||||||
|
UINT bytes_per_row;
|
||||||
|
UCHAR bytes_per_pixel;
|
||||||
|
|
||||||
|
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
|
||||||
|
|
||||||
|
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||||
|
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||||
|
|
||||||
|
/* Calculate the location of the relevant pixel (rows are flipped) */
|
||||||
|
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
|
||||||
|
|
||||||
|
|
||||||
|
/* In indexed color mode the pixel's value is an index within the palette */
|
||||||
|
if ( bmp->Header.BitsPerPixel == 8 )
|
||||||
|
{
|
||||||
|
pixel = bmp->Palette + *pixel * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: colors are stored in BGR order */
|
||||||
|
if ( r ) *r = *( pixel + 2 );
|
||||||
|
if ( g ) *g = *( pixel + 1 );
|
||||||
|
if ( b ) *b = *( pixel + 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Sets the specified pixel's RGB values.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b )
|
||||||
|
{
|
||||||
|
UCHAR* pixel;
|
||||||
|
UINT bytes_per_row;
|
||||||
|
UCHAR bytes_per_pixel;
|
||||||
|
|
||||||
|
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
bytes_per_pixel = bmp->Header.BitsPerPixel >> 3;
|
||||||
|
|
||||||
|
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||||
|
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||||
|
|
||||||
|
/* Calculate the location of the relevant pixel (rows are flipped) */
|
||||||
|
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel );
|
||||||
|
|
||||||
|
/* Note: colors are stored in BGR order */
|
||||||
|
*( pixel + 2 ) = r;
|
||||||
|
*( pixel + 1 ) = g;
|
||||||
|
*( pixel + 0 ) = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Gets the specified pixel's color index.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val )
|
||||||
|
{
|
||||||
|
UCHAR* pixel;
|
||||||
|
UINT bytes_per_row;
|
||||||
|
|
||||||
|
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||||
|
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||||
|
|
||||||
|
/* Calculate the location of the relevant pixel */
|
||||||
|
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
|
||||||
|
|
||||||
|
|
||||||
|
if ( val ) *val = *pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Sets the specified pixel's color index.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val )
|
||||||
|
{
|
||||||
|
UCHAR* pixel;
|
||||||
|
UINT bytes_per_row;
|
||||||
|
|
||||||
|
if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
|
||||||
|
/* Row's size is rounded up to the next multiple of 4 bytes */
|
||||||
|
bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height;
|
||||||
|
|
||||||
|
/* Calculate the location of the relevant pixel */
|
||||||
|
pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x );
|
||||||
|
|
||||||
|
*pixel = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Gets the color value for the specified palette index.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( r ) *r = *( bmp->Palette + index * 4 + 2 );
|
||||||
|
if ( g ) *g = *( bmp->Palette + index * 4 + 1 );
|
||||||
|
if ( b ) *b = *( bmp->Palette + index * 4 + 0 );
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Sets the color value for the specified palette index.
|
||||||
|
**************************************************************/
|
||||||
|
void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( bmp->Header.BitsPerPixel != 8 )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*( bmp->Palette + index * 4 + 2 ) = r;
|
||||||
|
*( bmp->Palette + index * 4 + 1 ) = g;
|
||||||
|
*( bmp->Palette + index * 4 + 0 ) = b;
|
||||||
|
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Returns the last error code.
|
||||||
|
**************************************************************/
|
||||||
|
BMP_STATUS BMP_GetError()
|
||||||
|
{
|
||||||
|
return BMP_LAST_ERROR_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Returns a description of the last error code.
|
||||||
|
**************************************************************/
|
||||||
|
const char* BMP_GetErrorDescription()
|
||||||
|
{
|
||||||
|
if ( BMP_LAST_ERROR_CODE >= 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM )
|
||||||
|
{
|
||||||
|
return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************** Private methods **********************************/
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Reads the BMP file's header into the data structure.
|
||||||
|
Returns BMP_OK on success.
|
||||||
|
**************************************************************/
|
||||||
|
int ReadHeader( BMP* bmp, FILE* f )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL || f == NULL )
|
||||||
|
{
|
||||||
|
return BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The header's fields are read one by one, and converted from the format's
|
||||||
|
little endian to the system's native representation. */
|
||||||
|
if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR;
|
||||||
|
|
||||||
|
return BMP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Writes the BMP file's header into the data structure.
|
||||||
|
Returns BMP_OK on success.
|
||||||
|
**************************************************************/
|
||||||
|
int WriteHeader( BMP* bmp, FILE* f )
|
||||||
|
{
|
||||||
|
if ( bmp == NULL || f == NULL )
|
||||||
|
{
|
||||||
|
return BMP_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The header's fields are written one by one, and converted to the format's
|
||||||
|
little endian representation. */
|
||||||
|
if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR;
|
||||||
|
if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR;
|
||||||
|
|
||||||
|
return BMP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Reads a little-endian unsigned int from the file.
|
||||||
|
Returns non-zero on success.
|
||||||
|
**************************************************************/
|
||||||
|
int ReadUINT( UINT* x, FILE* f )
|
||||||
|
{
|
||||||
|
UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
|
||||||
|
|
||||||
|
if ( x == NULL || f == NULL )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fread( little, 4, 1, f ) != 1 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] );
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Reads a little-endian unsigned short int from the file.
|
||||||
|
Returns non-zero on success.
|
||||||
|
**************************************************************/
|
||||||
|
int ReadUSHORT( USHORT *x, FILE* f )
|
||||||
|
{
|
||||||
|
UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
|
||||||
|
|
||||||
|
if ( x == NULL || f == NULL )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fread( little, 2, 1, f ) != 1 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*x = ( little[ 1 ] << 8 | little[ 0 ] );
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Writes a little-endian unsigned int to the file.
|
||||||
|
Returns non-zero on success.
|
||||||
|
**************************************************************/
|
||||||
|
int WriteUINT( UINT x, FILE* f )
|
||||||
|
{
|
||||||
|
UCHAR little[ 4 ]; /* BMPs use 32 bit ints */
|
||||||
|
|
||||||
|
little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 );
|
||||||
|
little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 );
|
||||||
|
little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 );
|
||||||
|
little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 );
|
||||||
|
|
||||||
|
return ( f && fwrite( little, 4, 1, f ) == 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
Writes a little-endian unsigned short int to the file.
|
||||||
|
Returns non-zero on success.
|
||||||
|
**************************************************************/
|
||||||
|
int WriteUSHORT( USHORT x, FILE* f )
|
||||||
|
{
|
||||||
|
UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */
|
||||||
|
|
||||||
|
little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 );
|
||||||
|
little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 );
|
||||||
|
|
||||||
|
return ( f && fwrite( little, 2, 1, f ) == 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char* BMP_GetImageData( BMP *bmp )
|
||||||
|
{
|
||||||
|
int x, y, width, height;
|
||||||
|
unsigned char* data;
|
||||||
|
unsigned char r, g, b;
|
||||||
|
|
||||||
|
if ( bmp == NULL )
|
||||||
|
{
|
||||||
|
BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
width = BMP_GetWidth(bmp);
|
||||||
|
height = BMP_GetHeight(bmp);
|
||||||
|
|
||||||
|
data = (unsigned char*)calloc(1, width*height*3);
|
||||||
|
for (x=0; x<width; x++)
|
||||||
|
for (y=0; y<height; y++) {
|
||||||
|
BMP_GetPixelRGB(bmp, x, y, &r, &g, &b);
|
||||||
|
data[(x+y*width)*3 + 0] = r;
|
||||||
|
data[(x+y*width)*3 + 1] = g;
|
||||||
|
data[(x+y*width)*3 + 2] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
Reference in New Issue