BlinkenArea - GitList
Repositories
Blog
Wiki
Blimp
Code
Commits
Branches
Tags
Search
Tree:
c1b58a7
Branches
Tags
master
1.4.4
v.1.4.3
v0.2
v0.3
v0.4
v0.5
v0.6
v1.0
v1.1
v1.2
v1.2.1
v1.3
v1.3.1
v1.3.2
v1.3.3
v1.3.4
v1.3.5
v1.3.6
v1.3.7
v1.3.8
v1.4.0
v1.4.1
v1.4.2
v1.4.4
Blimp
BlinkenFrame.java
Blimp v.1.2.1 (2006-08-01)
Christian Heimke
commited
c1b58a7
at 2011-07-15 09:18:32
BlinkenFrame.java
Blame
History
Raw
/* BlinkenLightsInteractiveMovieProgram * version 1.2.1 date 2006-08-01 * Copyright (C) 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 */ import java.awt.*; public class BlinkenFrame { private int height; private int width; private int channels; private int maxval; private int duration; private byte[][] data; BlinkenFrame( int height, int width, int channels, int maxval, int duration ) { if( height < 1 ) height = 1; if( height > 1024 ) height = 1024; if( width < 1 ) width = 1; if( width > 1024 ) width = 1024; if( channels < 1 ) channels = 1; if( channels > 16 ) channels = 16; if( maxval < 1 ) maxval = 1; if( maxval > 255 ) maxval = 255; if( duration < 1 ) duration = 1; if( duration > 65535 ) duration = 65535; this.height = height; this.width = width; this.channels = channels; this.maxval = maxval; this.duration = duration; data = new byte[height][width * channels]; } 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 < 1 ) duration = 1; if( duration > 65535 ) duration = 65535; 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[][] data; int y, x, c, i; int emptyY, emptyX, skipY, skipX, rangeY, rangeX, val, div; if( height < 1 ) height = 1; if( height > 1024 ) height = 1024; if( width < 1 ) width = 1; if( width > 1024 ) width = 1024; if( channels < 1 ) channels = 1; if( channels > 16 ) channels = 16; if( maxval < 1 ) maxval = 1; if( maxval > 255 ) maxval = 255; if( height == this.height && width == this.width && channels == this.channels && maxval == this.maxval ) return; //allocate new data array 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] = 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++ ) data[emptyY + y][destI + c] = (byte)((((int)this.data[skipY + y][srcI + c] & 0xFF) * maxval + this.maxval / 2) / this.maxval); for( ; c < channels; c++ ) data[emptyY + y][destI + c] = 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++ ) data[emptyY + y][destI + c] = (byte)((((int)this.data[skipY + y][srcI + c] & 0xFF) * maxval + this.maxval / 2) / this.maxval); for( c = channels - 1; c < this.channels; c++ ) val += (int)this.data[skipY + y][srcI + c] & 0xFF; div = this.maxval * (this.channels - channels + 1); data[emptyY + y][destI + channels - 1] = (byte)((val * maxval + div / 2) / div); } } } this.height = height; this.width = width; this.channels = channels; this.maxval = maxval; this.data = data; } public void scale( int height, int width ) { byte[][] 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 < 1 ) height = 1; if( height > 1024 ) height = 1024; if( width < 1 ) width = 1; if( width > 1024 ) width = 1024; if( height == this.height && width == this.width ) return; scaleHor = (double)width / (double)this.width; scaleVer = (double)height / (double)this.height; //allocate new data array 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 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)this.data[oyi][oxi_c] & 0xFF); } else //one line of source pixels { val = (double)((int)this.data[oyi][oxi_c] & 0xFF) * (1 - ox + oxi) + (double)((int)this.data[oyi][ox1i_c] & 0xFF) * (ox1 - ox1i); for( x_c = oxi_c + channels; x_c < ox1i_c; x_c += channels ) val += (double)((int)this.data[oyi][x_c] & 0xFF); val /= ox1 - ox; } } else //one column of source pixels { if( oxi == ox1i ) { val = (double)((int)this.data[oyi][oxi_c] & 0xFF) * (1 - oy + oyi) + (double)((int)this.data[oy1i][oxi_c] & 0xFF) * (oy1 - oy1i); for( y = oyi + 1; y < oy1i; y++ ) val += (double)((int)this.data[y][oxi_c] & 0xFF); val /= oy1 - oy; } else //rectangle of source pixels { val = (double)((int)this.data[oyi][oxi_c] & 0xFF) * (1 - oy + oyi) * (1 - ox + oxi) + (double)((int)this.data[oyi][ox1i_c] & 0xFF) * (1 - oy + oyi) * (ox1 - ox1i) + (double)((int)this.data[oy1i][oxi_c] & 0xFF) * (oy1 - oy1i) * (1 - ox + oxi) + (double)((int)this.data[oy1i][ox1i_c] & 0xFF) * (oy1 - oy1i) * (ox1 - ox1i); for( y = oyi + 1; y < oy1i; y++ ) { val += (double)((int)this.data[y][oxi_c] & 0xFF) * (1 - ox + oxi) + (double)((int)this.data[y][ox1i_c] & 0xFF) * (ox1 - ox1i); } for( x_c = oxi_c + channels; x_c < ox1i_c; x_c += channels ) { val += (double)((int)this.data[oyi][x_c] & 0xFF) * (1 - oy + oyi) + (double)((int)this.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)this.data[y][x_c] & 0xFF); val /= (oy1 - oy) * (ox1 - ox); } } data[ny][nx_c] = (byte)(int)(val + 0.5); } } //for( nx ... } //for( ny ... } //for( c ... this.height = height; this.width = width; this.data = 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 class BlinkenFrame