BlinkenArea - GitList
Repositories
Blog
Wiki
BlinkenLibJava
Code
Commits
Branches
Tags
Search
Tree:
b39aac5
Branches
Tags
master
v0.1.1
v0.1.2
v0.1.3
v0.1.4
v0.1.5
BlinkenLibJava
org
blinkenarea
BlinkenLib
BlinkenFrame.java
removed version information from source files (not needed with git)
Stefan Schuermans
commited
b39aac5
at 2011-09-10 16:17:50
BlinkenFrame.java
Blame
History
Raw
/* BlinkenLib * Copyright (C) 2004-2011: Stefan Schuermans <stefan@schuermans.info> * Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html * a blinkenarea.org project */ package org.blinkenarea.BlinkenLib; import java.awt.*; import org.blinkenarea.BlinkenLib.*; public class BlinkenFrame { private static byte [] BlinkenProtoBlpMagic = {(byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF}; private static byte [] BlinkenProtoEblpMagic = {(byte)0xFE, (byte)0xED, (byte)0xBE, (byte)0xEF}; private static byte [] BlinkenProtoMcufMagic = {(byte)0x23, (byte)0x54, (byte)0x26, (byte)0x66}; private int height; private int width; private int channels; private int maxval; private int duration; private byte[][] data; public BlinkenFrame( int height, int width, int channels, int maxval, int duration ) { if( height < BlinkenConstants.BlinkenHeightMin ) height = BlinkenConstants.BlinkenHeightMin; if( height > BlinkenConstants.BlinkenHeightMax ) height = BlinkenConstants.BlinkenHeightMax; if( width < BlinkenConstants.BlinkenWidthMin ) width = BlinkenConstants.BlinkenWidthMin; if( width > BlinkenConstants.BlinkenWidthMax ) width = BlinkenConstants.BlinkenWidthMax; if( channels < BlinkenConstants.BlinkenChannelsMin ) channels = BlinkenConstants.BlinkenChannelsMin; if( channels > BlinkenConstants.BlinkenChannelsMax ) channels = BlinkenConstants.BlinkenChannelsMax; if( maxval < BlinkenConstants.BlinkenMaxvalMin ) maxval = BlinkenConstants.BlinkenMaxvalMin; if( maxval > BlinkenConstants.BlinkenMaxvalMax ) maxval = BlinkenConstants.BlinkenMaxvalMax; if( duration < BlinkenConstants.BlinkenDurationMin ) duration = BlinkenConstants.BlinkenDurationMin; if( duration > BlinkenConstants.BlinkenDurationMax ) duration = BlinkenConstants.BlinkenDurationMax; this.height = height; this.width = width; this.channels = channels; this.maxval = maxval; this.duration = duration; data = new byte[height][width * channels]; } public BlinkenFrame( BlinkenFrame frame ) { int y, x, c, i; height = frame.height; width = frame.width; channels = frame.channels; maxval = frame.maxval; duration = frame.duration; data = new byte[height][width * channels]; for( y = 0; y < height; y++ ) for( x = 0, i = 0; x < width; x++ ) for( c = 0; c < channels; c++, i++ ) data[y][i] = frame.data[y][i]; } public void clear( ) { int x, y, c, i; for( y = 0; y < height; y++ ) for( x = 0, i = 0; x < width; x++ ) for( c = 0; c < channels; c++, i++ ) data[y][i] = 0; } public int getHeight( ) { return height; } public int getWidth( ) { return width; } public int getChannels( ) { return channels; } public int getMaxval( ) { return maxval; } public int getDuration( ) { return duration; } public void setDuration( int duration ) { if( duration < BlinkenConstants.BlinkenDurationMin ) duration = BlinkenConstants.BlinkenDurationMin; if( duration > BlinkenConstants.BlinkenDurationMax ) duration = BlinkenConstants.BlinkenDurationMax; this.duration = duration; } public byte getPixel( int y, int x, int c ) { if( y < 0 || y >= height || x < 0 || x >= width || c < 0 || c >= channels ) return 0; return data[y][x * channels + c]; } public void setPixel( int y, int x, int c, byte val ) { if( y < 0 || y >= height || x < 0 || x >= width || c < 0 || c >= channels ) return; if( val > maxval ) val = (byte)maxval; data[y][x * channels + c] = val; } public Color getColor( int y, int x ) { if( y < 0 || y >= height || x < 0 || x >= width || channels < 1 ) return new Color( 0, 0, 0 ); if( channels == 1 ) return new Color( (((int)data[y][x * 1 + 0] & 0xFF) * 255 + maxval / 2) / maxval, (((int)data[y][x * 1 + 0] & 0xFF) * 255 + maxval / 2) / maxval, (((int)data[y][x * 1 + 0] & 0xFF) * 255 + maxval / 2) / maxval ); if( channels == 2 ) return new Color( (((int)data[y][x * 2 + 0] & 0xFF) * 255 + maxval / 2) / maxval, (((int)data[y][x * 2 + 1] & 0xFF) * 255 + maxval / 2) / maxval, 0 ); int i = x * channels; return new Color( (((int)data[y][i + 0] & 0xFF) * 255 + maxval / 2) / maxval, (((int)data[y][i + 1] & 0xFF) * 255 + maxval / 2) / maxval, (((int)data[y][i + 2] & 0xFF) * 255 + maxval / 2) / maxval ); } public void setColor( int y, int x, Color color ) { int alpha, alpha_, c; if( y < 0 || y >= height || x < 0 || x >= width ) return; int i = x * channels; alpha = color.getAlpha( ); alpha_ = 255 - alpha; if( channels >= 1 ) data[y][i + 0] = (byte)(( ((color.getRed( ) * maxval + 127) / 255) * alpha + ((int)data[y][i + 0] & 0xFF) * alpha_ ) / 255); if( channels >= 2 ) data[y][i + 1] = (byte)(( ((color.getGreen( ) * maxval + 127) / 255) * alpha + ((int)data[y][i + 1] & 0xFF) * alpha_ ) / 255); if( channels >= 3 ) data[y][i + 2] = (byte)(( ((color.getBlue( ) * maxval + 127) / 255) * alpha + ((int)data[y][i + 2] & 0xFF) * alpha_ ) / 255); for( c = 3; c < channels; c++ ) data[y][i + c] = (byte)(( 0 + ((int)data[y][i + c] & 0xFF) * alpha_ ) / 255); } public void resize( int height, int width, int channels, int maxval ) { byte[][] new_data; int y, x, c, i; int emptyY, emptyX, skipY, skipX, rangeY, rangeX, val, div; if( height < BlinkenConstants.BlinkenHeightMin ) height = BlinkenConstants.BlinkenHeightMin; if( height > BlinkenConstants.BlinkenHeightMax ) height = BlinkenConstants.BlinkenHeightMax; if( width < BlinkenConstants.BlinkenWidthMin ) width = BlinkenConstants.BlinkenWidthMin; if( width > BlinkenConstants.BlinkenWidthMax ) width = BlinkenConstants.BlinkenWidthMax; if( channels < BlinkenConstants.BlinkenChannelsMin ) channels = BlinkenConstants.BlinkenChannelsMin; if( channels > BlinkenConstants.BlinkenChannelsMax ) channels = BlinkenConstants.BlinkenChannelsMax; if( maxval < BlinkenConstants.BlinkenMaxvalMin ) maxval = BlinkenConstants.BlinkenMaxvalMin; if( maxval > BlinkenConstants.BlinkenMaxvalMax ) maxval = BlinkenConstants.BlinkenMaxvalMax; if( height == this.height && width == this.width && channels == this.channels && maxval == this.maxval ) return; //allocate new data array new_data = new byte[height][width * channels]; for( y = 0; y < height; y++ ) for( x = 0, i = 0; x < width; x++ ) for( c = 0; c < channels; c++, i++ ) new_data[y][i] = 0; //get number of pixels to skip / to leave empty in X and Y direction if( height > this.height ) { emptyY = (height - this.height) / 2; skipY = 0; rangeY = this.height; } else { emptyY = 0; skipY = (this.height - height) / 2; rangeY = height; } if( width > this.width ) { emptyX = (width - this.width) / 2; skipX = 0; rangeX = this.width; } else { emptyX = 0; skipX = (this.width - width) / 2; rangeX = width; } //resize frame with help of calculated parameters for( y = 0; y < rangeY; y++ ) { for( x = 0; x < rangeX; x++ ) { int srcI = (skipX + x) * this.channels; int destI = (emptyX + x) * channels; if( channels >= this.channels ) //add channels: copy last channel into new channels { for( c = 0; c < this.channels; c++ ) new_data[emptyY + y][destI + c] = (byte)((((int)data[skipY + y][srcI + c] & 0xFF) * maxval + this.maxval / 2) / this.maxval); for( ; c < channels; c++ ) new_data[emptyY + y][destI + c] = new_data[emptyY + y][destI + this.channels - 1]; } else //remove channels: merge leftover channels with last kept channel { val = 0; for( c = 0; c < channels - 1; c++ ) new_data[emptyY + y][destI + c] = (byte)((((int)data[skipY + y][srcI + c] & 0xFF) * maxval + this.maxval / 2) / this.maxval); for( c = channels - 1; c < this.channels; c++ ) val += (int)data[skipY + y][srcI + c] & 0xFF; div = this.maxval * (this.channels - channels + 1); new_data[emptyY + y][destI + channels - 1] = (byte)((val * maxval + div / 2) / div); } } } this.height = height; this.width = width; this.channels = channels; this.maxval = maxval; data = new_data; } public void scale( int height, int width ) { byte[][] new_data; double scaleHor, scaleVer, ox, oy, ox1, oy1, val; int c, nx, nx_c, ny, x, x_c, y, oxi, oxi_c, oyi, ox1i, ox1i_c, oy1i; if( height < BlinkenConstants.BlinkenHeightMin ) height = BlinkenConstants.BlinkenHeightMin; if( height > BlinkenConstants.BlinkenHeightMax ) height = BlinkenConstants.BlinkenHeightMax; if( width < BlinkenConstants.BlinkenWidthMin ) width = BlinkenConstants.BlinkenWidthMin; if( width > BlinkenConstants.BlinkenWidthMax ) width = BlinkenConstants.BlinkenWidthMax; if( height == this.height && width == this.width ) return; scaleHor = (double)width / (double)this.width; scaleVer = (double)height / (double)this.height; //allocate new data array new_data = new byte[height][width * channels]; //scale every channel for( c = 0; c < channels; c++ ) { for( ny = 0; ny < height; ny++ ) { for( nx = 0, nx_c = c; nx < width; nx++, nx_c += channels ) { 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 >= this.height || ox1 >= this.width) //out of old picture new_data[ny][nx_c] = 0; else { oyi = (int)oy; oxi = (int)ox; oxi_c = oxi * channels + c; oy1i = (int)oy1; ox1i = (int)ox1; ox1i_c = ox1i * channels + c; if( oyi == oy1i ) { if( oxi == ox1i) //one source pixel { val = (double)((int)data[oyi][oxi_c] & 0xFF); } else //one line of source pixels { val = (double)((int)data[oyi][oxi_c] & 0xFF) * (1 - ox + oxi) + (double)((int)data[oyi][ox1i_c] & 0xFF) * (ox1 - ox1i); for( x_c = oxi_c + channels; x_c < ox1i_c; x_c += channels ) val += (double)((int)data[oyi][x_c] & 0xFF); val /= ox1 - ox; } } else //one column of source pixels { if( oxi == ox1i ) { val = (double)((int)data[oyi][oxi_c] & 0xFF) * (1 - oy + oyi) + (double)((int)data[oy1i][oxi_c] & 0xFF) * (oy1 - oy1i); for( y = oyi + 1; y < oy1i; y++ ) val += (double)((int)data[y][oxi_c] & 0xFF); val /= oy1 - oy; } else //rectangle of source pixels { val = (double)((int)data[oyi][oxi_c] & 0xFF) * (1 - oy + oyi) * (1 - ox + oxi) + (double)((int)data[oyi][ox1i_c] & 0xFF) * (1 - oy + oyi) * (ox1 - ox1i) + (double)((int)data[oy1i][oxi_c] & 0xFF) * (oy1 - oy1i) * (1 - ox + oxi) + (double)((int)data[oy1i][ox1i_c] & 0xFF) * (oy1 - oy1i) * (ox1 - ox1i); for( y = oyi + 1; y < oy1i; y++ ) { val += (double)((int)data[y][oxi_c] & 0xFF) * (1 - ox + oxi) + (double)((int)data[y][ox1i_c] & 0xFF) * (ox1 - ox1i); } for( x_c = oxi_c + channels; x_c < ox1i_c; x_c += channels ) { val += (double)((int)data[oyi][x_c] & 0xFF) * (1 - oy + oyi) + (double)((int)data[oy1i][x_c] & 0xFF) * (oy1 - oy1i); } for( y = oyi + 1; y < oy1i; y++ ) for( x_c = oxi_c + channels; x_c < ox1i_c; x_c += channels ) val += (double)((int)data[y][x_c] & 0xFF); val /= (oy1 - oy) * (ox1 - ox); } } new_data[ny][nx_c] = (byte)(int)(val + 0.5); } } //for( nx ... } //for( ny ... } //for( c ... this.height = height; this.width = width; data = new_data; } public String toString( ) { String str = ""; int h, w, c, i, val; for( h = 0; h < height; h++ ) { for( w = 0, i = 0; w < width; w++ ) { val = 0; for( val = 0, c = 0; c < channels; c++, i++ ) val += ((int)data[h][i] & 0xFF); val = val * 7 / maxval / channels; str = str + " -+*%#&@".substring( val, val + 1); } str = str + "\n"; } return str + duration + " ms\n"; } public byte [] toNetwork( int/*BlinkenProto*/ proto ) { byte [] netData; if( proto == BlinkenConstants.BlinkenProtoNone ) { return new byte [0]; } if( proto == BlinkenConstants.BlinkenProtoBlp ) { netData = new byte[12 + height * width]; //allocate buffer for frame netData[0] = BlinkenProtoBlpMagic[0]; //magic netData[1] = BlinkenProtoBlpMagic[1]; netData[2] = BlinkenProtoBlpMagic[2]; netData[3] = BlinkenProtoBlpMagic[3]; netData[4] = 0; //frameNo netData[5] = 0; netData[6] = 0; netData[7] = 0; netData[8] = (byte)(width >> 8 & 0xFF); //width netData[9] = (byte)(width & 0xFF); netData[10] = (byte)(height >> 8 & 0xFF); //height netData[11] = (byte)(height & 0xFF); for( int i = 12, y = 0; y < height; y++ ) { for( int x = 0, j = 0; x < width; x++, i++ ) { int val = 0; for( int c = 0; c < channels; c++, j++ ) val += (int)data[y][j] & 0xFF; netData[i] = (byte)(val >= channels * maxval / 2 ? 0x01 : 0x00); } } return netData; } if( proto == BlinkenConstants.BlinkenProtoEblp ) { netData = new byte[12 + height * width]; //allocate buffer for frame netData[0] = BlinkenProtoEblpMagic[0]; //magic netData[1] = BlinkenProtoEblpMagic[1]; netData[2] = BlinkenProtoEblpMagic[2]; netData[3] = BlinkenProtoEblpMagic[3]; netData[4] = 0; //frameNo netData[5] = 0; netData[6] = 0; netData[7] = 0; netData[8] = (byte)(width >> 8 & 0xFF); //width netData[9] = (byte)(width & 0xFF); netData[10] = (byte)(height >> 8 & 0xFF); //height netData[11] = (byte)(height & 0xFF); for( int i = 12, y = 0; y < height; y++ ) { for( int x = 0, j = 0; x < width; x++, i++ ) { int val = 0; for( int c = 0; c < channels; c++, j++ ) val += (int)data[y][j] & 0xFF; val /= channels; netData[i] = (byte)(maxval == 255 ? val : (val * 255 + maxval / 2) / maxval); } } return netData; } if( proto == BlinkenConstants.BlinkenProtoMcuf ) { netData = new byte[12 + height * width * channels]; //allocate buffer for frame netData[0] = BlinkenProtoMcufMagic[0]; //magic netData[1] = BlinkenProtoMcufMagic[1]; netData[2] = BlinkenProtoMcufMagic[2]; netData[3] = BlinkenProtoMcufMagic[3]; netData[4] = (byte)(height >> 8 & 0xFF); //height netData[5] = (byte)(height & 0xFF); netData[6] = (byte)(width >> 8 & 0xFF); //width netData[7] = (byte)(width & 0xFF); netData[8] = (byte)(channels >> 8 & 0xFF); //channels netData[9] = (byte)(channels & 0xFF); netData[10] = (byte)(maxval >> 8 & 0xFF); //maxval netData[11] = (byte)(maxval & 0xFF); for( int i = 12, y = 0; y < height; y++ ) for( int x = 0, j = 0; x < width; x++ ) for( int c = 0; c < channels; c++, i++, j++ ) netData[i] = data[y][j]; return netData; } return new byte [0]; } public int/*BlinkenProto*/ fromNetwork( byte [] netData ) { if( netData.length >= 12 && netData[0] == BlinkenProtoBlpMagic[0] && netData[1] == BlinkenProtoBlpMagic[1] && netData[2] == BlinkenProtoBlpMagic[2] && netData[3] == BlinkenProtoBlpMagic[3] ) { int netWidth = ((int)netData[8] & 0xFF) << 8 | ((int)netData[9] & 0xFF); //get header data int netHeight = ((int)netData[10] & 0xFF) << 8 | ((int)netData[11] & 0xFF); if( netData.length < 12 + netHeight * netWidth ) //check length of data return BlinkenConstants.BlinkenProtoNone; if( netHeight < BlinkenConstants.BlinkenHeightMin || netHeight > BlinkenConstants.BlinkenHeightMax || //check header data netWidth < BlinkenConstants.BlinkenWidthMin || netWidth > BlinkenConstants.BlinkenWidthMax ) return BlinkenConstants.BlinkenProtoNone; height = netHeight; //set frame to header data width = netWidth; channels = 1; maxval = 1; duration = BlinkenConstants.BlinkenDurationMin; data = new byte[height][width * channels]; for( int i = 12, y = 0; y < height; y++ ) //put data into frame for( int x = 0; x < width; x++, i++ ) data[y][x] = (byte)(netData[i] != 0 ? 0x01 : 0x00); return BlinkenConstants.BlinkenProtoBlp; } if( netData.length >= 12 && netData[0] == BlinkenProtoEblpMagic[0] && netData[1] == BlinkenProtoEblpMagic[1] && netData[2] == BlinkenProtoEblpMagic[2] && netData[3] == BlinkenProtoEblpMagic[3] ) { int netWidth = ((int)netData[8] & 0xFF) << 8 | ((int)netData[9] & 0xFF); //get header data int netHeight = ((int)netData[10] & 0xFF) << 8 | ((int)netData[11] & 0xFF); if( netData.length < 12 + netHeight * netWidth ) //check length of data return BlinkenConstants.BlinkenProtoNone; if( netHeight < BlinkenConstants.BlinkenHeightMin || netHeight > BlinkenConstants.BlinkenHeightMax || //check header data netWidth < BlinkenConstants.BlinkenWidthMin || netWidth > BlinkenConstants.BlinkenWidthMax ) return BlinkenConstants.BlinkenProtoNone; height = netHeight; //set frame to header data width = netWidth; channels = 1; maxval = 255; duration = BlinkenConstants.BlinkenDurationMin; data = new byte[height][width * channels]; for( int i = 12, y = 0; y < height; y++ ) //put data into frame for( int x = 0; x < width; x++, i++ ) data[y][x] = netData[i]; return BlinkenConstants.BlinkenProtoEblp; } if( netData.length >= 12 && netData[0] == BlinkenProtoMcufMagic[0] && netData[1] == BlinkenProtoMcufMagic[1] && netData[2] == BlinkenProtoMcufMagic[2] && netData[3] == BlinkenProtoMcufMagic[3] ) { int netHeight = ((int)netData[4] & 0xFF) << 8 | ((int)netData[5] & 0xFF); //get header data int netWidth = ((int)netData[6] & 0xFF) << 8 | ((int)netData[7] & 0xFF); int netChannels = ((int)netData[8] & 0xFF) << 8 | ((int)netData[9] & 0xFF); int netMaxval = ((int)netData[10] & 0xFF) << 8 | ((int)netData[11] & 0xFF); if( netData.length < 12 + netHeight * netWidth * netChannels ) //check length of data return BlinkenConstants.BlinkenProtoNone; if( netHeight < BlinkenConstants.BlinkenHeightMin || netHeight > BlinkenConstants.BlinkenHeightMax || //check header data netWidth < BlinkenConstants.BlinkenWidthMin || netWidth > BlinkenConstants.BlinkenWidthMax || netChannels < BlinkenConstants.BlinkenChannelsMin || netChannels > BlinkenConstants.BlinkenChannelsMax || netMaxval < BlinkenConstants.BlinkenMaxvalMin || netMaxval > BlinkenConstants.BlinkenMaxvalMax ) return BlinkenConstants.BlinkenProtoNone; height = netHeight; //set frame to header data width = netWidth; channels = netChannels; maxval = netMaxval; duration = BlinkenConstants.BlinkenDurationMin; data = new byte[height][width * channels]; for( int i = 12, y = 0; y < height; y++ ) //put data into frame for( int x = 0, j = 0; x < width; x++ ) for( int c = 0; c < channels; c++, i++, j++ ) data[y][j] = netData[i]; return BlinkenConstants.BlinkenProtoMcuf; } return BlinkenConstants.BlinkenProtoNone; } } //public class BlinkenFrame