2018-09-29 13:10:56 -07:00
# include <QCoreApplication>
# include <QSvgRenderer>
# include <QPainter>
# include <QImage>
2018-09-29 19:49:55 -07:00
# include <QColor>
2018-09-30 07:46:08 -07:00
# include <QRectF>
2018-09-29 18:53:10 -07:00
# include <QFile>
2019-02-21 10:22:52 -08:00
# include <QFileInfo>
2018-09-29 13:10:56 -07:00
# include <QString>
# include <stdio.h>
2018-09-29 18:53:10 -07:00
# include <stdint.h>
2018-09-29 19:49:55 -07:00
# include <string.h>
2018-09-29 13:10:56 -07:00
2018-09-29 19:49:55 -07:00
# define BITMAP_HEADER_SIZE 16
2018-09-30 09:55:28 -07:00
# define BITMAP_DIRECT_INFO_TYPE_SIZE 8
2018-09-29 19:49:55 -07:00
# define MAX_PALM_BITMAP_SIZE (0xFFFF * 4)
2018-09-29 18:53:10 -07:00
2018-10-15 14:36:22 -07:00
static const uint8_t palmPalette8Bpp [ 256 ] [ 3 ] = {
{ 255 , 255 , 255 } , { 255 , 204 , 255 } , { 255 , 153 , 255 } , { 255 , 102 , 255 } ,
{ 255 , 51 , 255 } , { 255 , 0 , 255 } , { 255 , 255 , 204 } , { 255 , 204 , 204 } ,
{ 255 , 153 , 204 } , { 255 , 102 , 204 } , { 255 , 51 , 204 } , { 255 , 0 , 204 } ,
{ 255 , 255 , 153 } , { 255 , 204 , 153 } , { 255 , 153 , 153 } , { 255 , 102 , 153 } ,
{ 255 , 51 , 153 } , { 255 , 0 , 153 } , { 204 , 255 , 255 } , { 204 , 204 , 255 } ,
{ 204 , 153 , 255 } , { 204 , 102 , 255 } , { 204 , 51 , 255 } , { 204 , 0 , 255 } ,
{ 204 , 255 , 204 } , { 204 , 204 , 204 } , { 204 , 153 , 204 } , { 204 , 102 , 204 } ,
{ 204 , 51 , 204 } , { 204 , 0 , 204 } , { 204 , 255 , 153 } , { 204 , 204 , 153 } ,
{ 204 , 153 , 153 } , { 204 , 102 , 153 } , { 204 , 51 , 153 } , { 204 , 0 , 153 } ,
{ 153 , 255 , 255 } , { 153 , 204 , 255 } , { 153 , 153 , 255 } , { 153 , 102 , 255 } ,
{ 153 , 51 , 255 } , { 153 , 0 , 255 } , { 153 , 255 , 204 } , { 153 , 204 , 204 } ,
{ 153 , 153 , 204 } , { 153 , 102 , 204 } , { 153 , 51 , 204 } , { 153 , 0 , 204 } ,
{ 153 , 255 , 153 } , { 153 , 204 , 153 } , { 153 , 153 , 153 } , { 153 , 102 , 153 } ,
{ 153 , 51 , 153 } , { 153 , 0 , 153 } , { 102 , 255 , 255 } , { 102 , 204 , 255 } ,
{ 102 , 153 , 255 } , { 102 , 102 , 255 } , { 102 , 51 , 255 } , { 102 , 0 , 255 } ,
{ 102 , 255 , 204 } , { 102 , 204 , 204 } , { 102 , 153 , 204 } , { 102 , 102 , 204 } ,
{ 102 , 51 , 204 } , { 102 , 0 , 204 } , { 102 , 255 , 153 } , { 102 , 204 , 153 } ,
{ 102 , 153 , 153 } , { 102 , 102 , 153 } , { 102 , 51 , 153 } , { 102 , 0 , 153 } ,
{ 51 , 255 , 255 } , { 51 , 204 , 255 } , { 51 , 153 , 255 } , { 51 , 102 , 255 } ,
{ 51 , 51 , 255 } , { 51 , 0 , 255 } , { 51 , 255 , 204 } , { 51 , 204 , 204 } ,
{ 51 , 153 , 204 } , { 51 , 102 , 204 } , { 51 , 51 , 204 } , { 51 , 0 , 204 } ,
{ 51 , 255 , 153 } , { 51 , 204 , 153 } , { 51 , 153 , 153 } , { 51 , 102 , 153 } ,
{ 51 , 51 , 153 } , { 51 , 0 , 153 } , { 0 , 255 , 255 } , { 0 , 204 , 255 } ,
{ 0 , 153 , 255 } , { 0 , 102 , 255 } , { 0 , 51 , 255 } , { 0 , 0 , 255 } ,
{ 0 , 255 , 204 } , { 0 , 204 , 204 } , { 0 , 153 , 204 } , { 0 , 102 , 204 } ,
{ 0 , 51 , 204 } , { 0 , 0 , 204 } , { 0 , 255 , 153 } , { 0 , 204 , 153 } ,
{ 0 , 153 , 153 } , { 0 , 102 , 153 } , { 0 , 51 , 153 } , { 0 , 0 , 153 } ,
{ 255 , 255 , 102 } , { 255 , 204 , 102 } , { 255 , 153 , 102 } , { 255 , 102 , 102 } ,
{ 255 , 51 , 102 } , { 255 , 0 , 102 } , { 255 , 255 , 51 } , { 255 , 204 , 51 } ,
{ 255 , 153 , 51 } , { 255 , 102 , 51 } , { 255 , 51 , 51 } , { 255 , 0 , 51 } ,
{ 255 , 255 , 0 } , { 255 , 204 , 0 } , { 255 , 153 , 0 } , { 255 , 102 , 0 } ,
{ 255 , 51 , 0 } , { 255 , 0 , 0 } , { 204 , 255 , 102 } , { 204 , 204 , 102 } ,
{ 204 , 153 , 102 } , { 204 , 102 , 102 } , { 204 , 51 , 102 } , { 204 , 0 , 102 } ,
{ 204 , 255 , 51 } , { 204 , 204 , 51 } , { 204 , 153 , 51 } , { 204 , 102 , 51 } ,
{ 204 , 51 , 51 } , { 204 , 0 , 51 } , { 204 , 255 , 0 } , { 204 , 204 , 0 } ,
{ 204 , 153 , 0 } , { 204 , 102 , 0 } , { 204 , 51 , 0 } , { 204 , 0 , 0 } ,
{ 153 , 255 , 102 } , { 153 , 204 , 102 } , { 153 , 153 , 102 } , { 153 , 102 , 102 } ,
{ 153 , 51 , 102 } , { 153 , 0 , 102 } , { 153 , 255 , 51 } , { 153 , 204 , 51 } ,
{ 153 , 153 , 51 } , { 153 , 102 , 51 } , { 153 , 51 , 51 } , { 153 , 0 , 51 } ,
{ 153 , 255 , 0 } , { 153 , 204 , 0 } , { 153 , 153 , 0 } , { 153 , 102 , 0 } ,
{ 153 , 51 , 0 } , { 153 , 0 , 0 } , { 102 , 255 , 102 } , { 102 , 204 , 102 } ,
{ 102 , 153 , 102 } , { 102 , 102 , 102 } , { 102 , 51 , 102 } , { 102 , 0 , 102 } ,
{ 102 , 255 , 51 } , { 102 , 204 , 51 } , { 102 , 153 , 51 } , { 102 , 102 , 51 } ,
{ 102 , 51 , 51 } , { 102 , 0 , 51 } , { 102 , 255 , 0 } , { 102 , 204 , 0 } ,
{ 102 , 153 , 0 } , { 102 , 102 , 0 } , { 102 , 51 , 0 } , { 102 , 0 , 0 } ,
{ 51 , 255 , 102 } , { 51 , 204 , 102 } , { 51 , 153 , 102 } , { 51 , 102 , 102 } ,
{ 51 , 51 , 102 } , { 51 , 0 , 102 } , { 51 , 255 , 51 } , { 51 , 204 , 51 } ,
{ 51 , 153 , 51 } , { 51 , 102 , 51 } , { 51 , 51 , 51 } , { 51 , 0 , 51 } ,
{ 51 , 255 , 0 } , { 51 , 204 , 0 } , { 51 , 153 , 0 } , { 51 , 102 , 0 } ,
{ 51 , 51 , 0 } , { 51 , 0 , 0 } , { 0 , 255 , 102 } , { 0 , 204 , 102 } ,
{ 0 , 153 , 102 } , { 0 , 102 , 102 } , { 0 , 51 , 102 } , { 0 , 0 , 102 } ,
{ 0 , 255 , 51 } , { 0 , 204 , 51 } , { 0 , 153 , 51 } , { 0 , 102 , 51 } ,
{ 0 , 51 , 51 } , { 0 , 0 , 51 } , { 0 , 255 , 0 } , { 0 , 204 , 0 } ,
{ 0 , 153 , 0 } , { 0 , 102 , 0 } , { 0 , 51 , 0 } , { 17 , 17 , 17 } ,
{ 34 , 34 , 34 } , { 68 , 68 , 68 } , { 85 , 85 , 85 } , { 119 , 119 , 119 } ,
{ 136 , 136 , 136 } , { 170 , 170 , 170 } , { 187 , 187 , 187 } , { 221 , 221 , 221 } ,
{ 238 , 238 , 238 } , { 192 , 192 , 192 } , { 128 , 0 , 0 } , { 128 , 0 , 128 } ,
{ 0 , 128 , 0 } , { 0 , 128 , 128 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } ,
{ 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } ,
{ 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } ,
{ 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } ,
{ 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } ,
{ 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } ,
{ 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 }
} ;
static inline uint16_t getRgbDiff ( uint8_t r1 , uint8_t g1 , uint8_t b1 , uint8_t r2 , uint8_t g2 , uint8_t b2 ) {
return qMax ( r1 , r2 ) - qMin ( r1 , r2 ) + qMax ( g1 , g2 ) - qMin ( g1 , g2 ) + qMax ( b1 , b2 ) - qMin ( b1 , b2 ) ;
}
static inline uint8_t getBest8BppIndex ( uint8_t r , uint8_t g , uint8_t b ) {
uint16_t closeness = 0xFFFF ;
uint8_t bestIndex ;
for ( uint16_t count = 0 ; count < 256 ; count + + ) {
uint16_t thisDiff = getRgbDiff ( r , g , b , palmPalette8Bpp [ count ] [ 0 ] , palmPalette8Bpp [ count ] [ 1 ] , palmPalette8Bpp [ count ] [ 2 ] ) ;
if ( thisDiff < closeness ) {
closeness = thisDiff ;
bestIndex = count ;
}
}
return bestIndex ;
}
2018-09-29 18:53:10 -07:00
static inline void writeBe16 ( uint8_t * data , uint16_t value ) {
2019-02-21 10:22:52 -08:00
data [ 0 ] = value > > 8 ;
data [ 1 ] = value & 0xFF ;
2018-09-29 18:53:10 -07:00
}
static inline uint16_t getRowBytes ( int16_t width , uint8_t bitsPerPixel ) {
uint16_t rowBytes = width * bitsPerPixel / 8 ;
//add 1 byte at the end for leftover bits
if ( width * bitsPerPixel % 8 > 0 )
rowBytes + = 1 ;
2018-09-29 19:49:55 -07:00
//Palm OS crashes from 16 bit accesses on odd addresses, so this is likely the same
if ( rowBytes & 1 )
rowBytes + = 1 ;
2018-09-29 18:53:10 -07:00
return rowBytes ;
}
2018-09-29 19:49:55 -07:00
static inline uint16_t getNextDepthOffset ( int16_t width , int16_t height , uint8_t bitsPerPixel ) {
2019-02-21 10:22:52 -08:00
uint32_t nextDepthOffset = BITMAP_HEADER_SIZE ;
2018-09-29 18:53:10 -07:00
2018-09-30 09:55:28 -07:00
if ( bitsPerPixel = = 16 )
nextDepthOffset + = BITMAP_DIRECT_INFO_TYPE_SIZE ;
2018-10-15 14:36:22 -07:00
//custom palette is not supported right now
//if(bitsPerPixel == 8)
// nextDepthOffset += 0xFF;
2018-09-29 19:49:55 -07:00
nextDepthOffset + = getRowBytes ( width , bitsPerPixel ) * height ;
2019-02-21 10:22:52 -08:00
//must be 32 bit aligned
if ( nextDepthOffset & 3 )
nextDepthOffset = ( nextDepthOffset & ~ 3 ) + 4 ;
2018-09-29 19:49:55 -07:00
return nextDepthOffset / 4 ;
2018-09-29 18:53:10 -07:00
}
2018-09-29 19:49:55 -07:00
void renderTo1Bit ( uint8_t * data , const QImage & image ) {
uint16_t rowBytes = getRowBytes ( image . width ( ) , 1 ) ;
2018-09-29 18:53:10 -07:00
2018-09-29 19:49:55 -07:00
memset ( data , 0x00 , rowBytes * image . height ( ) ) ;
2018-09-30 07:46:08 -07:00
for ( int16_t y = 0 ; y < image . height ( ) ; y + + ) {
for ( int16_t x = 0 ; x < image . width ( ) ; x + + ) {
2018-09-29 19:49:55 -07:00
QColor pixel = QColor ( image . pixel ( x , y ) ) ;
2018-10-05 14:09:18 -07:00
bool pixelAveraged = ( pixel . redF ( ) + pixel . greenF ( ) + pixel . blueF ( ) ) / 3.0 < 0.5 ;
2018-09-29 19:49:55 -07:00
if ( pixelAveraged )
data [ y * rowBytes + x / 8 ] | = 1 < < 7 - x % 8 ;
}
}
2018-09-29 18:53:10 -07:00
}
2018-09-29 20:25:48 -07:00
void renderTo2Bits ( uint8_t * data , const QImage & image ) {
uint16_t rowBytes = getRowBytes ( image . width ( ) , 2 ) ;
memset ( data , 0x00 , rowBytes * image . height ( ) ) ;
2018-09-30 07:46:08 -07:00
for ( int16_t y = 0 ; y < image . height ( ) ; y + + ) {
for ( int16_t x = 0 ; x < image . width ( ) ; x + + ) {
2018-09-29 20:25:48 -07:00
QColor pixel = QColor ( image . pixel ( x , y ) ) ;
uint8_t pixelAveraged = ( pixel . redF ( ) + pixel . greenF ( ) + pixel . blueF ( ) ) / 3.0 * 4.0 ;
data [ y * rowBytes + x / 4 ] | = pixelAveraged < < 6 - x % 4 * 2 ;
}
}
}
void renderTo4Bits ( uint8_t * data , const QImage & image ) {
uint16_t rowBytes = getRowBytes ( image . width ( ) , 4 ) ;
memset ( data , 0x00 , rowBytes * image . height ( ) ) ;
2018-09-30 07:46:08 -07:00
for ( int16_t y = 0 ; y < image . height ( ) ; y + + ) {
for ( int16_t x = 0 ; x < image . width ( ) ; x + + ) {
2018-09-29 20:25:48 -07:00
QColor pixel = QColor ( image . pixel ( x , y ) ) ;
uint8_t pixelAveraged = ( pixel . redF ( ) + pixel . greenF ( ) + pixel . blueF ( ) ) / 3.0 * 16.0 ;
data [ y * rowBytes + x / 2 ] | = pixelAveraged < < ( x % 2 ? 0 : 4 ) ;
}
}
}
void renderTo8Bits ( uint8_t * data , const QImage & image ) {
uint16_t rowBytes = getRowBytes ( image . width ( ) , 8 ) ;
memset ( data , 0x00 , rowBytes * image . height ( ) ) ;
2018-09-30 07:46:08 -07:00
for ( int16_t y = 0 ; y < image . height ( ) ; y + + ) {
for ( int16_t x = 0 ; x < image . width ( ) ; x + + ) {
2018-09-29 20:25:48 -07:00
QColor pixel = QColor ( image . pixel ( x , y ) ) ;
2018-10-15 14:36:22 -07:00
if ( pixel . red ( ) = = 0xFF & & pixel . green ( ) = = 0xFF & & pixel . blue ( ) = = 0xFF )
data [ y * rowBytes + x ] = 0xFF ; //transparentIndex
else
data [ y * rowBytes + x ] = getBest8BppIndex ( pixel . red ( ) , pixel . green ( ) , pixel . blue ( ) ) ;
2018-09-29 20:25:48 -07:00
}
}
}
void renderTo16Bits ( uint8_t * data , const QImage & image ) {
uint16_t rowBytes = getRowBytes ( image . width ( ) , 16 ) ;
memset ( data , 0x00 , rowBytes * image . height ( ) ) ;
2018-09-30 07:46:08 -07:00
for ( int16_t y = 0 ; y < image . height ( ) ; y + + ) {
for ( int16_t x = 0 ; x < image . width ( ) ; x + + ) {
2018-09-29 20:25:48 -07:00
QColor pixel = QColor ( image . pixel ( x , y ) ) ;
2018-09-30 07:46:08 -07:00
uint16_t pixel16 = ( pixel . red ( ) > > 3 & 0x001F ) < < 11 | ( pixel . green ( ) > > 2 & 0x003F ) < < 5 | ( pixel . blue ( ) > > 3 & 0x001F ) ;
2018-09-29 20:25:48 -07:00
2018-09-30 07:46:08 -07:00
writeBe16 ( data + y * rowBytes + x * 2 , pixel16 ) ;
2018-09-29 20:25:48 -07:00
}
}
}
2019-02-21 10:22:52 -08:00
uint32_t renderPalmBitmap ( const QImage & bitmap , uint8_t * output , uint8_t bitsPerPixel , bool lastBitmap ) {
/*
QFileInfo imageSource ( path ) ;
2018-10-15 14:36:22 -07:00
QImage canvas ( width , height , QImage : : Format_RGB32 ) ;
2018-09-29 13:10:56 -07:00
QPainter painter ( & canvas ) ;
2018-09-29 18:53:10 -07:00
uint32_t offset = 0 ;
2018-09-29 13:10:56 -07:00
2018-09-30 07:46:08 -07:00
//clear buffer to white and render
2018-10-15 14:36:22 -07:00
canvas . fill ( QColor ( 0xFF , 0xFF , 0xFF ) . rgb ( ) ) ;
2019-02-21 10:22:52 -08:00
if ( imageSource . isDir ( ) ) {
//use image of correct size for Palm icon
//$DIR/icon$WIDTHx$HEIGHTx$BPP.png", doesnt actually have to be a png, just has to have that extension
QImage icon ( path + " /icon " + QString : : number ( width ) + " x " + QString : : number ( height ) + " .png " ) ;
painter . drawImage ( 0 , 0 , icon ) ;
}
else if ( imageSource . isFile ( ) & & imageSource . suffix ( ) = = " svg " ) {
//render SVG to Palm icon
QSvgRenderer svgRenderer ( path ) ;
svgRenderer . render ( & painter ) ;
}
*/
2018-09-29 13:10:56 -07:00
2018-09-29 18:53:10 -07:00
//write a Palm bitmap struct
2019-02-21 10:22:52 -08:00
uint32_t offset = 0 ;
uint8_t bitmapVersion = bitsPerPixel < = 4 ? 1 : 2 ;
2018-09-29 18:53:10 -07:00
2019-02-21 10:22:52 -08:00
writeBe16 ( output + offset , bitmap . width ( ) ) ; //width
2018-09-29 19:49:55 -07:00
offset + = sizeof ( int16_t ) ;
2019-02-21 10:22:52 -08:00
writeBe16 ( output + offset , bitmap . height ( ) ) ; //height
2018-09-29 19:49:55 -07:00
offset + = sizeof ( int16_t ) ;
2019-02-21 10:22:52 -08:00
writeBe16 ( output + offset , getRowBytes ( bitmap . width ( ) , bitsPerPixel ) ) ; //rowBytes
2018-09-29 18:53:10 -07:00
offset + = sizeof ( uint16_t ) ;
2019-02-21 10:22:52 -08:00
writeBe16 ( output + offset , ( bitsPerPixel = = 8 ? 0x2000 : 0x0000 ) | ( bitsPerPixel = = 16 ? 0x0400 : 0x0000 ) ) ; //bitmapFlags, only hasTransparency and directColor are implemented
2018-09-29 18:53:10 -07:00
offset + = sizeof ( uint16_t ) ;
2019-02-21 10:22:52 -08:00
if ( bitmapVersion > = 1 ) {
output [ offset ] = bitsPerPixel ; //pixelSize
2018-09-29 18:53:10 -07:00
offset + = sizeof ( uint8_t ) ;
2019-02-21 10:22:52 -08:00
output [ offset ] = bitmapVersion ; //version
2018-09-29 18:53:10 -07:00
offset + = sizeof ( uint8_t ) ;
2019-02-21 10:22:52 -08:00
writeBe16 ( output + offset , lastBitmap ? 0 : getNextDepthOffset ( bitmap . width ( ) , bitmap . height ( ) , bitsPerPixel ) ) ; //nextDepthOffset
offset + = sizeof ( uint16_t ) ;
if ( bitmapVersion > = 2 ) {
output [ offset ] = 0xFF ; //transparentIndex, white is transparent, not doing this causes issues on Palm OS5+
offset + = sizeof ( uint8_t ) ;
output [ offset ] = 0xFF ; //compressionType, none
offset + = sizeof ( uint8_t ) ;
writeBe16 ( output + offset , 0x0000 ) ; //reserved
offset + = sizeof ( uint16_t ) ;
if ( bitsPerPixel = = 16 ) {
//add BitmapDirectInfoType
output [ offset ] = 0x05 ; //redBits
offset + = sizeof ( uint8_t ) ;
output [ offset ] = 0x06 ; //greenBits
offset + = sizeof ( uint8_t ) ;
output [ offset ] = 0x05 ; //blueBits
offset + = sizeof ( uint8_t ) ;
output [ offset ] = 0x00 ; //reserved
offset + = sizeof ( uint8_t ) ;
//RGBColorType transparentColor
output [ offset ] = 0xFF ; //index
offset + = sizeof ( uint8_t ) ;
output [ offset ] = 0x1F ; //r
offset + = sizeof ( uint8_t ) ;
output [ offset ] = 0x3F ; //g
offset + = sizeof ( uint8_t ) ;
output [ offset ] = 0x1F ; //b
offset + = sizeof ( uint8_t ) ;
}
//0xFF look up table goes here when active, custom LUT is currently unsupported
}
else {
//bitmapV1
writeBe16 ( output + offset , 0x0000 ) ; //reserved
offset + = sizeof ( uint16_t ) ;
writeBe16 ( output + offset , 0x0000 ) ; //reserved
offset + = sizeof ( uint16_t ) ;
}
2018-09-29 18:53:10 -07:00
}
else {
2019-02-21 10:22:52 -08:00
//bitmapV0
writeBe16 ( output + offset , 0x0000 ) ; //reserved
offset + = sizeof ( uint16_t ) ;
writeBe16 ( output + offset , 0x0000 ) ; //reserved
offset + = sizeof ( uint16_t ) ;
writeBe16 ( output + offset , 0x0000 ) ; //reserved
offset + = sizeof ( uint16_t ) ;
writeBe16 ( output + offset , 0x0000 ) ; //reserved
offset + = sizeof ( uint16_t ) ;
2018-09-29 18:53:10 -07:00
}
2018-09-29 19:49:55 -07:00
switch ( bitsPerPixel ) {
case 1 :
2019-02-21 10:22:52 -08:00
renderTo1Bit ( output + offset , bitmap ) ;
2018-09-29 19:49:55 -07:00
break ;
case 2 :
2019-02-21 10:22:52 -08:00
renderTo2Bits ( output + offset , bitmap ) ;
2018-09-29 19:49:55 -07:00
break ;
case 4 :
2019-02-21 10:22:52 -08:00
renderTo4Bits ( output + offset , bitmap ) ;
2018-09-29 19:49:55 -07:00
break ;
case 8 :
2019-02-21 10:22:52 -08:00
renderTo8Bits ( output + offset , bitmap ) ;
2018-09-29 19:49:55 -07:00
break ;
case 16 :
2019-02-21 10:22:52 -08:00
renderTo16Bits ( output + offset , bitmap ) ;
2018-09-29 19:49:55 -07:00
break ;
}
2019-02-21 10:22:52 -08:00
offset + = getRowBytes ( bitmap . width ( ) , bitsPerPixel ) * bitmap . height ( ) ;
//must be 32 bit aligned to chain bitmaps
if ( ! lastBitmap & & offset & 3 )
offset = ( offset & ~ 3 ) + 4 ;
2018-09-29 18:53:10 -07:00
return offset ;
2018-09-29 13:10:56 -07:00
}
2019-02-21 10:22:52 -08:00
QImage renderSvgToQimage ( const QString & path , int16_t width , int16_t height ) {
QSvgRenderer svgRenderer ( path ) ;
QImage canvas ( width , height , QImage : : Format_RGB32 ) ;
QPainter painter ( & canvas ) ;
//clear buffer to white and render
canvas . fill ( QColor ( 0xFF , 0xFF , 0xFF ) . rgb ( ) ) ;
svgRenderer . render ( & painter ) ;
return canvas ;
}
QImage getIconImage ( const QString & path , int16_t width , int16_t height , uint8_t bpp ) {
//$DIR/icon$WIDTHx$HEIGHTx$BPP.png", doesnt actually have to be a png, just has to have that extension
return QImage ( path + " /icon " + QString : : number ( width ) + " x " + QString : : number ( height ) + " x " + QString : : number ( bpp ) + " .png " ) ;
}
void convertToPalmIcons ( const QString & path , const QString & outputDirectory ) {
QFileInfo imagePath ( path ) ;
2019-02-21 11:03:31 -08:00
QFile taib03E8File ( outputDirectory + " /tAIB03e8.bin " ) ;
QFile taib03E9File ( outputDirectory + " /tAIB03e9.bin " ) ;
2018-09-29 20:25:48 -07:00
uint8_t * taib03E8 = new uint8_t [ MAX_PALM_BITMAP_SIZE * 5 ] ;
uint8_t * taib03E9 = new uint8_t [ MAX_PALM_BITMAP_SIZE * 5 ] ;
2018-09-29 18:53:10 -07:00
uint32_t taib03E8Offset = 0 ;
uint32_t taib03E9Offset = 0 ;
2019-02-21 10:22:52 -08:00
//render folder of icons or .svg file to all sizes of Palm OS icon with the proper names for prc-tools
if ( imagePath . isDir ( ) ) {
taib03E8Offset + = renderPalmBitmap ( getIconImage ( path , 22 , 22 , 1 ) , taib03E8 + taib03E8Offset , 1 , false ) ; //1bpp, greyscale
taib03E8Offset + = renderPalmBitmap ( getIconImage ( path , 22 , 22 , 2 ) , taib03E8 + taib03E8Offset , 2 , false ) ; //2bpp, greyscale
taib03E8Offset + = renderPalmBitmap ( getIconImage ( path , 22 , 22 , 4 ) , taib03E8 + taib03E8Offset , 4 , false ) ; //4bpp, greyscale
taib03E8Offset + = renderPalmBitmap ( getIconImage ( path , 22 , 22 , 8 ) , taib03E8 + taib03E8Offset , 8 , false ) ; //8bpp, color
taib03E8Offset + = renderPalmBitmap ( getIconImage ( path , 22 , 22 , 16 ) , taib03E8 + taib03E8Offset , 16 , true ) ; //16bpp, color
taib03E9Offset + = renderPalmBitmap ( getIconImage ( path , 15 , 9 , 1 ) , taib03E9 + taib03E9Offset , 1 , false ) ; //1bpp, greyscale
taib03E9Offset + = renderPalmBitmap ( getIconImage ( path , 15 , 9 , 2 ) , taib03E9 + taib03E9Offset , 2 , false ) ; //2bpp, greyscale
taib03E9Offset + = renderPalmBitmap ( getIconImage ( path , 15 , 9 , 4 ) , taib03E9 + taib03E9Offset , 4 , false ) ; //4bpp, greyscale
taib03E9Offset + = renderPalmBitmap ( getIconImage ( path , 15 , 9 , 8 ) , taib03E9 + taib03E9Offset , 8 , false ) ; //8bpp, color
taib03E9Offset + = renderPalmBitmap ( getIconImage ( path , 15 , 9 , 16 ) , taib03E9 + taib03E9Offset , 16 , true ) ; //16bpp, color
}
else if ( imagePath . isFile ( ) & & imagePath . suffix ( ) = = " svg " ) {
QImage svgOutputBig = renderSvgToQimage ( path , 22 , 22 ) ;
QImage svgOutputLittle = renderSvgToQimage ( path , 15 , 9 ) ;
taib03E8Offset + = renderPalmBitmap ( svgOutputBig , taib03E8 + taib03E8Offset , 1 , false ) ; //1bpp, greyscale
taib03E8Offset + = renderPalmBitmap ( svgOutputBig , taib03E8 + taib03E8Offset , 2 , false ) ; //2bpp, greyscale
taib03E8Offset + = renderPalmBitmap ( svgOutputBig , taib03E8 + taib03E8Offset , 4 , false ) ; //4bpp, greyscale
taib03E8Offset + = renderPalmBitmap ( svgOutputBig , taib03E8 + taib03E8Offset , 8 , false ) ; //8bpp, color
taib03E8Offset + = renderPalmBitmap ( svgOutputBig , taib03E8 + taib03E8Offset , 16 , true ) ; //16bpp, color
taib03E9Offset + = renderPalmBitmap ( svgOutputLittle , taib03E9 + taib03E9Offset , 1 , false ) ; //1bpp, greyscale
taib03E9Offset + = renderPalmBitmap ( svgOutputLittle , taib03E9 + taib03E9Offset , 2 , false ) ; //2bpp, greyscale
taib03E9Offset + = renderPalmBitmap ( svgOutputLittle , taib03E9 + taib03E9Offset , 4 , false ) ; //4bpp, greyscale
taib03E9Offset + = renderPalmBitmap ( svgOutputLittle , taib03E9 + taib03E9Offset , 8 , false ) ; //8bpp, color
taib03E9Offset + = renderPalmBitmap ( svgOutputLittle , taib03E9 + taib03E9Offset , 16 , true ) ; //16bpp, color
}
2018-09-29 18:53:10 -07:00
if ( taib03E8File . open ( QFile : : WriteOnly | QFile : : Truncate ) ) {
taib03E8File . write ( ( const char * ) taib03E8 , taib03E8Offset ) ;
taib03E8File . close ( ) ;
}
if ( taib03E9File . open ( QFile : : WriteOnly | QFile : : Truncate ) ) {
taib03E9File . write ( ( const char * ) taib03E9 , taib03E9Offset ) ;
taib03E9File . close ( ) ;
}
2018-10-15 14:47:24 -07:00
delete [ ] taib03E8 ;
delete [ ] taib03E9 ;
2018-09-29 13:10:56 -07:00
}
2019-02-21 10:22:52 -08:00
void convertToPalmBitmap ( const QString & imagePath , const QString & outputPath ) {
QImage image ( imagePath ) ;
QFile outputFile ( outputPath ) ;
uint8_t * outputBuffer = new uint8_t [ MAX_PALM_BITMAP_SIZE * 5 ] ;
uint32_t outputOffset = 0 ;
outputOffset + = renderPalmBitmap ( image , outputBuffer + outputOffset , 1 , false ) ; //1bpp, greyscale
outputOffset + = renderPalmBitmap ( image , outputBuffer + outputOffset , 2 , false ) ; //2bpp, greyscale
outputOffset + = renderPalmBitmap ( image , outputBuffer + outputOffset , 4 , false ) ; //4bpp, greyscale
outputOffset + = renderPalmBitmap ( image , outputBuffer + outputOffset , 8 , false ) ; //8bpp, color
outputOffset + = renderPalmBitmap ( image , outputBuffer + outputOffset , 16 , true ) ; //16bpp, color
if ( outputFile . open ( QFile : : WriteOnly | QFile : : Truncate ) ) {
outputFile . write ( ( const char * ) outputBuffer , outputOffset ) ;
outputFile . close ( ) ;
}
delete [ ] outputBuffer ;
}
2018-09-29 13:10:56 -07:00
int main ( int argc , char * argv [ ] ) {
2019-02-21 10:22:52 -08:00
if ( argc = = 4 ) {
QString command = argv [ 1 ] ;
if ( command = = " icon " )
convertToPalmIcons ( QString ( argv [ 2 ] ) , QString ( argv [ 3 ] ) ) ;
else if ( command = = " bitmap " )
convertToPalmBitmap ( QString ( argv [ 2 ] ) , QString ( argv [ 3 ] ) ) ;
else
printf ( " \" %s \" is not a valid command. \n " , command . toStdString ( ) . c_str ( ) ) ;
2018-09-29 13:10:56 -07:00
}
else {
//invalid parameters
2019-02-21 10:22:52 -08:00
printf ( " MakePalmBitmap v1.1 \n " ) ;
2018-09-29 13:10:56 -07:00
printf ( " A replacement for the pilrc bitmap converter, which seems to be broken on 64 bit systems. \n " ) ;
2019-02-21 10:22:52 -08:00
printf ( " Args:icon \" /path/to/image.svg \" \" /path/to/palm/application/directory \" \n " ) ;
printf ( " OR \n " ) ;
printf ( " Args:icon \" /path/to/image/dir \" \" /path/to/palm/application/directory \" \n " ) ;
printf ( " OR \n " ) ;
printf ( " Args:bitmap \" /path/to/image.png \" \" /path/to/palm/application/directory/Tbmp****.bin \" \n " ) ;
2018-09-29 13:10:56 -07:00
printf ( " Fleas have pet rabbits! \n " ) ;
}
return 0 ;
}