2025-08-22 21:50 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)

+ contrib/hbbmp/core.c
  + contrib/hbbmp/hbbmp.ch
  + contrib/hbbmp/hbbmp.h
  + contrib/hbbmp/hbbmp.hbc
  + contrib/hbbmp/hbbmp.hbp
  + contrib/hbbmp/hbbmp.hbx
  + contrib/hbbmp/readme.txt
  + contrib/hbbmp/tests/hbbmptst.prg
  + contrib/hbbmp/tests/hbmk.hbm
    + added new BMP image library for Harbour
    ; HBBMP is small library for Harbour dedicated to create and modify
      BMP images. It has not any 3rd party libs dependencies.
      See readme.txt for more information

  + contrib/hbzebra/tests/bmp.prg
    + added example code which uses HBBMP as backend for HBZEBRA and
      creates BMP images with generated barcodes.
This commit is contained in:
Przemysław Czerpak
2025-08-22 21:50:57 +02:00
parent 188c206440
commit 8319837387
11 changed files with 1451 additions and 0 deletions

View File

@@ -7,6 +7,25 @@
Entries may not always be in chronological/commit order. Entries may not always be in chronological/commit order.
See license at the end of file. */ See license at the end of file. */
2025-08-22 21:50 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
+ contrib/hbbmp/core.c
+ contrib/hbbmp/hbbmp.ch
+ contrib/hbbmp/hbbmp.h
+ contrib/hbbmp/hbbmp.hbc
+ contrib/hbbmp/hbbmp.hbp
+ contrib/hbbmp/hbbmp.hbx
+ contrib/hbbmp/readme.txt
+ contrib/hbbmp/tests/hbbmptst.prg
+ contrib/hbbmp/tests/hbmk.hbm
+ added new BMP image library for Harbour
; HBBMP is small library for Harbour dedicated to create and modify
BMP images. It has not any 3rd party libs dependencies.
See readme.txt for more information
+ contrib/hbzebra/tests/bmp.prg
+ added example code which uses HBBMP as backend for HBZEBRA and
creates BMP images with generated barcodes.
2025-08-22 12:00 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) 2025-08-22 12:00 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
* contrib/hbzebra/coredraw.c * contrib/hbzebra/coredraw.c
* contrib/hbzebra/hbzebra.hbx * contrib/hbzebra/hbzebra.hbx

876
contrib/hbbmp/core.c Normal file
View File

@@ -0,0 +1,876 @@
/*
* BMP image library for Harbour
*
* Copyright 2025 Przemyslaw Czerpak <druzus /at/ priv.onet.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#include "hbbmp.h"
#include "hbapi.h"
#include "hbapifs.h"
#include "hbapierr.h"
void hb_bmp_free( PHB_BMPINFO pBMP )
{
if( pBMP->data )
hb_xfree( pBMP->data );
hb_xfree( pBMP );
}
PHB_BMPINFO hb_bmp_new( int width, int height, int depth, int dpi, int * piError )
{
PHB_BMPINFO pBMP = NULL;
HB_BOOL fromtop = height < 0;
if( piError )
*piError = 0;
if( fromtop )
height = -height;
if( dpi == 0 )
dpi = HB_BMP_DPI_DEFAULT;
if( width < 1 || height < 1 || width > 0x10000 || height > 0x10000 )
{
if( piError )
*piError = HB_BMP_ERROR_SIZE;
}
else
{
int rowlen;
switch( depth )
{
case 0:
depth = HB_BMP_DEPTH_DEFAULT;
/* fallthrough */
case 1:
/* 2 color depth BMP is not officially supported,
uncomment line below if you need it */
/* case 2: */
case 4:
case 8:
case 16:
case 24:
case 32:
break;
default:
if( piError )
*piError = HB_BMP_ERROR_DEPTH;
return NULL;
}
pBMP = ( PHB_BMPINFO ) hb_xgrabz( sizeof( HB_BMPINFO ) );
rowlen = ( ( width * depth + 31 ) >> 5 ) << 2;
pBMP->error = 0;
pBMP->width = width;
pBMP->height = height;
pBMP->dpi = dpi;
pBMP->depth = depth;
pBMP->clrused = 0;
pBMP->rowlen = rowlen;
pBMP->fromtop = fromtop;
pBMP->data = ( HB_BYTE * ) hb_xgrabz( rowlen * height );
}
return pBMP;
}
PHB_BMPINFO hb_bmp_copy( PHB_BMPINFO pBMP )
{
PHB_BMPINFO pBMPnew = ( PHB_BMPINFO ) hb_xgrab( sizeof( HB_BMPINFO ) );
memcpy( pBMPnew, pBMP, sizeof( HB_BMPINFO ) );
pBMPnew->data = ( HB_BYTE * ) hb_xgrab( pBMP->rowlen * pBMP->height );
memcpy( pBMPnew->data, pBMP->data, pBMP->rowlen * pBMP->height );
pBMPnew->error = 0;
return pBMPnew;
}
HB_BYTE * hb_bmp_bitmapptr( PHB_BMPINFO pBMP, HB_SIZE * pnSize )
{
if( pnSize )
*pnSize = pBMP->rowlen * pBMP->height;
return pBMP->data;
}
void hb_bmp_seterror( PHB_BMPINFO pBMP, int error )
{
pBMP->error = error;
}
int hb_bmp_error( PHB_BMPINFO pBMP )
{
return pBMP->error;
}
int hb_bmp_width( PHB_BMPINFO pBMP )
{
return pBMP->width;
}
int hb_bmp_height( PHB_BMPINFO pBMP )
{
return pBMP->height;
}
int hb_bmp_depth( PHB_BMPINFO pBMP )
{
return pBMP->depth;
}
HB_MAXINT hb_bmp_color( PHB_BMPINFO pBMP, int r, int g, int b, int a )
{
HB_MAXINT iColor = -1;
pBMP->error = 0;
if( ( r & 0xFF ) != r || ( g & 0xFF ) != g ||
( b & 0xFF ) != b || ( a & 0xFF ) != a )
pBMP->error = HB_BMP_ERROR_COLORVALUE;
else if( pBMP->depth == 32 )
iColor = b | ( g << 8 ) | ( r << 16 ) | ( a << 24 );
else if( pBMP->depth == 24 )
iColor = b | ( g << 8 ) | ( r << 16 );
/* 16 color depth does not have RGB mapping in BMP format
* color indexes have to be used directly and their RGB
* values defined outside BMP structure
*/
else if( pBMP->depth <= 8 )
{
int i;
for( i = 0; i < pBMP->clrused; ++i )
{
if( pBMP->palette[ i ].blue == b &&
pBMP->palette[ i ].green == g &&
pBMP->palette[ i ].red == r &&
pBMP->palette[ i ].alpha == a )
{
iColor = i;
break;
}
}
if( iColor == -1 )
{
if( pBMP->clrused < 1 << pBMP->depth )
{
iColor = pBMP->clrused++;
pBMP->palette[ iColor ].blue = b;
pBMP->palette[ iColor ].green = g;
pBMP->palette[ iColor ].red = r;
pBMP->palette[ iColor ].alpha = a;
}
else
pBMP->error = HB_BMP_ERROR_PALETTEFULL;
}
}
else
pBMP->error = HB_BMP_ERROR_COLORINDEX;
return iColor;
}
HB_BOOL hb_bmp_color2rgb( PHB_BMPINFO pBMP, HB_MAXINT clr, int * r, int * g, int * b, int * a )
{
pBMP->error = HB_BMP_ERROR_COLORINDEX;
* b = * g = * r = * a = -1;
if( clr >= 0 && clr <= HB_LL( 0xFFFFFFFF ) )
{
switch( pBMP->depth )
{
case 1:
case 2:
case 4:
case 8:
if( clr < ( HB_MAXINT ) pBMP->clrused )
{
* b = pBMP->palette[ clr ].blue;
* g = pBMP->palette[ clr ].green;
* r = pBMP->palette[ clr ].red;
* a = pBMP->palette[ clr ].alpha;
pBMP->error = 0;
}
break;
/* 16 color depth does not have RGB mapping in BMP format
* color indexes have to be used directly and their RGB
* values defined outside BMP structure
*/
case 24:
/* ignore alpha channel */
clr &= 0xFFFFFF;
/* fallthrough */
case 32:
* b = clr & 0xFF;
* g = ( clr >> 8 ) & 0xFF;
* r = ( clr >> 16 ) & 0xFF;
* a = ( clr >> 24 ) & 0xFF;
pBMP->error = 0;
break;
}
}
return pBMP->error == 0;
}
HB_BOOL hb_bmp_putpixel( PHB_BMPINFO pBMP, int x, int y, HB_MAXINT clr )
{
if( x < 0 || x >= pBMP->width || y < 0 || y >= pBMP->height )
pBMP->error = HB_BMP_ERROR_RANGE;
else if( clr < 0 || ( clr > ( pBMP->depth <= 8 ? pBMP->clrused :
( pBMP->depth == 16 ? 0xFFFF :
HB_LL( 0xFFFFFFFF ) ) ) ) )
pBMP->error = HB_BMP_ERROR_COLORINDEX;
else
{
int index = ( ( ( pBMP->fromtop ? y : pBMP->height - y - 1 ) *
pBMP->rowlen ) << 3 ) + ( x * pBMP->depth );
HB_BYTE * ptr = &pBMP->data[ index >> 3 ];
int shift = -1;
switch( pBMP->depth )
{
case 1:
shift = 0x07 ^ ( x & 0x07 );
break;
case 2:
shift = ( 0x03 ^ ( x & 0x03 ) ) << 1;
break;
case 4:
shift = ( 0x01 ^ ( x & 0x01 ) ) << 2;
break;
case 8:
*ptr = ( HB_BYTE ) clr;
break;
case 16:
HB_PUT_LE_UINT16( ptr, clr );
break;
case 24:
HB_PUT_LE_UINT24( ptr, clr );
break;
case 32:
HB_PUT_LE_UINT32( ptr, clr );
break;
}
if( shift >= 0 )
*ptr = ( HB_BYTE ) ( ( *ptr & ~( ( ( 0x01 << pBMP->depth ) - 1 ) << shift ) ) | ( clr << shift ) );
pBMP->error = 0;
}
return pBMP->error == 0;
}
HB_MAXINT hb_bmp_getpixel( PHB_BMPINFO pBMP, int x, int y )
{
HB_MAXINT clr = -1;
if( x < 0 || x >= pBMP->width || y < 0 || y >= pBMP->height )
pBMP->error = HB_BMP_ERROR_RANGE;
else
{
int index = ( ( ( pBMP->fromtop ? y : pBMP->height - y - 1 ) *
pBMP->rowlen ) << 3 ) + ( x * pBMP->depth );
HB_BYTE * ptr = &pBMP->data[ index >> 3 ];
int shift = -1;
switch( pBMP->depth )
{
case 1:
shift = 0x07 ^ ( x & 0x07 );
break;
case 2:
shift = ( 0x03 ^ ( x & 0x03 ) ) << 1;
break;
case 4:
shift = ( 0x01 ^ ( x & 0x01 ) ) << 2;
break;
case 8:
clr = *ptr;
break;
case 16:
clr = HB_GET_LE_UINT16( ptr );
break;
case 24:
clr = HB_GET_LE_UINT24( ptr );
break;
case 32:
clr = HB_GET_LE_UINT32( ptr );
break;
}
if( shift >= 0 )
clr = ( *ptr & ( ( ( 0x01 << pBMP->depth ) - 1 ) << shift ) ) >> shift;
pBMP->error = 0;
}
return clr;
}
void hb_bmp_line( PHB_BMPINFO pBMP, int x1, int y1, int x2, int y2, HB_MAXINT clr )
{
if( clr < 0 || ( clr > ( pBMP->depth <= 8 ? pBMP->clrused :
( pBMP->depth == 16 ? 0xFFFF :
HB_LL( 0xFFFFFFFF ) ) ) ) )
pBMP->error = HB_BMP_ERROR_COLORINDEX;
else
{
double dd;
int dx, dy, x, y;
dx = x1 >= x2 ? x1 - x2 : x2 - x1;
dy = y1 >= y2 ? y1 - y2 : y2 - y1;
if( dx >= dy || dy == 0 ? x1 > x2 : y1 > y2 || dx == 0 )
{
int nn = x1;
x1 = x2;
x2 = nn;
nn = y1;
y1 = y2;
y2 = nn;
}
if( dy == 0 )
{
for( x = HB_MAX( x1, 0 ); x <= x2 && x < pBMP->width; ++x )
hb_bmp_putpixel( pBMP, x, y1, clr );
}
else if( dx == 0 )
{
for( y = HB_MAX( y1, 0 ); y <= y2 && y < pBMP->height; ++y )
hb_bmp_putpixel( pBMP, x1, y, clr );
}
else if( dx >= dy )
{
dd = ( double ) ( y2 - y1 ) / ( x2 - x1 );
for( x = HB_MAX( x1, 0 ); x <= x2 && x < pBMP->width; ++x )
hb_bmp_putpixel( pBMP, x, ( int ) ( dd * ( x - x1 ) + 0.50001 ) + y1, clr );
}
else
{
dd = ( double ) ( x2 - x1 ) / ( y2 - y1 );
for( y = HB_MAX( y1, 0 ); y <= y2 && y < pBMP->height; ++y )
hb_bmp_putpixel( pBMP, ( int ) ( dd * ( y - y1 ) + 0.50001 ) + x1, y, clr );
}
pBMP->error = 0;
}
}
void hb_bmp_rect( PHB_BMPINFO pBMP, int x, int y, int width, int height, HB_MAXINT clr, HB_BOOL fFill )
{
if( width < 0 )
{
x += width;
width = - width;
}
if( height < 0 )
{
y += height;
height = - height;
}
if( clr < 0 || ( clr > ( pBMP->depth <= 8 ? pBMP->clrused :
( pBMP->depth == 16 ? 0xFFFF :
HB_LL( 0xFFFFFFFF ) ) ) ) )
pBMP->error = HB_BMP_ERROR_COLORINDEX;
else if( width < 0 || height < 0 ||
x >= pBMP->width || y >= pBMP->height ||
x + width < 0 || y + height < 0 )
pBMP->error = HB_BMP_ERROR_RANGE;
else
{
int x1, y1, x2, y2, xx, yy;
x1 = HB_MAX( x, 0 );
y1 = HB_MAX( y, 0 );
x2 = x1 + width >= pBMP->width ? pBMP->width : x1 + width;
y2 = y1 + height >= pBMP->height ? pBMP->height : y1 + height;
if( fFill )
{
for( xx = x1; xx < x2; ++xx )
{
for( yy = y1; yy < y2; ++yy )
hb_bmp_putpixel( pBMP, xx, yy, clr );
}
}
else
{
if( y >= 0 )
{
for( xx = x1; xx < x2; ++xx )
hb_bmp_putpixel( pBMP, xx, y, clr );
}
if( x >= 0 )
{
for( yy = y1; yy < y2; ++yy )
hb_bmp_putpixel( pBMP, x, yy, clr );
}
if( y2 < pBMP->height )
{
for( xx = x1; xx < x2; ++xx )
hb_bmp_putpixel( pBMP, xx, y2 - 1, clr );
}
if( x2 < pBMP->width )
{
for( yy = y1; yy < y2; ++yy )
hb_bmp_putpixel( pBMP, x2 - 1, yy, clr );
}
}
pBMP->error = 0;
}
}
PHB_BMPINFO hb_bmp_decode( const HB_BYTE * data, HB_SIZE size, int * piError )
{
PHB_BMPINFO pBMP = NULL;
int iError = 0;
if( ! data || size < HB_BMP_FILEHEADER_SIZE + HB_BMP_INFOHEADER_MINSIZE )
iError = HB_BMP_ERROR_CORRUPT;
else
{
PHB_BMPHEADER header = ( PHB_BMPHEADER ) data;
if( header->signature[ 0 ] != 'B' || header->signature[ 1 ] != 'M' )
iError = HB_BMP_ERROR_CORRUPT;
else
{
/* file_size in BMP headers is often wrong so I do not check it
* int file_size = HB_GET_LE_INT32( header->file_size );
*/
int bmpoffset = HB_GET_LE_INT32( header->bmpoffset ),
headersize = HB_GET_LE_INT32( header->headersize ),
width = 0, height = 0, depth = 0, rowlen = 0, dpi = 0,
clrused = 0, palette_bytes = 0;
HB_BOOL fromtop;
if( size < ( HB_SIZE ) ( HB_BMP_FILEHEADER_SIZE +
HB_BMP_INFOHEADER_MINSIZE + headersize ) )
iError = HB_BMP_ERROR_CORRUPT;
else if( headersize == 12 || headersize == 16 )
{
PHB_BMPOS2HEADER header_os2 = ( PHB_BMPOS2HEADER ) header->file_size;
width = HB_GET_LE_UINT16( header_os2->width );
height = HB_GET_LE_UINT16( header_os2->height );
depth = HB_GET_LE_UINT16( header_os2->bitsperpixel );
if( depth <= 8 )
clrused = 0x01 << depth;
dpi = HB_BMP_DPI_DEFAULT;
palette_bytes = 3;
if( depth != 1 && depth != 2 && depth != 4 && depth != 8 && depth != 24 )
iError = HB_BMP_ERROR_CORRUPT;
}
else if( headersize == 40 || headersize == 52 || headersize == 56 ||
headersize == 108 || headersize == 124 )
{
width = HB_GET_LE_INT32( header->width );
height = HB_GET_LE_INT32( header->height );
dpi = ( int ) ( ( double ) HB_GET_LE_INT32( header->hresolution ) / 39.3701 + 0.5 );
depth = HB_GET_LE_UINT16( header->bitsperpixel );
if( depth <= 8 )
{
clrused = HB_GET_LE_INT32( header->clrused );
if( clrused == 0 )
clrused = 0x01 << depth;
}
palette_bytes = 4;
if( ( depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
depth != 16 && depth != 24 && depth != 32 ) )
iError = HB_BMP_ERROR_CORRUPT;
else if( HB_GET_LE_INT32( header->compression ) != 0 )
iError = HB_BMP_ERROR_UNSUPPORTED;
}
else
iError = HB_BMP_ERROR_CORRUPT;
fromtop = height < 0;
if( fromtop )
height = -height;
rowlen = ( ( width * depth + 31 ) >> 5 ) << 2;
if( iError == 0 &&
( HB_BMP_FILEHEADER_SIZE + headersize + clrused * palette_bytes > bmpoffset ||
( HB_SIZE ) bmpoffset + rowlen * height > size ) )
iError = HB_BMP_ERROR_CORRUPT;
else if( iError == 0 )
{
pBMP = hb_bmp_new( width, fromtop ? -height : height, depth, dpi, &iError );
if( pBMP )
{
const HB_BYTE * ptr = data + HB_BMP_FILEHEADER_SIZE + headersize;
int idx, unused = 0;
for( idx = 0; idx < clrused; ++idx )
{
pBMP->palette[ idx ].blue = *ptr++;
pBMP->palette[ idx ].green = *ptr++;
pBMP->palette[ idx ].red = *ptr++;
if( palette_bytes == 4 )
pBMP->palette[ idx ].alpha = *ptr++;
if( pBMP->palette[ idx ].blue == 0 &&
pBMP->palette[ idx ].green == 0 &&
pBMP->palette[ idx ].red == 0 &&
pBMP->palette[ idx ].alpha == 0 )
++unused;
else if( unused > 1 )
unused = 1;
}
if( unused > 1 )
clrused -= unused - 1;
pBMP->clrused = clrused;
memcpy( pBMP->data, data + bmpoffset, rowlen * height );
}
}
}
}
if( piError )
*piError = iError;
return pBMP;
}
HB_BYTE * hb_bmp_encode( PHB_BMPINFO pBMP, HB_SIZE * pnSize )
{
int clrused, bmpoffset, bmpsize, file_size, idx, height, dpi;
PHB_BMPHEADER header;
HB_BYTE * data, * ptr;
/* always allocate area for whole palette for programs which
* do not check number of used colors in BMP header
*/
clrused = pBMP->depth > 8 ? 0 : 0x01 << pBMP->depth;
/* 4 byte alignment is not required inside file */
/* bmpoffset = ( sizeof( HB_BMPHEADER ) + clrused * 4 + 3 ) & ~0x03; */
bmpoffset = sizeof( HB_BMPHEADER ) + clrused * 4;
bmpsize = pBMP->rowlen * pBMP->height;
file_size = bmpoffset + bmpsize;
height = pBMP->fromtop ? -pBMP->height : pBMP->height;
dpi = ( int ) ( HB_BMP_INCHES_PER_METRE * pBMP->dpi + 0.5 );
/* when clrused is set in BMP header to value different then 0 or
* palette size some BMP viewers cannot show BMP correctly so
* I decided to comment code below and always store 0
*/
/*
if( clrused > 0 )
clrused = clrused > pBMP->clrused ? pBMP->clrused : 0;
*/
clrused = 0;
data = ( HB_BYTE * ) hb_xgrab( file_size + 1 );
memset( data, 0, sizeof( HB_BMPHEADER ) );
header = ( PHB_BMPHEADER ) data;
header->signature[ 0 ] = 'B';
header->signature[ 1 ] = 'M';
HB_PUT_LE_UINT32( header->file_size, file_size );
HB_PUT_LE_UINT16( header->reserved1, 0 );
HB_PUT_LE_UINT16( header->reserved2, 0 );
HB_PUT_LE_UINT32( header->bmpoffset, bmpoffset );
HB_PUT_LE_UINT32( header->headersize, sizeof( HB_BMPHEADER ) - HB_BMP_FILEHEADER_SIZE );
HB_PUT_LE_UINT32( header->width, pBMP->width );
HB_PUT_LE_UINT32( header->height, height );
HB_PUT_LE_UINT16( header->planes, 1 );
HB_PUT_LE_UINT16( header->bitsperpixel, pBMP->depth );
HB_PUT_LE_UINT32( header->compression, 0 );
HB_PUT_LE_UINT32( header->bitmapsize, bmpsize );
HB_PUT_LE_UINT32( header->hresolution, dpi );
HB_PUT_LE_UINT32( header->vresolution, dpi );
HB_PUT_LE_UINT32( header->clrused, clrused );
HB_PUT_LE_UINT32( header->clrimportant, 0 );
ptr = data + sizeof( HB_BMPHEADER );
for( idx = 0; idx < pBMP->clrused; ++idx )
{
*ptr++ = pBMP->palette[ idx ].blue;
*ptr++ = pBMP->palette[ idx ].green;
*ptr++ = pBMP->palette[ idx ].red;
*ptr++ = pBMP->palette[ idx ].alpha;
}
while( ptr < data + bmpoffset )
*ptr++ = 0;
memcpy( data + bmpoffset, pBMP->data, pBMP->rowlen * pBMP->height );
data[ file_size ] = 0;
*pnSize = file_size;
pBMP->error = 0;
return data;
}
/* Collectable pointer support */
static HB_GARBAGE_FUNC( hb_bmp_destructor )
{
PHB_BMPINFO * pBMPptr = ( PHB_BMPINFO * ) Cargo;
if( *pBMPptr )
{
hb_bmp_free( *pBMPptr );
*pBMPptr = NULL;
}
}
static const HB_GC_FUNCS s_gcBMPfuncs =
{
hb_bmp_destructor,
hb_gcDummyMark
};
void hb_bmpParamFree( int iParam )
{
PHB_BMPINFO * pBMPPtr = ( PHB_BMPINFO * ) hb_parptrGC( &s_gcBMPfuncs, iParam );
if( pBMPPtr && *pBMPPtr )
{
hb_bmp_free( *pBMPPtr );
*pBMPPtr = NULL;
}
}
PHB_BMPINFO hb_bmpParam( int iParam, HB_BOOL fError )
{
PHB_BMPINFO * pBMPPtr = ( PHB_BMPINFO * ) hb_parptrGC( &s_gcBMPfuncs, iParam );
if( pBMPPtr && *pBMPPtr )
return *pBMPPtr;
else if( fError )
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
return NULL;
}
void hb_bmpReturn( PHB_BMPINFO pBMP )
{
if( pBMP )
{
PHB_BMPINFO * pBMPPtr = ( PHB_BMPINFO * )
hb_gcAllocate( sizeof( PHB_BMPINFO ), &s_gcBMPfuncs );
*pBMPPtr = pBMP;
hb_retptrGC( pBMPPtr );
}
else
hb_ret();
}
/* PRG functions */
HB_FUNC( HB_BMP_NEW )
{
int iError = 0;
PHB_BMPINFO pBMP = hb_bmp_new( hb_parni( 1 ), hb_parni( 2 ),
hb_parnidef( 3, 1 ),
hb_parnidef( 4, HB_BMP_DPI_DEFAULT ),
&iError );
hb_storni( iError, 5 );
hb_bmpReturn( pBMP );
}
HB_FUNC( HB_BMP_COPY )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
pBMP = hb_bmp_copy( pBMP );
hb_bmpReturn( pBMP );
}
HB_FUNC( HB_BMP_DECODE )
{
const char * data = hb_parc( 1 );
if( data )
{
int iError = 0;
PHB_BMPINFO pBMP = hb_bmp_decode( ( const HB_BYTE * ) data, hb_parclen( 1 ), &iError );
hb_storni( iError, 2 );
hb_bmpReturn( pBMP );
}
else
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( HB_BMP_ENCODE )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
{
HB_SIZE size;
HB_BYTE * data = hb_bmp_encode( pBMP, &size );
hb_retclen_buffer( ( char * ) data, size );
}
}
HB_FUNC( HB_BMP_FREE )
{
hb_bmpParamFree( 1 );
}
HB_FUNC( HB_BMP_ERROR )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_retni( hb_bmp_error( pBMP ) );
}
HB_FUNC( HB_BMP_WIDTH )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_retni( hb_bmp_width( pBMP ) );
}
HB_FUNC( HB_BMP_HEIGHT )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_retni( hb_bmp_height( pBMP ) );
}
HB_FUNC( HB_BMP_DEPTH )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_retni( hb_bmp_depth( pBMP ) );
}
HB_FUNC( HB_BMP_COLOR )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_retnint( hb_bmp_color( pBMP, hb_parni( 2 ), hb_parni( 3 ), hb_parni( 4 ), hb_parni( 5 ) ) );
}
HB_FUNC( HB_BMP_COLOR2RGB )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
{
int r, g, b, a;
hb_retl( hb_bmp_color2rgb( pBMP, hb_parnint( 2 ), &r, &g, &b, &a ) );
hb_storni( r, 3 );
hb_storni( g, 4 );
hb_storni( b, 5 );
hb_storni( a, 6 );
}
}
HB_FUNC( HB_BMP_PUTPIXEL )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_retl( hb_bmp_putpixel( pBMP, hb_parni( 2 ), hb_parni( hb_parni( 3 ) ), hb_parnint( 4 ) ) );
}
HB_FUNC( HB_BMP_GETPIXEL )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_retnint( hb_bmp_getpixel( pBMP, hb_parni( 2 ), hb_parni( hb_parni( 3 ) ) ) );
}
HB_FUNC( HB_BMP_LINE )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_bmp_line( pBMP, hb_parni( 2 ), hb_parni( 3 ), hb_parni( 4 ), hb_parni( 5 ), hb_parnint( 6 ) );
}
HB_FUNC( HB_BMP_RECT )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
hb_bmp_rect( pBMP, hb_parni( 2 ), hb_parni( 3 ), hb_parni( 4 ), hb_parni( 5 ), hb_parnint( 6 ), hb_parldef( 7, HB_TRUE ) );
}
HB_FUNC( HB_BMP_LOAD )
{
const char * pszFileName = hb_parc( 1 );
if( pszFileName )
{
int iError = 0;
HB_SIZE size;
HB_BYTE * data = hb_fileLoad( pszFileName, 0x1000000, &size );
if( data )
{
PHB_BMPINFO pBMP = hb_bmp_decode( data, size, &iError );
hb_bmpReturn( pBMP );
hb_xfree( data );
}
else
iError = HB_BMP_ERROR_FILEREAD;
hb_storni( iError, 2 );
}
else
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( HB_BMP_SAVE )
{
PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE );
if( pBMP )
{
const char * pszFileName = hb_parc( 2 );
if( pszFileName )
{
HB_SIZE size;
HB_BYTE * data = hb_bmp_encode( pBMP, &size );
HB_BOOL fResult = hb_fileSave( pszFileName, data, size );
if( ! fResult )
hb_bmp_seterror( pBMP, HB_BMP_ERROR_FILEWRITE );
hb_retl( fResult );
hb_xfree( data );
}
else
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
}

63
contrib/hbbmp/hbbmp.ch Normal file
View File

@@ -0,0 +1,63 @@
/*
* BMP image library for Harbour
*
* Copyright 2025 Przemyslaw Czerpak <druzus /at/ priv.onet.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
/* NOTE: This file is also used by C code. */
#ifndef _HBBMP_CH_
#define _HBBMP_CH_
#define HB_BMP_ERROR_SIZE 1
#define HB_BMP_ERROR_DEPTH 2
#define HB_BMP_ERROR_COLORVALUE 3
#define HB_BMP_ERROR_PALETTEFULL 4
#define HB_BMP_ERROR_COLORINDEX 5
#define HB_BMP_ERROR_RANGE 6
#define HB_BMP_ERROR_CORRUPT 7
#define HB_BMP_ERROR_UNSUPPORTED 8
#define HB_BMP_ERROR_FILEREAD 9
#define HB_BMP_ERROR_FILEWRITE 10
#endif /* _HBBMP_CH_ */

138
contrib/hbbmp/hbbmp.h Normal file
View File

@@ -0,0 +1,138 @@
/*
* BMP image library for Harbour
*
* Copyright 2025 Przemyslaw Czerpak <druzus /at/ priv.onet.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file LICENSE.txt. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#ifndef _HBBMP_H_
#define _HBBMP_H_
#include "hbdefs.h"
#include "hbbmp.ch"
HB_EXTERN_BEGIN
#define HB_BMP_DEPTH_DEFAULT 1
#define HB_BMP_DPI_DEFAULT 72
#define HB_BMP_INCHES_PER_METRE 39.3701
#define HB_BMP_FILEHEADER_SIZE 14
#define HB_BMP_INFOHEADER_MINSIZE 12
typedef struct _HB_BMPHEADER
{
HB_BYTE signature [ 2 ]; /* "BM" */
HB_BYTE file_size [ 4 ]; /* the size of the BMP file in bytes */
HB_BYTE reserved1 [ 2 ]; /* reserved, depends on the application, if created manually can be 0 */
HB_BYTE reserved2 [ 2 ]; /* reserved, depends on the application, if created manually can be 0 */
HB_BYTE bmpoffset [ 4 ]; /* the offset of the byte where the bitmap image data (pixel array) can be found */
HB_BYTE headersize [ 4 ]; /* the size of this header, in bytes (40) */
HB_BYTE width [ 4 ]; /* the bitmap width in pixels (signed integer) */
HB_BYTE height [ 4 ]; /* the bitmap height in pixels (signed integer) */
HB_BYTE planes [ 2 ]; /* the number of color planes (must be 1) */
HB_BYTE bitsperpixel[ 2 ]; /* the number of bits per pixel (color depth): 1, 4, 8, 16, 24 or 32 */
HB_BYTE compression [ 4 ]; /* the compression method, 0 uncompressed */
HB_BYTE bitmapsize [ 4 ]; /* the image size (the size of the raw bitmap data), 0 can be used for uncompressed bitmaps */
HB_BYTE hresolution [ 4 ]; /* the horizontal resolution of the image (pixel per metre, signed integer) */
HB_BYTE vresolution [ 4 ]; /* the vertical resolution of the image (pixel per metre, signed integer) */
HB_BYTE clrused [ 4 ]; /* the number of colors in the color palette, or 0 to default to 2^n */
HB_BYTE clrimportant[ 4 ]; /* the number of important colors used, or 0 when every color is important; generally ignored */
} HB_BMPHEADER, * PHB_BMPHEADER;
typedef struct _HB_BMPOS2HEADER
{
HB_BYTE headersize [ 4 ]; /* the size of this header, in bytes (12) */
HB_BYTE width [ 2 ]; /* the bitmap width in pixels (signed integer) */
HB_BYTE height [ 2 ]; /* the bitmap height in pixels (signed integer) */
HB_BYTE planes [ 2 ]; /* the number of color planes (must be 1) */
HB_BYTE bitsperpixel[ 2 ]; /* the number of bits per pixel (color depth): 1, 4, 8, 16, 24 or 32 */
} HB_BMPOS2HEADER, * PHB_BMPOS2HEADER;
typedef struct _HB_BMPPALETTEITM
{
HB_BYTE blue;
HB_BYTE green;
HB_BYTE red;
HB_BYTE alpha;
} HB_BMPPALETTEITM, * PHB_BMPPALETTEITM;
typedef struct _HB_BMPINFO
{
int error;
int width;
int height;
int rowlen;
HB_BOOL fromtop;
int dpi;
int depth;
int clrused;
HB_BMPPALETTEITM palette[ 256 ];
HB_BYTE* data;
} HB_BMPINFO, * PHB_BMPINFO;
extern HB_EXPORT PHB_BMPINFO hb_bmp_new( int width, int height, int depth, int dpi, int * piError );
extern HB_EXPORT PHB_BMPINFO hb_bmp_copy( PHB_BMPINFO pBMP );
extern HB_EXPORT PHB_BMPINFO hb_bmp_decode( const HB_BYTE * data, HB_SIZE size, int * piError );
extern HB_EXPORT HB_BYTE * hb_bmp_encode( PHB_BMPINFO pBMP, HB_SIZE * pnSsize );
extern HB_EXPORT void hb_bmp_free( PHB_BMPINFO pBMP );
extern HB_EXPORT HB_BYTE * hb_bmp_bitmapptr( PHB_BMPINFO pBMP, HB_SIZE * pnSize );
extern HB_EXPORT void hb_bmp_seterror( PHB_BMPINFO pBMP, int error );
extern HB_EXPORT int hb_bmp_error( PHB_BMPINFO pBMP );
extern HB_EXPORT int hb_bmp_width( PHB_BMPINFO pBMP );
extern HB_EXPORT int hb_bmp_height( PHB_BMPINFO pBMP );
extern HB_EXPORT int hb_bmp_depth( PHB_BMPINFO pBMP );
extern HB_EXPORT HB_MAXINT hb_bmp_color( PHB_BMPINFO pBMP, int r, int g, int b, int a );
extern HB_EXPORT HB_BOOL hb_bmp_color2rgb( PHB_BMPINFO pBMP, HB_MAXINT clr, int * r, int * g, int * b, int * a );
extern HB_EXPORT HB_BOOL hb_bmp_putpixel( PHB_BMPINFO pBMP, int x, int y, HB_MAXINT clr );
extern HB_EXPORT HB_MAXINT hb_bmp_getpixel( PHB_BMPINFO pBMP, int x, int y );
extern HB_EXPORT void hb_bmp_line( PHB_BMPINFO pBMP, int x1, int y1, int x2, int y2, HB_MAXINT clr );
extern HB_EXPORT void hb_bmp_rect( PHB_BMPINFO pBMP, int x, int y, int width, int height, HB_MAXINT clr, HB_BOOL fFill );
extern HB_EXPORT PHB_BMPINFO hb_bmpParam( int iParam, HB_BOOL fError );
extern HB_EXPORT void hb_bmpParamFree( int iParam );
extern HB_EXPORT void hb_bmpReturn( PHB_BMPINFO pBMP );
HB_EXTERN_END
#endif /* _HBBMP_H_ */

5
contrib/hbbmp/hbbmp.hbc Normal file
View File

@@ -0,0 +1,5 @@
description=BMP image library for Harbour
incpaths=.
libs=${hb_name}

10
contrib/hbbmp/hbbmp.hbp Normal file
View File

@@ -0,0 +1,10 @@
-hblib
-inc
-o${hb_name}
-w3 -es2
${hb_name}.hbx
core.c

46
contrib/hbbmp/hbbmp.hbx Normal file
View File

@@ -0,0 +1,46 @@
/* --------------------------------------------------------------------
* NOTE: You can add manual override which functions to include or
* exclude from automatically generated EXTERNAL/DYNAMIC list.
* Syntax: // HB_FUNC_INCLUDE <func>
* // HB_FUNC_EXCLUDE <func>
*/
/* --------------------------------------------------------------------
* WARNING: Automatically generated code below. DO NOT EDIT! (except casing)
* Regenerate using hbmk2 '-hbx=' option.
*/
#ifndef __HBEXTERN_CH__HBBMP__
#define __HBEXTERN_CH__HBBMP__
#if defined( __HBEXTREQ__ ) .OR. defined( __HBEXTERN__HBBMP__ANNOUNCE )
ANNOUNCE __HBEXTERN__HBBMP__
#endif
#if defined( __HBEXTREQ__ ) .OR. defined( __HBEXTERN__HBBMP__REQUEST )
#command DYNAMIC <fncs,...> => EXTERNAL <fncs>
#endif
DYNAMIC hb_bmp_color
DYNAMIC hb_bmp_color2rgb
DYNAMIC hb_bmp_copy
DYNAMIC hb_bmp_decode
DYNAMIC hb_bmp_depth
DYNAMIC hb_bmp_encode
DYNAMIC HB_BMP_ERROR
DYNAMIC hb_bmp_free
DYNAMIC hb_bmp_getpixel
DYNAMIC hb_bmp_height
DYNAMIC hb_bmp_line
DYNAMIC hb_bmp_load
DYNAMIC hb_bmp_new
DYNAMIC hb_bmp_putpixel
DYNAMIC hb_bmp_rect
DYNAMIC hb_bmp_save
DYNAMIC hb_bmp_width
#if defined( __HBEXTREQ__ ) .OR. defined( __HBEXTERN__HBBMP__REQUEST )
#uncommand DYNAMIC <fncs,...> => EXTERNAL <fncs>
#endif
#endif

110
contrib/hbbmp/readme.txt Normal file
View File

@@ -0,0 +1,110 @@
Copyright 2025 Przemyslaw Czerpak <druzus /at/ priv.onet.pl>
HBBMP is small library for Harbour dedicated to create and modify
BMP images. It has not any 3rd party libs dependencies.
It allows to create new images load existing ones and draw
simple graphics primitives. I did not implement more advanced
ones to not create math lib dependencies.
Anyhow if someone is interesting in it then please implement it.
For me this library is enough to work as backend for HBZEBRA
library (excellent job of Mindaugas Kavaliauskas).
I hope you will find it useful.
Only uncompressed BMP images are supported. When BMP file with
compression flag is loaded then UNSUPPORTED error is set. This
is the only case when this error can appear.
This library can work images using 1, 4, 8, 16, 24 and 32 color
depth (all officially defined). It can work with 2-bit color depth
(4 colors) BMP images which are not supported in official
documentation. I blocked them inside hb_bmp_new() C function but
if someone needs to create such BMP file then it's enough to
uncomment one line with "case 2:" in this code.
In BMP images with 1, 4 and 8 color depths number of colors is
limited to 2, 16 and 256 colors. If limit exceeds or unsupported
colors are defined then -1 is returned and error is set.
In BMP images with 24 color depth alpha channel does not exists
and this library silently ignores it when user pass it in color
index.
BMP images with 16-bit color depth does not have RGB color table
so only arbitrary color indexes can be used and their real colors
necessary for visualization have to be defined outside BMP file.
BMP images color depth 24 and 32 do not use color table and color
indexes are pure big endian RGB values with optional alpha channel
which is ignored in case of 24 bit depth (0xAARRGGBB) so it's not
necessary to allocate colors and programmer may use it directly,
i.e. red := 0xFF0000
The color and alpha must be in range from 0 to 255.
When new BMP is created user can change the order in which rows
are stored in memory and files from bottom-up to top-down setting
the image height to negative value.
On PRG level the BMP image structure is represented as pointer
item with attached destructor so when last variable (Harbour
item) pointing to given BMP structure is cleared or overwritten
(f.e. by pBMP := NIL) then destructor is called and BMP image
structure removed from memory. Anyhow it's possible to force
release operation by explicit call to hb_bmp_free().
The following PRG functions exist in HBBMP lib:
Create new BMP in memory, return pointer item or NIL on error.
hb_bmp_new( <nWidth>, <nHeight>, [<nDepth>=1], [<nDPI>=72], [@<nError>] )
=> <pBMP> | NIL (error indicator)
Make independent copy of memory BMP structures:
hb_bmp_copy( <pBMPsrc> ) => <pBMPcopy>
Free BMP structure from memory:
hb_bmp_free( <pBMP> ) => NIL
Load BMP image from file, return pointer item BMP image structure
or NIL on error:
hb_bmp_load( <cFileName>, [@<nError>] ) => <pBMP> | NIL
Save BMP image into file:
hb_bmp_save( <pBMP>, <cFileName> ) => <lOK>
Create new BMP image structure from passed BMP file body, return
pointer item BMP structure or NIL on error:
hb_bmp_decode( <cBMPdata>, [@<nError>] ) => <pBMP> | NIL
Create BMP file body from BMP image structure:
hb_bmp_encode( <pBMP> ) => <cBMPdata>
Get BMP width:
hb_bmp_width( <pBMP> ) => <nWidth>
Get BMP height:
hb_bmp_height( <pBMP> ) => <nHeight>
Get BMP color depth:
hb_bmp_depth( <pBMP> ) => <nDepth>
Allocate new color or take index to existing one, or error -1
is returned:
hb_bmp_color( <pBMP>, <nRed>, <nGreen>, <nBlue>, <nAlpha> )
=> <nColor> | -1
Convert color index to its RGB value, return .T. on success or
.F. in case of error:
hb_bmp_color2rgb( <pBMP>, <nColor>,
@<nRed>, @<nGreen>, @<nBlue>, @<nAlpha> )
=> <lOK>
Set pixel using given coordinates and color index:
hb_bmp_putpixel( <pBMP>, <nX>, <nY>, <nColor> ) => <lOK>
Get color index of pixel at given coordinates, on error -1
is returned:
hb_bmp_getpixel( <pBMP>, <nX>, <nY> ) => <nColor>
Draw line from the given starting and ending points and color index:
hb_bmp_line( <pBMP>, <nX1>, <nY1>, <nX2>, <nY2>, <nColor> ) => NIL
Draw rectangle (filled by default) using given coordinates, size and
index color:
hb_bmp_rect( <pBMP>, <nX>, <nY>, <nWidth>, <nHeight>,
<nColor>, [<lFill>=.t.] ) => NIL

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2025 Przemyslaw Czerpak <druzus /at/ priv.onet.pl>
*/
#define WIDTH 240
#define HEIGHT 200
#xtranslate _out( <frm> [, <params,...>] ) => outstd( hb_strFormat( <frm>, <params> ) + hb_eol() )
#xtranslate _err( <frm> [, <params,...>] ) => outerr( hb_strFormat( <frm>, <params> ) + hb_eol() )
REQUEST HB_GT_CGI_DEFAULT
PROCEDURE Main()
LOCAL pBMP, depth, bkg, black, red, green, blue, last, fname, x1, x2, y1, y2, nn
FOR EACH depth IN { 1, 4, 8, 24, 32 }
IF Empty( pBMP := hb_bmp_new( WIDTH, HEIGHT, depth ) )
_err( "Cannot create BMP with DEPTH=%d", depth )
ELSE
_out( "Created BMP width=%d, height=%d, depth=%d", ;
hb_bmp_width( pBMP ), hb_bmp_height( pBMP ), hb_bmp_depth( pBMP ) )
bmp_color( pBMP, 255, 255, 255, 0, @bkg, @last )
bmp_color( pBMP, 0, 0, 0, 0, @black, @last )
bmp_color( pBMP, 127, 0, 0, 0, @red, @last )
bmp_color( pBMP, 0, 127, 0, 0, @green, @last )
bmp_color( pBMP, 0, 0, 127, 0, @blue, @last )
hb_bmp_rect( pBMP, 0, 0, WIDTH, HEIGHT, bkg )
hb_bmp_rect( pBMP, 1, 1, WIDTH - 2, HEIGHT - 2, black, .f. )
hb_bmp_rect( pBMP, 20, 20, WIDTH - 40, HEIGHT - 40, black )
hb_bmp_rect( pBMP, 30, 30, WIDTH - 60, HEIGHT - 60, bkg )
x1 := 40 ; y1 := 40 ; x2 := WIDTH - 40 ; y2 := HEIGHT - 40
hb_bmp_rect( pBMP, x1, y1, x2 - x1 + 1, y2 - y1 + 1, red, .f. )
hb_bmp_line( pBMP, x1, y1, x2, y2, blue )
hb_bmp_line( pBMP, x2, y1, x1, y2, green )
hb_bmp_line( pBMP, x1 + x1, y1, x2 - x1, y2, blue )
hb_bmp_line( pBMP, x2 - x1, y1, x1 + x1, y2, green )
FOR nn := 1 TO 5
hb_bmp_rect( pBMP, 20 * nn, 8, 12, 8, { green, blue, red, black, green }[ nn ] )
NEXT
fname := "test_" + strzero( depth, 2 ) + ".bmp"
bmp_save( pBMP, fname )
pBMP := NIL
ENDIF
_out( "" )
NEXT
RETURN
STATIC FUNCTION bmp_color( pBMP, r, g, b, a, /*@*/clr, /*@*/last )
LOCAL r2, g2, b2, a2
clr = hb_bmp_color( pBMP, r, g, b, a )
IF clr >= 0
last := clr
hb_bmp_color2rgb( pBMP, clr, @r2, @g2, @b2, @a2 )
_out( "Allocated color 0x%08x: r=%s, g=%s, b=%s, a=%s => r=%s, g=%s, b=%s, a=%s", clr, ;
hb_valToExp( r ), hb_valToExp( g ), hb_valToExp( b ), hb_valToExp( a ), ;
hb_valToExp( r2 ), hb_valToExp( g2 ), hb_valToExp( b2 ), hb_valToExp( a2 ) )
RETURN .T.
ELSE
clr := last
_err( "Cannot allocate color" )
ENDIF
RETURN .F.
STATIC FUNCTION bmp_save( pBMP, fname )
IF hb_bmp_save( pBMP, fname )
_out( "Created file: %s", fname )
RETURN .T.
ELSE
_err( "Cannot save file: %s", fname )
ENDIF
RETURN .F.

View File

@@ -0,0 +1,3 @@
hbbmp.hbc
-w3 -es2

View File

@@ -0,0 +1,106 @@
/*
* Copyright 2025 Przemyslaw Czerpak <druzus /at/ priv.onet.pl>
*/
#require "hbzebra"
#require "hbbmp"
#define WIDTH 1
REQUEST HB_GT_CGI_DEFAULT
PROCEDURE Main()
DrawBarcode( WIDTH, "EAN13", "477012345678" )
DrawBarcode( WIDTH, "EAN8", "1234567" )
DrawBarcode( WIDTH, "UPCA", "01234567891" )
DrawBarcode( WIDTH, "UPCE", "123456" )
DrawBarcode( WIDTH, "CODE39", "ABC123" )
DrawBarcode( WIDTH, "CODE39", "ABC123", HB_ZEBRA_FLAG_CHECKSUM + HB_ZEBRA_FLAG_WIDE3 )
DrawBarcode( WIDTH, "ITF", "12345678901", HB_ZEBRA_FLAG_CHECKSUM )
DrawBarcode( WIDTH, "MSI", "1234567", HB_ZEBRA_FLAG_CHECKSUM )
DrawBarcode( WIDTH, "CODABAR", "40156", HB_ZEBRA_FLAG_WIDE3 )
DrawBarcode( WIDTH, "CODE93", "ABC-123" )
DrawBarcode( WIDTH, "CODE11", "1234567890", HB_ZEBRA_FLAG_CHECKSUM + HB_ZEBRA_FLAG_WIDE3 )
DrawBarcode( WIDTH, "CODE128", "Code 128" )
DrawBarcode( WIDTH, "PDF417", "Hello, World of Harbour!!! It's 2D barcode PDF417 :)" )
DrawBarcode( WIDTH, "DATAMATRIX", "Hello, World of Harbour!!! It's 2D barcode DataMatrix :)" )
DrawBarcode( WIDTH, "QRCODE", "https://en.wikipedia.org/wiki/QR_Code" )
?
RETURN
STATIC PROCEDURE DrawBarcode( nLineWidth, cType, cCode, nFlags )
LOCAL hZebra, pBMP, nLineHeight, nX, nY, nWidth, nHeight, nDepth, nColor, cFile
SWITCH cType
CASE "EAN13" ; hZebra := hb_zebra_create_ean13( cCode, nFlags ) ; EXIT
CASE "EAN8" ; hZebra := hb_zebra_create_ean8( cCode, nFlags ) ; EXIT
CASE "UPCA" ; hZebra := hb_zebra_create_upca( cCode, nFlags ) ; EXIT
CASE "UPCE" ; hZebra := hb_zebra_create_upce( cCode, nFlags ) ; EXIT
CASE "CODE39" ; hZebra := hb_zebra_create_code39( cCode, nFlags ) ; EXIT
CASE "ITF" ; hZebra := hb_zebra_create_itf( cCode, nFlags ) ; EXIT
CASE "MSI" ; hZebra := hb_zebra_create_msi( cCode, nFlags ) ; EXIT
CASE "CODABAR" ; hZebra := hb_zebra_create_codabar( cCode, nFlags ) ; EXIT
CASE "CODE93" ; hZebra := hb_zebra_create_code93( cCode, nFlags ) ; EXIT
CASE "CODE11" ; hZebra := hb_zebra_create_code11( cCode, nFlags ) ; EXIT
CASE "CODE128" ; hZebra := hb_zebra_create_code128( cCode, nFlags ) ; EXIT
CASE "PDF417" ; hZebra := hb_zebra_create_pdf417( cCode, nFlags ); nLineHeight := nLineWidth * 3 ; EXIT
CASE "DATAMATRIX" ; hZebra := hb_zebra_create_datamatrix( cCode, nFlags ); nLineHeight := nLineWidth ; EXIT
CASE "QRCODE" ; hZebra := hb_zebra_create_qrcode( cCode, nFlags ); nLineHeight := nLineWidth ; EXIT
ENDSWITCH
IF hZebra != NIL
IF hb_zebra_geterror( hZebra ) == 0
IF nLineHeight == NIL
nLineHeight := nLineWidth * 36
ENDIF
nDepth := 1
/* get barcode size and add 1 pixel border over it */
hb_zebra_getsize( hZebra, @nWidth, @nHeight )
nX := 1
nY := 1
nWidth := nWidth * nLineWidth + 2
nHeight := nHeight * nLineHeight + 2
? cType, "code width", hb_ntos( nWidth ), "height", hb_ntos( nHeight )
IF Empty( pBMP := hb_bmp_new( nWidth, nHeight, nDepth ) )
? "Cannot create BMP image"
ELSE
/* allocate white color (RGB) and use it to fill the background */
nColor := hb_bmp_color( pBMP, 255, 255, 255 )
hb_bmp_rect( pBMP, 0, 0, nWidth, nHeight, nColor )
/* allocate black color for barcode drawing */
nColor := hb_bmp_color( pBMP, 0, 0, 0 )
? "Building BMP with", cType, "code for vale:", hb_zebra_getcode( hZebra )
hb_zebra_draw_bmp( hZebra, pBMP, nColor, nX, nY, nLineWidth, nLineHeight )
cFile := Lower( cType ) + ".bmp"
? "Creating BMP file:", cFile
IF ! hb_bmp_save( pBMP, cFile )
? "Cannot save BMP to file:", cFile
ENDIF
/* destroy BMP file */
pBMP := NIL
ENDIF
ELSE
? "Type", cType, "Code", cCode, "Error", hb_zebra_geterror( hZebra )
ENDIF
hb_zebra_destroy( hZebra )
ELSE
? "Invalid barcode type", cType
ENDIF
?
RETURN
STATIC FUNCTION hb_zebra_draw_bmp( hZebra, pBMP, nColor, ... )
IF hb_zebra_geterror( hZebra ) != 0
RETURN HB_ZEBRA_ERROR_INVALIDZEBRA
ENDIF
RETURN hb_zebra_draw( hZebra, {| x, y, w, h | hb_bmp_rect( pBMP, x, y, w, h, nColor ) }, ... )