BlinkenArea - GitList
Repositories
Blog
Wiki
BlinkenLib
Code
Commits
Branches
Tags
Search
Tree:
457e484
Branches
Tags
master
v0.1
v0.2
v0.3
v0.3.1
v0.4
v0.4.1
v0.5
v0.5.1
v0.5.2
v0.5.3
v0.5.4
v0.5.5
v0.6.0
v0.6.1
v0.6.2
v0.6.3
v0.6.4
v0.6.5
v0.6.6
v0.6.7
v0.6.8
v0.6.9
v0.7.0
v0.7.1
v0.7.10
v0.7.2
v0.7.3
v0.7.4
v0.7.5
v0.7.6
v0.7.7
v0.7.8
v0.7.9
v0.8.0
v0.8.1
BlinkenLib
BlinkenFrame.c
BlinkenLib v.0.3 (2005-02-16)
Christian Heimke
commited
457e484
at 2011-07-15 09:01:49
BlinkenFrame.c
Blame
History
Raw
/* BlinkenLib * version 0.3 date 2005-02-16 * Copyright 2004-2005 Stefan Schuermans <1stein@schuermans.info> * Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html * a blinkenarea.org project * powered by eventphone.de */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <netinet/in.h> #include "BlinkenConstants.h" #include "BlinkenFrame.h" #include "Tools.h" struct sBlinkenFrame { int height; int width; int channels; int maxval; int duration; unsigned char * * * pppData; }; //blinken protocol headers typedef struct sBlinkenProtoBlpHdr { uint32_t magic; uint32_t frameNo; uint16_t width; uint16_t height; } stBlinkenProtoBlpHdr; #define BlinkenProtoBlpMagic 0xDEADBEEF typedef struct sBlinkenProtoEblpHdr { uint32_t magic; uint32_t frameNo; uint16_t width; uint16_t height; } stBlinkenProtoEblpHdr; #define BlinkenProtoEblpMagic 0xFEEDBEEF typedef struct sBlinkenProtoMcufHdr { uint32_t magic; uint16_t height; uint16_t width; uint16_t channels; uint16_t maxval; } stBlinkenProtoMcufHdr; #define BlinkenProtoMcufMagic 0x23542666 stBlinkenFrame * BlinkenFrameNew( int height, int width, int channels, int maxval, int duration ) { stBlinkenFrame * pFrame; if( height < BlinkenHeightMin ) height = BlinkenHeightMin; if( height > BlinkenHeightMax ) height = BlinkenHeightMax; if( width < BlinkenWidthMin ) width = BlinkenWidthMin; if( width > BlinkenWidthMax ) width = BlinkenWidthMax; if( channels < BlinkenChannelsMin ) channels = BlinkenChannelsMin; if( channels > BlinkenChannelsMax ) channels = BlinkenMaxvalMax; if( maxval < BlinkenMaxvalMin ) maxval = BlinkenMaxvalMin; if( maxval > BlinkenMaxvalMax ) maxval = BlinkenMaxvalMax; if( duration < BlinkenDurationMin ) duration = BlinkenDurationMin; if( duration > BlinkenDurationMax ) duration = BlinkenDurationMax; pFrame = (stBlinkenFrame *)malloc( sizeof( stBlinkenFrame ) ); if( pFrame == NULL ) return NULL; pFrame->height = height; pFrame->width = width; pFrame->channels = channels; pFrame->maxval = maxval; pFrame->duration = duration; pFrame->pppData = (unsigned char * * *)malloc3D( height, width, channels, sizeof( unsigned char ) ); if( pFrame->pppData == NULL ) { free( pFrame ); return NULL; } return pFrame; } stBlinkenFrame * BlinkenFrameClone( stBlinkenFrame * pSrcFrame ) { int y, x, c; stBlinkenFrame * pFrame; if( pSrcFrame == NULL ) return NULL; pFrame = BlinkenFrameNew( pSrcFrame->height, pSrcFrame->width, pSrcFrame->channels, pSrcFrame->maxval, pSrcFrame->duration ); if( pFrame == NULL ) return NULL; for( y = 0; y < pFrame->height; y++ ) for( x = 0; x < pFrame->width; x++ ) for( c = 0; c < pFrame->channels; c++ ) pFrame->pppData[y][x][c] = pSrcFrame->pppData[y][x][c]; return pFrame; } void BlinkenFrameFree( stBlinkenFrame * pFrame ) { if( pFrame == NULL ) return; free( pFrame->pppData ); free( pFrame ); } void BlinkenFrameClear( stBlinkenFrame * pFrame ) { int y, x, c; if( pFrame == NULL ) return; for( y = 0; y < pFrame->height; y++ ) for( x = 0; x < pFrame->width; x++ ) for( c = 0; c < pFrame->channels; c++ ) pFrame->pppData[y][x][c] = 0; } int BlinkenFrameGetHeight( stBlinkenFrame * pFrame ) { if( pFrame == NULL ) return 0; return pFrame->height; } int BlinkenFrameGetWidth( stBlinkenFrame * pFrame ) { if( pFrame == NULL ) return 0; return pFrame->width; } int BlinkenFrameGetChannels( stBlinkenFrame * pFrame ) { if( pFrame == NULL ) return 0; return pFrame->channels; } int BlinkenFrameGetMaxval( stBlinkenFrame * pFrame ) { if( pFrame == NULL ) return 0; return pFrame->maxval; } int BlinkenFrameGetDuration( stBlinkenFrame * pFrame ) { if( pFrame == NULL ) return 0; return pFrame->duration; } void BlinkenFrameSetDuration( stBlinkenFrame * pFrame, int duration ) { if( pFrame == NULL ) return; if( duration < BlinkenDurationMin ) duration = BlinkenDurationMin; if( duration > BlinkenDurationMax ) duration = BlinkenDurationMax; pFrame->duration = duration; } unsigned char BlinkenFrameGetPixel( stBlinkenFrame * pFrame, int y, int x, int c ) { if( pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width || c < 0 || c >= pFrame->channels ) return 0; return pFrame->pppData[y][x][c]; } void BlinkenFrameSetPixel( stBlinkenFrame * pFrame, int y, int x, int c, unsigned char val ) { if( pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width || c < 0 || c >= pFrame->channels ) return; if( val > pFrame->maxval ) val = pFrame->maxval; pFrame->pppData[y][x][c] = val; } unsigned long BlinkenFrameGetColor( stBlinkenFrame * pFrame, int y, int x ) { if( pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width ) return 0; if( pFrame->channels == 1 ) return (((unsigned long)pFrame->pppData[y][x][0] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 16 | (((unsigned long)pFrame->pppData[y][x][0] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 8 | (((unsigned long)pFrame->pppData[y][x][0] * 255 + pFrame->maxval / 2) / pFrame->maxval); if( pFrame->channels == 2 ) return (((unsigned long)pFrame->pppData[y][x][0] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 16 | (((unsigned long)pFrame->pppData[y][x][1] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 8; return (((unsigned long)pFrame->pppData[y][x][0] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 16 | (((unsigned long)pFrame->pppData[y][x][1] * 255 + pFrame->maxval / 2) / pFrame->maxval) << 8 | (((unsigned long)pFrame->pppData[y][x][2] * 255 + pFrame->maxval / 2) / pFrame->maxval); } void BlinkenFrameSetColor( stBlinkenFrame * pFrame, int y, int x, unsigned long color ) { int alpha, alpha_, c; if( pFrame == NULL || y < 0 || y >= pFrame->height || x < 0 || x >= pFrame->width ) return; alpha = (color >> 24) & 0xFF; alpha_ = 255 - alpha; if( pFrame->channels >= 1 ) pFrame->pppData[y][x][0] = (unsigned char)(( ((((color >> 16) & 0xFF) * pFrame->maxval + 127) / 255) * alpha + (unsigned long)pFrame->pppData[y][x][0] * alpha_ ) / 255); if( pFrame->channels >= 2 ) pFrame->pppData[y][x][1] = (unsigned char)(( ((((color >> 8) & 0xFF) * pFrame->maxval + 127) / 255) * alpha + (unsigned long)pFrame->pppData[y][x][1] * alpha_ ) / 255); if( pFrame->channels >= 3 ) pFrame->pppData[y][x][2] = (unsigned char)(( (((color & 0xFF) * pFrame->maxval + 127) / 255) * alpha + (unsigned long)pFrame->pppData[y][x][2] * alpha_ ) / 255); for( c = 3; c < pFrame->channels; c++ ) pFrame->pppData[y][x][c] = (unsigned char)(( 0 + (unsigned long)pFrame->pppData[y][x][c] * alpha_ ) / 255); } void BlinkenFrameResize( stBlinkenFrame * pFrame, int height, int width, int channels, int maxval ) { unsigned char * * * pppData; int y, x, c; int emptyY, emptyX, skipY, skipX, rangeY, rangeX; unsigned long val, div; if( pFrame == NULL ) return; if( height < BlinkenHeightMin ) height = BlinkenHeightMin; if( height > BlinkenHeightMax ) height = BlinkenHeightMax; if( width < BlinkenWidthMin ) width = BlinkenWidthMin; if( width > BlinkenWidthMax ) width = BlinkenWidthMax; if( channels < BlinkenChannelsMin ) channels = BlinkenChannelsMin; if( channels > BlinkenChannelsMax ) channels = BlinkenMaxvalMax; if( maxval < BlinkenMaxvalMin ) maxval = BlinkenMaxvalMin; if( maxval > BlinkenMaxvalMax ) maxval = BlinkenMaxvalMax; if( height == pFrame->height && width == pFrame->width && channels == pFrame->channels && maxval == pFrame->maxval ) return; //allocate new data array pppData = (unsigned char * * *)malloc3D( height, width, channels, sizeof( unsigned char ) ); if( pppData == NULL ) return; for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) for( c = 0; c < channels; c++ ) pppData[y][x][c] = 0; //get number of pixels to skip / to leave empty in X and Y direction if( height > pFrame->height ) { emptyY = (height - pFrame->height) / 2; skipY = 0; rangeY = pFrame->height; } else { emptyY = 0; skipY = (pFrame->height - height) / 2; rangeY = height; } if( width > pFrame->width ) { emptyX = (width - pFrame->width) / 2; skipX = 0; rangeX = pFrame->width; } else { emptyX = 0; skipX = (pFrame->width - width) / 2; rangeX = width; } //resize frame with help of calculated parameters for( y = 0; y < rangeY; y++ ) { for( x = 0; x < rangeX; x++ ) { if( channels >= pFrame->channels ) //add channels: copy last channel into new channels { for( c = 0; c < pFrame->channels; c++ ) pppData[emptyY + y][emptyX + x][c] = (unsigned char)(((unsigned long)pFrame->pppData[skipY + y][skipX + x][c] * maxval + pFrame->maxval / 2) / pFrame->maxval); for( ; c < channels; c++ ) pppData[emptyY + y][emptyX + x][c] = pppData[emptyY + y][emptyX + x][pFrame->channels - 1]; } else //remove channels: merge leftover channels with last kept channel { val = 0; for( c = 0; c < channels - 1; c++ ) pppData[emptyY + y][emptyX + x][c] = (unsigned char)(((unsigned long)pFrame->pppData[skipY + y][skipX + x][c] * maxval + pFrame->maxval / 2) / pFrame->maxval); for( c = channels - 1; c < pFrame->channels; c++ ) val += (unsigned long)pFrame->pppData[skipY + y][skipX + x][c]; div = pFrame->maxval * (pFrame->channels - channels + 1); pppData[emptyY + y][emptyX + x][channels - 1] = (unsigned char)((val * maxval + div / 2) / div); } } } pFrame->height = height; pFrame->width = width; pFrame->channels = channels; pFrame->maxval = maxval; free( pFrame->pppData ); pFrame->pppData = pppData; } void BlinkenFrameScale( stBlinkenFrame * pFrame, int height, int width ) { unsigned char * * * pppData; double scaleHor, scaleVer, ox, oy, ox1, oy1, val; int c, nx, ny, x, y, oxi, oyi, ox1i, oy1i; if( pFrame == NULL ) return; if( height < BlinkenHeightMin ) height = BlinkenHeightMin; if( height > BlinkenHeightMax ) height = BlinkenHeightMax; if( width < BlinkenWidthMin ) width = BlinkenWidthMin; if( width > BlinkenWidthMax ) width = BlinkenWidthMax; if( height == pFrame->height && width == pFrame->width ) return; scaleHor = (double)width / (double)pFrame->width; scaleVer = (double)height / (double)pFrame->height; //allocate new data array pppData = (unsigned char * * *)malloc3D( height, width, pFrame->channels, sizeof( unsigned char ) ); if( pppData == NULL ) return; //scale every channel for( c = 0; c < pFrame->channels; c++ ) { for( ny = 0; ny < height; ny++ ) { for( nx = 0; nx < width; nx++ ) { oy = (double)ny / scaleVer; //sub-pixel exact range in old picture ox = (double)nx / scaleHor; oy1 = (double)(ny + 1) / scaleVer - 0.000001; ox1 = (double)(nx + 1) / scaleHor - 0.000001; if( oy < 0 || ox < 0 || oy1 >= pFrame->height || ox1 >= pFrame->width) //out of old picture pppData[ny][nx][c] = 0; else { oyi = (int)oy; oxi = (int)ox; oy1i = (int)oy1; ox1i = (int)ox1; if( oyi == oy1i ) { if( oxi == ox1i) //one source pixel { val = (double)pFrame->pppData[oyi][oxi][c]; } else //one line of source pixels { val = (double)pFrame->pppData[oyi][oxi][c] * (1 - ox + oxi) + (double)pFrame->pppData[oyi][ox1i][c] * (ox1 - ox1i); for( x = oxi + 1; x < ox1i; x++ ) val += (double)pFrame->pppData[oyi][x][c]; val /= ox1 - ox; } } else //one column of source pixels { if( oxi == ox1i ) { val = (double)pFrame->pppData[oyi][oxi][c] * (1 - oy + oyi) + (double)pFrame->pppData[oy1i][oxi][c] * (oy1 - oy1i); for( y = oyi + 1; y < oy1i; y++ ) val += (double)pFrame->pppData[y][oxi][c]; val /= oy1 - oy; } else //rectangle of source pixels { val = (double)pFrame->pppData[oyi][oxi][c] * (1 - oy + oyi) * (1 - ox + oxi) + (double)pFrame->pppData[oyi][ox1i][c] * (1 - oy + oyi) * (ox1 - ox1i) + (double)pFrame->pppData[oy1i][oxi][c] * (oy1 - oy1i) * (1 - ox + oxi) + (double)pFrame->pppData[oy1i][ox1i][c] * (oy1 - oy1i) * (ox1 - ox1i); for( y = oyi + 1; y < oy1i; y++ ) { val += (double)pFrame->pppData[y][oxi][c] * (1 - ox + oxi) + (double)pFrame->pppData[y][ox1i][c] * (ox1 - ox1i); } for( x = oxi + 1; x < ox1i; x++ ) { val += (double)pFrame->pppData[oyi][x][c] * (1 - oy + oyi) + (double)pFrame->pppData[oy1i][x][c] * (oy1 - oy1i); } for( y = oyi + 1; y < oy1i; y++ ) for( x = oxi + 1; x < ox1i; x++ ) val += (double)pFrame->pppData[y][x][c]; val /= (oy1 - oy) * (ox1 - ox); } } pppData[ny][nx][c] = (unsigned char)(val + 0.5); } } //for( nx ... } //for( ny ... } //for( c ... pFrame->height = height; pFrame->width = width; free( pFrame->pppData ); pFrame->pppData = pppData; } char * BlinkenFrameToString( stBlinkenFrame * pFrame ) { int size, y, x, c; char * str, * ptr; unsigned long val; if( pFrame == NULL ) return NULL; size = pFrame->height * (pFrame->width + 1) + 32; str = (char *)malloc( size ); if( str == NULL ) return NULL; ptr = str; for( y = 0; y < pFrame->height; y++ ) { for( x = 0; x < pFrame->width; x++ ) { val = 0; for( val = 0, c = 0; c < pFrame->channels; c++ ) val += pFrame->pppData[y][x][c]; val = val * 7 / pFrame->maxval / pFrame->channels; *ptr = " -+*%#&@"[val]; ptr++; } *ptr = '\n'; ptr++; } sprintf( ptr, "%u ms\n", pFrame->duration ); return str; } int BlinkenFrameToNetwork( stBlinkenFrame * pFrame, etBlinkenProto proto, char * pData, int maxLength ) //returns length or -1 on error { int y, x, c, i, val; if( pFrame == NULL ) return -1; switch( proto ) { case BlinkenProtoNone: return 0; case BlinkenProtoBlp: if( maxLength < (int)sizeof( stBlinkenProtoBlpHdr ) + pFrame->height * pFrame->width ) //buffer too short return -1; ((stBlinkenProtoBlpHdr *)pData)->magic = htonl( BlinkenProtoBlpMagic ); //build header ((stBlinkenProtoBlpHdr *)pData)->frameNo = htonl( 0 ); ((stBlinkenProtoBlpHdr *)pData)->width = htons( pFrame->width ); ((stBlinkenProtoBlpHdr *)pData)->height = htons( pFrame->height ); i = sizeof( stBlinkenProtoBlpHdr ); //put data into packet for( y = 0; y < pFrame->height; y++ ) { for( x = 0; x < pFrame->width; x++, i++ ) { val = 0; for( c = 0; c < pFrame->channels; c++ ) val += pFrame->pppData[y][x][c]; pData[i] = (val >= pFrame->channels * pFrame->maxval / 2 ? 0x01 : 0x00); } } return i; //return length case BlinkenProtoEblp: if( maxLength < (int)sizeof( stBlinkenProtoEblpHdr ) + pFrame->height * pFrame->width ) //buffer too short return -1; ((stBlinkenProtoEblpHdr *)pData)->magic = htonl( BlinkenProtoEblpMagic ); //build header ((stBlinkenProtoEblpHdr *)pData)->frameNo = htonl( 0 ); ((stBlinkenProtoEblpHdr *)pData)->width = htons( pFrame->width ); ((stBlinkenProtoEblpHdr *)pData)->height = htons( pFrame->height ); i = sizeof( stBlinkenProtoEblpHdr ); //put data into packet for( y = 0; y < pFrame->height; y++ ) { for( x = 0; x < pFrame->width; x++, i++ ) { val = 0; for( c = 0; c < pFrame->channels; c++ ) val += pFrame->pppData[y][x][c]; val /= pFrame->channels; pData[i] = (pFrame->maxval == 255 ? (unsigned char)val : (unsigned char)((val * 255 + pFrame->maxval / 2) / pFrame->maxval)); } } return i; //return length case BlinkenProtoMcuf: if( maxLength < (int)sizeof( stBlinkenProtoMcufHdr ) + pFrame->height * pFrame->width * pFrame->channels ) //buffer too short return -1; ((stBlinkenProtoMcufHdr *)pData)->magic = htonl( BlinkenProtoMcufMagic ); //build header ((stBlinkenProtoMcufHdr *)pData)->height = htons( pFrame->height ); ((stBlinkenProtoMcufHdr *)pData)->width = htons( pFrame->width ); ((stBlinkenProtoMcufHdr *)pData)->channels = htons( pFrame->channels ); ((stBlinkenProtoMcufHdr *)pData)->maxval = htons( pFrame->maxval ); i = sizeof( stBlinkenProtoMcufHdr ); //put data into packet for( y = 0; y < pFrame->height; y++ ) for( x = 0; x < pFrame->width; x++ ) for( c = 0; c < pFrame->channels; c++, i++ ) pData[i] = pFrame->pppData[y][x][c]; return i; //return length default: return -1; } } stBlinkenFrame * BlinkenFrameFromNetwork( char * pData, int length, etBlinkenProto * pProto ) //returns protocol in *pProto if pProto not NULL { stBlinkenFrame * pFrame; int height, width, channels, maxval, y, x, c, i; if( length >= (int)sizeof( stBlinkenProtoBlpHdr ) && ((stBlinkenProtoBlpHdr *)pData)->magic == htonl( BlinkenProtoBlpMagic ) ) { if( pProto != NULL ) //return protocol *pProto = BlinkenProtoBlp; height = ntohs( ((stBlinkenProtoBlpHdr *)pData)->height ); //get header data width = ntohs( ((stBlinkenProtoBlpHdr *)pData)->width ); if( length < (int)sizeof( stBlinkenProtoBlpHdr ) + height * width ) //check length of packet return NULL; if( height < BlinkenHeightMin || height > BlinkenHeightMax || //check header data width < BlinkenWidthMin || width > BlinkenWidthMax ) return NULL; pFrame = BlinkenFrameNew( height, width, 1, 1, 0 ); //create frame according to header data if( pFrame == NULL ) return NULL; i = sizeof( stBlinkenProtoEblpHdr ); //put data into frame for( y = 0; y < pFrame->height; y++ ) for( x = 0; x < pFrame->width; x++, i++ ) pFrame->pppData[y][x][0] = pData[i]; return pFrame; } if( length >= (int)sizeof( stBlinkenProtoEblpHdr ) && ((stBlinkenProtoEblpHdr *)pData)->magic == htonl( BlinkenProtoEblpMagic ) ) { if( pProto != NULL ) //return protocol *pProto = BlinkenProtoEblp; height = ntohs( ((stBlinkenProtoEblpHdr *)pData)->height ); //get header data width = ntohs( ((stBlinkenProtoEblpHdr *)pData)->width ); if( length < (int)sizeof( stBlinkenProtoEblpHdr ) + width * height ) //check length of packet return NULL; if( height < BlinkenHeightMin || height > BlinkenHeightMax || //check header data width < BlinkenWidthMin || width > BlinkenWidthMax ) return NULL; pFrame = BlinkenFrameNew( height, width, 1, 255, 0 ); //create frame according to header data if( pFrame == NULL ) return NULL; i = sizeof( stBlinkenProtoEblpHdr ); //put data into frame for( y = 0; y < pFrame->height; y++ ) for( x = 0; x < pFrame->width; x++, i++ ) pFrame->pppData[y][x][0] = pData[i]; return pFrame; } if( length >= (int)sizeof( stBlinkenProtoMcufHdr ) && ((stBlinkenProtoMcufHdr *)pData)->magic == htonl( BlinkenProtoMcufMagic ) ) { if( pProto != NULL ) //return protocol *pProto = BlinkenProtoMcuf; height = ntohs( ((stBlinkenProtoMcufHdr *)pData)->height ); //get header data width = ntohs( ((stBlinkenProtoMcufHdr *)pData)->width ); channels = ntohs( ((stBlinkenProtoMcufHdr *)pData)->channels ); maxval = ntohs( ((stBlinkenProtoMcufHdr *)pData)->maxval ); if( length < (int)sizeof( stBlinkenProtoMcufHdr ) + height * width * channels ) //check length of packet return NULL; if( height < BlinkenHeightMin || height > BlinkenHeightMax || //check header data width < BlinkenWidthMin || width > BlinkenWidthMax || channels < BlinkenChannelsMin || channels > BlinkenChannelsMax || maxval < BlinkenMaxvalMin || maxval > BlinkenMaxvalMax ) return NULL; pFrame = BlinkenFrameNew( height, width, channels, maxval, 0 ); //create frame according to header data if( pFrame == NULL ) return NULL; i = sizeof( stBlinkenProtoMcufHdr ); //put data into frame for( y = 0; y < pFrame->height; y++ ) for( x = 0; x < pFrame->width; x++ ) for( c = 0; c < pFrame->channels; c++, i++ ) pFrame->pppData[y][x][c] = pData[i]; return pFrame; } if( pProto != NULL ) //return protocol *pProto = BlinkenProtoNone; return NULL; }