diff --git a/ChangeLog.txt b/ChangeLog.txt index 3a63a44951..5fa0d80bd9 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -7,6 +7,42 @@ Entries may not always be in chronological/commit order. See license at the end of file. */ +2025-08-29 12:49 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * contrib/hbbmp/core.c + * contrib/hbbmp/hbbmp.ch + * contrib/hbbmp/hbbmp.h + * contrib/hbbmp/hbbmp.hbx + + added new PRG functions: + hb_bmp_frombitmap( , , , , ; + [=1], [=72], [], ; + [@] ) -> | NIL + hb_bmp_colorreset( ) + + * contrib/hbct/dattime3.c + ! struct timespec initialization + + * contrib/hbplist.txt + + added hbbmp library + + * contrib/hbzebra/coredraw.c + * contrib/hbzebra/hbzebra.hbx + + added new PRG function: + hb_zebra_getbitmap( , =8, =.F., ; + @, @, , , ; + ) -> | NIL + + * contrib/hbzebra/tests/bmp.prg + + added example for much faster BMP creation using hb_zebra_getbitmap() and + hb_bmp_frombitmap() functions + + * src/rtl/filebuf.c + ! casting + + * src/vm/extrap.c + * allocate stack buffer dynamically, in new Linux version IGSTKSZ is + defined as sysconf( _SC_SIGSTKSZ ) so it cannot be used as legal size + for static arrays + 2025-08-23 18:49 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/hbbmp/core.c ! fixed copy & past typos reported by Grigory Filatov. Thanks a lot. diff --git a/contrib/hbbmp/core.c b/contrib/hbbmp/core.c index 9db77a20df..5eaf2387c3 100644 --- a/contrib/hbbmp/core.c +++ b/contrib/hbbmp/core.c @@ -65,7 +65,11 @@ PHB_BMPINFO hb_bmp_new( int width, int height, int depth, int dpi, int * piError *piError = 0; if( fromtop ) + { height = -height; + if( height == 1 ) + fromtop = HB_FALSE; + } if( dpi == 0 ) dpi = HB_BMP_DPI_DEFAULT; @@ -114,6 +118,72 @@ PHB_BMPINFO hb_bmp_new( int width, int height, int depth, int dpi, int * piError return pBMP; } +PHB_BMPINFO hb_bmp_frombitmap( const HB_BYTE * bitmap, int align, + int width, int height, int depth, int dpi, + const int * palette, int colors, int * piError ) +{ + static const int mono_palette[ 2 ] = { 0x00FFFFFF, 0x00000000 }; + PHB_BMPINFO pBMP = NULL; + + if( bitmap && ( align >= 8 || align >= depth ) && ( align & ( align - 1 ) ) == 0 ) + pBMP = hb_bmp_new( width, height, depth, dpi, piError ); + else if ( piError ) + *piError = HB_BMP_ERROR_CORRUPT; + + if( pBMP ) + { + if( bitmap ) + { + int rowbits = ( ( pBMP->width * depth ) + align - 1 ) & ~( align - 1 ); + int rowlen = ( rowbits + 0x07 ) >> 3, row, col; + + if( align == 32 ) + memcpy( pBMP->data, bitmap, pBMP->height * pBMP->rowlen ); + else if( pBMP->height == 1 ) + memcpy( pBMP->data, bitmap, HB_MIN( rowlen, pBMP->rowlen ) ); + else if( align >= 8 ) + { + for( row = 0; row < height; ++row ) + memcpy( pBMP->data + pBMP->rowlen * row, bitmap + rowlen * row, + HB_MIN( rowlen, pBMP->rowlen ) ); + } + else + { + int maskb, shift; + + shift = depth == 4 ? 1 : ( depth == 2 ? 2 : 3 ); + maskb = ( 0x01 << shift ) - 1; + for( row = 0; row < height; ++row ) + { + HB_BYTE * rowdst = pBMP->data + pBMP->rowlen * row; + int offset = row * rowbits; + for( col = 0; col < width; ++col, offset += depth ) + rowdst[ col >> shift ] |= ( ( bitmap[ offset >> shift ] >> + ( ( maskb - ( offset & maskb ) ) * depth ) ) & + maskb ) << ( maskb - ( col & maskb ) ) * depth; + } + } + } + if( depth == 1 && ( palette == NULL || colors <= 0 ) ) + { + palette = mono_palette; + colors = 2; + } + if( palette && colors > 0 && depth <= 8 ) + { + int i; + if( colors > 256 ) + colors = 256; + for( i = 0; i < colors; ++i ) + { + int clr = palette[ i ]; + hb_bmp_color( pBMP, ( clr >> 16 ) & 0xFF, ( clr >> 8 ) & 0xFF, clr & 0xFF, ( clr >> 24 ) & 0xFF ); + } + } + } + return pBMP; +} + PHB_BMPINFO hb_bmp_copy( PHB_BMPINFO pBMP ) { PHB_BMPINFO pBMPnew = ( PHB_BMPINFO ) hb_xgrab( sizeof( HB_BMPINFO ) ); @@ -159,6 +229,12 @@ int hb_bmp_depth( PHB_BMPINFO pBMP ) return pBMP->depth; } +void hb_bmp_colorreset( PHB_BMPINFO pBMP ) +{ + memset( pBMP->palette, 0, sizeof( pBMP->palette ) ); + pBMP->clrused = 0; +} + HB_MAXINT hb_bmp_color( PHB_BMPINFO pBMP, int r, int g, int b, int a ) { HB_MAXINT iColor = -1; @@ -460,7 +536,9 @@ 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 ) + if( ! data || size > 0x10000000 ) + iError = HB_BMP_ERROR_PARAM; + else if( size < HB_BMP_FILEHEADER_SIZE + HB_BMP_INFOHEADER_MINSIZE ) iError = HB_BMP_ERROR_CORRUPT; else { @@ -691,7 +769,6 @@ void hb_bmpReturn( PHB_BMPINFO pBMP ) 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 ), @@ -700,6 +777,50 @@ HB_FUNC( HB_BMP_NEW ) hb_bmpReturn( pBMP ); } +/* hb_bmp_frombitmap( , , , , [=1], [=72], [], [@] ) -> | NIL */ +HB_FUNC( HB_BMP_FROMBITMAP ) +{ + const HB_BYTE * bitmap = ( const HB_BYTE * ) hb_parc( 1 ); + int align = hb_parni( 2 ), width = hb_parni( 3 ), height = hb_parni( 4 ), + depth = hb_parni( 5 ), dpi = hb_parni( 6 ), + iError = 0; + PHB_ITEM pColors = hb_param( 7, HB_IT_ARRAY ); + HB_BOOL fromtop = height < 0; + PHB_BMPINFO pBMP = NULL; + + if( fromtop ) + { + height = -height; + if( height == 1 ) + fromtop = HB_FALSE; + } + if( ! bitmap || ( align & ( align - 1 ) ) != 0 || + ( HB_SIZE ) ( ( ( width * depth + align - 1 ) & ~( align - 1 ) ) * + height + 0x07 ) >> 3 > hb_parclen( 1 ) ) + iError = HB_BMP_ERROR_PARAM; + else + { + pBMP = hb_bmp_frombitmap( bitmap, align, width, fromtop ? -height : height, depth, dpi, + NULL, 0, &iError ); + if( pBMP && pColors && depth <= 8 ) + { + HB_SIZE nLen = hb_arrayLen( pColors ), nAt; + + if( nLen > ( HB_SIZE ) ( 1 << depth ) ) + nLen = ( HB_SIZE ) ( 1 << depth ); + hb_bmp_colorreset( pBMP ); + for( nAt = 1; nAt <= nLen; ++nAt ) + { + int clr = hb_arrayGetNI( pColors, nAt ); + hb_bmp_color( pBMP, ( clr >> 16 ) & 0xFF, ( clr >> 8 ) & 0xFF, + clr * 0xFF, ( clr >> 24 ) & 0xFF ); + } + } + } + hb_storni( iError, 8 ); + hb_bmpReturn( pBMP ); +} + HB_FUNC( HB_BMP_COPY ) { PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE ); @@ -774,6 +895,14 @@ HB_FUNC( HB_BMP_DEPTH ) hb_retni( hb_bmp_depth( pBMP ) ); } +HB_FUNC( HB_BMP_COLORRESET ) +{ + PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE ); + + if( pBMP ) + hb_bmp_colorreset( pBMP ); +} + HB_FUNC( HB_BMP_COLOR ) { PHB_BMPINFO pBMP = hb_bmpParam( 1, HB_TRUE ); diff --git a/contrib/hbbmp/hbbmp.ch b/contrib/hbbmp/hbbmp.ch index 65938041cc..40545008e4 100644 --- a/contrib/hbbmp/hbbmp.ch +++ b/contrib/hbbmp/hbbmp.ch @@ -59,5 +59,6 @@ #define HB_BMP_ERROR_UNSUPPORTED 8 #define HB_BMP_ERROR_FILEREAD 9 #define HB_BMP_ERROR_FILEWRITE 10 +#define HB_BMP_ERROR_PARAM 11 #endif /* _HBBMP_CH_ */ diff --git a/contrib/hbbmp/hbbmp.h b/contrib/hbbmp/hbbmp.h index 8891ea2b17..a54ab3a726 100644 --- a/contrib/hbbmp/hbbmp.h +++ b/contrib/hbbmp/hbbmp.h @@ -112,6 +112,7 @@ typedef struct _HB_BMPINFO } 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_frombitmap( const HB_BYTE * bitmap, int align, int width, int height, int depth, int dpi, const int * palette, int colors, 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 ); @@ -122,6 +123,7 @@ 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 void hb_bmp_colorreset( 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 ); diff --git a/contrib/hbbmp/hbbmp.hbx b/contrib/hbbmp/hbbmp.hbx index 2327f83f7a..1f447ea9cb 100644 --- a/contrib/hbbmp/hbbmp.hbx +++ b/contrib/hbbmp/hbbmp.hbx @@ -23,12 +23,14 @@ DYNAMIC hb_bmp_color DYNAMIC hb_bmp_color2rgb +DYNAMIC hb_bmp_colorreset DYNAMIC hb_bmp_copy DYNAMIC hb_bmp_decode DYNAMIC hb_bmp_depth DYNAMIC hb_bmp_encode -DYNAMIC HB_BMP_ERROR +DYNAMIC hb_bmp_error DYNAMIC hb_bmp_free +DYNAMIC hb_bmp_frombitmap DYNAMIC hb_bmp_getpixel DYNAMIC hb_bmp_height DYNAMIC hb_bmp_line diff --git a/contrib/hbct/dattime3.c b/contrib/hbct/dattime3.c index a68aa26794..61ffb8a2d4 100644 --- a/contrib/hbct/dattime3.c +++ b/contrib/hbct/dattime3.c @@ -195,7 +195,7 @@ HB_FUNC( SETDATE ) long lNewDate = lDate - hb_dateEncode( 1970, 1, 1 ); # if defined( __GLIBC__ ) && ( ( __GLIBC__ > 2 ) || ( ( __GLIBC__ == 2 ) && ( __GLIBC_MINOR__ >= 31 ) ) ) /* stime() is deprecated in glibc 2.31+ */ - struct timespec ts = { 0 }; + struct timespec ts = { 0, 0 }; clock_gettime( CLOCK_REALTIME, &ts ); /* keep tv_nsec */ ts.tv_sec = lNewDate * 86400 + ( ts.tv_sec % 86400 ); fResult = clock_settime( CLOCK_REALTIME, &ts ) == 0; diff --git a/contrib/hbplist.txt b/contrib/hbplist.txt index 8653dfda86..508c9ed352 100644 --- a/contrib/hbplist.txt +++ b/contrib/hbplist.txt @@ -4,6 +4,7 @@ gtwvg/gtwvg.hbp hbamf/hbamf.hbp hbblat/hbblat.hbp hbblink/hbblink.hbp +hbbmp/hbbmp.hbp hbbz2/hbbz2.hbp # uses: bz2 (locally hosted) hbbz2io/hbbz2io.hbp # uses: bz2 (locally hosted) hbcairo/hbcairo.hbp diff --git a/contrib/hbzebra/coredraw.c b/contrib/hbzebra/coredraw.c index 893a463ece..bee1e0737c 100644 --- a/contrib/hbzebra/coredraw.c +++ b/contrib/hbzebra/coredraw.c @@ -171,6 +171,7 @@ int hb_zebra_getsize( PHB_ZEBRA pZebra, int * piWidth, int * piHeight ) return 0; } +/* hb_zebra_getsize( , @, @ ) -> */ HB_FUNC( HB_ZEBRA_GETSIZE ) { PHB_ZEBRA pZebra = hb_zebra_param( 1 ); @@ -184,3 +185,94 @@ HB_FUNC( HB_ZEBRA_GETSIZE ) hb_storni( iHeight, 3 ); } } + +/* NOTE: caller must free the returned bitmap pointer if not NULL */ +unsigned char * hb_zebra_getbitmap( PHB_ZEBRA pZebra, int iAlign, HB_BOOL fBottomUp, + HB_SIZE * pnSize, int * piWidth, int * piHeight, + int iScaleX, int iScaleY, int iBorder ) +{ + unsigned char * pBitMap = NULL; + HB_SIZE nSize = 0; + int iWidth, iHeight; + + if( hb_zebra_getsize( pZebra, &iWidth, &iHeight ) == 0 && + iWidth != 0 && iHeight != 0 ) + { + HB_SIZE nLen = hb_bitbuffer_len( pZebra->pBits ), n; + int iLineBits, iLineOffset, iMaxCol, iCol; + + if( iAlign < 1 || iAlign > 64 || ( iAlign & ( iAlign - 1 ) ) != 0 ) + iAlign = 8; + if( iScaleX < 1 ) + iScaleX = 1; + if( iScaleY < 1 ) + iScaleY = 1; + if( iBorder < 0 ) + iBorder = 0; + iWidth = iWidth * iScaleX + ( iBorder << 1 ); + iHeight = iHeight * iScaleY + ( iBorder << 1 ); + iLineBits = ( iWidth + ( iAlign - 1 ) ) & ~( iAlign - 1 ); + nSize = ( iLineBits * iHeight + 0x07 ) >> 3; + if( nLen > ( nSize << 3 ) ) + nLen = nSize << 3; + pBitMap = ( unsigned char * ) hb_xgrab( nSize + 1 ); + + iMaxCol = pZebra->iCol; + iCol = 0; + if( fBottomUp ) + iLineOffset = iLineBits * ( iHeight - iBorder - 1 ); + else + iLineOffset = iLineBits * iBorder; + + memset( pBitMap, 0, nSize ); + for( n = 0; n < nLen; n++ ) + { + if( hb_bitbuffer_get( pZebra->pBits, n ) ) + { + int iBitPos = iLineOffset + iCol * iScaleX + iBorder, iX, iY; + for( iY = 0; iY < iScaleY; ++iY ) + { + for( iX = 0; iX < iScaleX; ++iX ) + { + unsigned char * ptr = pBitMap + ( ( iBitPos + iX ) >> 3 ); + *ptr |= 0x80 >> ( ( iBitPos + iX ) & 0x07 ); + } + iBitPos += fBottomUp ? - iLineBits : iLineBits; + } + } + if( ++iCol == iMaxCol ) + { + iCol = 0; + iLineOffset += ( fBottomUp ? - iLineBits : iLineBits ) * iScaleY; + } + } + } + + *pnSize = nSize; + *piWidth = iWidth; + *piHeight = iHeight; + + return pBitMap; +} + +/* hb_zebra_getbitmap( , =8, =.F., @, @, , , ) -> | NIL */ +HB_FUNC( HB_ZEBRA_GETBITMAP ) +{ + PHB_ZEBRA pZebra = hb_zebra_param( 1 ); + + if( pZebra ) + { + HB_SIZE nSize; + int iWidth, iHeight; + unsigned char * pBitMap = hb_zebra_getbitmap( pZebra, hb_parni( 2 ), hb_parl( 3 ), + &nSize, &iWidth, &iHeight, + hb_parni( 6 ), hb_parni( 7 ), hb_parni( 8 ) ); + + hb_storni( iWidth, 4 ); + hb_storni( iHeight, 5 ); + if( pBitMap ) + hb_retclen_buffer( ( char * ) pBitMap, nSize ); + else + hb_retc_null(); + } +} diff --git a/contrib/hbzebra/hbzebra.hbx b/contrib/hbzebra/hbzebra.hbx index 4d7f021009..70df9534e8 100644 --- a/contrib/hbzebra/hbzebra.hbx +++ b/contrib/hbzebra/hbzebra.hbx @@ -37,6 +37,7 @@ DYNAMIC hb_zebra_create_upca DYNAMIC hb_zebra_create_upce DYNAMIC hb_zebra_destroy DYNAMIC hb_zebra_draw +DYNAMIC hb_zebra_getbitmap DYNAMIC hb_zebra_getcode DYNAMIC hb_zebra_geterror DYNAMIC hb_zebra_getsize diff --git a/contrib/hbzebra/tests/bmp.prg b/contrib/hbzebra/tests/bmp.prg index 656de86b13..0d2817aaa9 100644 --- a/contrib/hbzebra/tests/bmp.prg +++ b/contrib/hbzebra/tests/bmp.prg @@ -33,7 +33,8 @@ PROCEDURE Main() STATIC PROCEDURE DrawBarcode( nLineWidth, cType, cCode, nFlags ) - LOCAL hZebra, pBMP, nLineHeight, nX, nY, nWidth, nHeight, nDepth, nColor, cFile + LOCAL hZebra, cFile, cBitMap, pBMP, ; + nLineHeight, nX, nY, nWidth, nHeight, nDepth, nAlign, nColor SWITCH cType CASE "EAN13" ; hZebra := hb_zebra_create_ean13( cCode, nFlags ) ; EXIT @@ -59,13 +60,13 @@ STATIC PROCEDURE DrawBarcode( nLineWidth, cType, cCode, nFlags ) nLineHeight := nLineWidth * 36 ENDIF + nAlign := 32 nDepth := 1 + nX := nY := 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 + nWidth := nWidth * nLineWidth + nY + nY + nHeight := nHeight * nLineHeight + nX + nX ? cType, "code width", hb_ntos( nWidth ), "height", hb_ntos( nHeight ) IF Empty( pBMP := hb_bmp_new( nWidth, nHeight, nDepth ) ) @@ -86,6 +87,18 @@ STATIC PROCEDURE DrawBarcode( nLineWidth, cType, cCode, nFlags ) /* destroy BMP file */ pBMP := NIL ENDIF + + /* and now much faster version */ + cBitMap := hb_zebra_getbitmap( hZebra, nAlign, .T./*lBottomUp>*/, @nWidth, @nHeight, nLineWidth, nLineHeight, nX ) + pBMP := hb_bmp_frombitmap( cBitMap, nAlign, nWidth, nHeight, nDepth, /*nDPI*/, /*aPalette*/, /*@nError*/ ) + cFile := Lower( cType ) + "b.bmp" + ? "Creating BMP file:", cFile + IF ! hb_bmp_save( pBMP, cFile ) + ? "Cannot save BMP to file:", cFile + ENDIF + /* destroy BMP file */ + pBMP := NIL + ELSE ? "Type", cType, "Code", cCode, "Error", hb_zebra_geterror( hZebra ) ENDIF diff --git a/src/rtl/filebuf.c b/src/rtl/filebuf.c index 1c57942be1..207f211eac 100644 --- a/src/rtl/filebuf.c +++ b/src/rtl/filebuf.c @@ -1655,7 +1655,7 @@ HB_BOOL hb_fileSave( const char * pszFileName, const void * buffer, HB_SIZE nSiz NULL, NULL ); if( pFile != NULL ) { - const HB_BYTE * pData = buffer; + const HB_BYTE * pData = ( const HB_BYTE * ) buffer; while( nSize > 0 ) { diff --git a/src/vm/extrap.c b/src/vm/extrap.c index b5e7537b82..901a65c1b3 100644 --- a/src/vm/extrap.c +++ b/src/vm/extrap.c @@ -82,7 +82,7 @@ #endif #if defined( HB_SIGNAL_EXCEPTION_HANDLER ) - static HB_BYTE * s_signal_stack[ SIGSTKSZ ]; + static void * s_signal_stack = NULL; #endif #if defined( HB_OS_WIN ) && ! defined( HB_OS_WIN_CE ) && ! defined( __TINYC__ ) @@ -585,7 +585,9 @@ void hb_vmSetExceptionHandler( void ) #elif defined( HB_SIGNAL_EXCEPTION_HANDLER ) { stack_t ss; - ss.ss_sp = ( void * ) s_signal_stack; + if( s_signal_stack == NULL ) + s_signal_stack = hb_xgrab( SIGSTKSZ ); + ss.ss_sp = s_signal_stack; ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; /* set alternative stack for SIGSEGV executed on stack overflow */ @@ -620,10 +622,6 @@ void hb_vmUnsetExceptionHandler( void ) } #elif defined( HB_SIGNAL_EXCEPTION_HANDLER ) { - /* we are using static buffer for alternative stack so we do not - * have to deallocate it to free the memory on application exit - */ -#if 0 stack_t ss, oss; ss.ss_sp = NULL; ss.ss_size = SIGSTKSZ; @@ -631,10 +629,12 @@ void hb_vmUnsetExceptionHandler( void ) /* set alternative stack for SIGSEGV executed on stack overflow */ if( sigaltstack( &ss, &oss ) == 0 ) { - if( oss.ss_sp && SS_DISABLE ) - free( oss.ss_sp ); + if( s_signal_stack != NULL ) + { + hb_xfree( s_signal_stack ); + s_signal_stack = NULL; + } } -#endif } #endif }