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
BlinkenMovie.java
Blimp v.1.2.1 (2006-08-01)
Christian Heimke
commited
c1b58a7
at 2011-07-15 09:18:32
BlinkenMovie.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.util.*; import java.util.regex.*; import java.io.*; public class BlinkenMovie { private int height; private int width; private int channels; private int maxval; private int infoCnt; private String[][] infos; private int frameCnt; private BlinkenFrame[] frames; BlinkenMovie( int height, int width, int channels, int maxval ) { 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; this.height = height; this.width = width; this.channels = channels; this.maxval = maxval; infoCnt = 0; infos = new String[0][2]; frameCnt = 0; frames = new BlinkenFrame[0]; } BlinkenMovie( BlinkenMovie movie ) { int i; height = movie.height; width = movie.width; channels = movie.channels; maxval = movie.maxval; infoCnt = 0; infos = new String[0][2]; frameCnt = 0; frames = new BlinkenFrame[0]; for( i = 0; i < movie.infoCnt; i++ ) appendInfo( new String( movie.infos[i][0] ), new String( movie.infos[i][1] ) ); for( i = 0; i < movie.frameCnt; i++ ) appendFrame( new BlinkenFrame( movie.frames[i] ) ); } public int getHeight( ) { return height; } public int getWidth( ) { return width; } public int getChannels( ) { return channels; } public int getMaxval( ) { return maxval; } public int getDuration( ) { int duration, i; duration = 0; for( i = 0; i < frameCnt; i++ ) duration += frames[i].getDuration( ); return duration; } public int getInfoCnt( ) { return infoCnt; } public String getInfoType( int infoNo ) { if( infoCnt < 1 ) return ""; if( infoNo < 0 ) infoNo = 0; if( infoNo >= infoCnt ) infoNo = infoCnt - 1; return infos[infoNo][0]; } public String getInfoData( int infoNo ) { if( infoCnt < 1 ) return ""; if( infoNo < 0 ) infoNo = 0; if( infoNo >= infoCnt ) infoNo = infoCnt - 1; return infos[infoNo][1]; } public void setInfo( int infoNo, String infoType, String infoData ) { if( infoNo < 0 || infoNo >= infoCnt ) return; infos[infoNo][0] = infoType; infos[infoNo][1] = infoData; } public void insertInfo( int infoNo, String infoType, String infoData ) { String[][] infos; int i; if( infoNo < 0 || infoNo > infoCnt ) return; infos = new String[infoCnt+1][2]; for( i = 0; i < infoNo; i++ ) { infos[i][0] = this.infos[i][0]; infos[i][1] = this.infos[i][1]; } infos[infoNo][0] = infoType; infos[infoNo][1] = infoData; for( i = infoNo; i < infoCnt; i++ ) { infos[i+1][0] = this.infos[i][0]; infos[i+1][1] = this.infos[i][1]; } this.infos = infos; infoCnt++; } public void appendInfo( String infoType, String infoData ) { insertInfo( infoCnt, infoType, infoData ); } public void deleteInfo( int infoNo ) { String[][] infos; int i; if( infoNo < 0 || infoNo >= infoCnt ) return; infos = new String[infoCnt-1][2]; for( i = 0; i < infoNo; i++ ) { infos[i][0] = this.infos[i][0]; infos[i][1] = this.infos[i][1]; } for( i = infoNo; i < infoCnt-1; i++ ) { infos[i][0] = this.infos[i+1][0]; infos[i][1] = this.infos[i+1][1]; } this.infos = infos; infoCnt--; } public void deleteInfos( ) { infos = new String[0][2]; infoCnt = 0; } public int getFrameCnt( ) { return frameCnt; } public BlinkenFrame getFrame( int frameNo ) { BlinkenFrame frame; if( frameCnt < 1 ) { frame = new BlinkenFrame( height, width, channels, maxval, 0 ); frame.clear( ); return frame; } if( frameNo < 0 ) frameNo = 0; if( frameNo >= frameCnt ) frameNo = frameCnt - 1; return frames[frameNo]; } public void setFrame( int frameNo, BlinkenFrame frame ) { if( frameNo < 0 || frameNo >= frameCnt ) return; frame.resize( height, width, channels, maxval ); frames[frameNo] = frame; } public void insertFrame( int frameNo, BlinkenFrame frame ) { BlinkenFrame[] frames; int i; if( frameNo < 0 || frameNo > frameCnt ) return; frames = new BlinkenFrame[frameCnt+1]; for( i = 0; i < frameNo; i++ ) frames[i] = this.frames[i]; frame.resize( height, width, channels, maxval ); frames[frameNo] = frame; for( i = frameNo; i < frameCnt; i++ ) frames[i+1] = this.frames[i]; this.frames = frames; frameCnt++; } public void appendFrame( BlinkenFrame frame ) { insertFrame( frameCnt, frame ); } public void deleteFrame( int frameNo ) { BlinkenFrame[] frames; int i; if( frameNo < 0 || frameNo >= frameCnt ) return; frames = new BlinkenFrame[frameCnt-1]; for( i = 0; i < frameNo; i++ ) frames[i] = this.frames[i]; for( i = frameNo; i < frameCnt-1; i++ ) frames[i] = this.frames[i+1]; this.frames = frames; frameCnt--; } public void deleteFrames( ) { frames = new BlinkenFrame[0]; frameCnt = 0; } public void resize( int height, int width, int channels, int maxval ) { int i; 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; this.height = height; this.width = width; this.channels = channels; this.maxval = maxval; for( i = 0; i < frameCnt; i++ ) frames[i].resize( height, width, channels, maxval ); } public void scale( int height, int width ) { int i; if( height < 1 ) height = 1; if( height > 1024 ) height = 1024; if( width < 1 ) width = 1; if( width > 1024 ) width = 1024; this.height = height; this.width = width; for( i = 0; i < frameCnt; i++ ) frames[i].scale( height, width ); } public String toString( ) { String str = "BlinkenMovie " + width + "x" + height + "-" + channels + "/" + (maxval + 1) + "\n"; int i; for( i = 0; i < infoCnt; i++ ) str += infos[i][0] + " = " + infos[i][1] + "\n"; for( i = 0; i < frameCnt; i++ ) str += "frame " + i + "\n" + frames[i].toString( ); return str; } public boolean loadBlm( String filename ) { Pattern header, infoLine, startOfFrame, dataLine; BufferedReader file; String line, pixel; Matcher matcher; int width, height, duration, y, x, val; BlinkenFrame frame; //initialize needed regexp patterns header = Pattern.compile( "^ *# BlinkenLights Movie ([0-9]+)x([0-9]+)" ); infoLine = Pattern.compile( "^ *# ?([A-Za-z0-9]+)(?: *= *|: *)(.*)" ); startOfFrame = Pattern.compile( "^ *@([0-9]+)" ); dataLine = Pattern.compile( " *([01])" ); //delete all frames deleteInfos( ); deleteFrames( ); resize( 0, 0, 0, 0 ); //try to read file try { //open file file = new BufferedReader( new FileReader( filename ) ); //read magic and size if( (line = file.readLine( )) != null ) { if( (matcher = header.matcher( line )).find( ) ) { width = Integer.parseInt( matcher.group( 1 ) ); height = Integer.parseInt( matcher.group( 2 ) ); resize( height, width, 1, 1 ); //create unused dummy frame for beginning frame = new BlinkenFrame( height, width, 1, 1, 0 ); y = 0; //read frames while( (line = file.readLine( )) != null ) { //info line if( (matcher = infoLine.matcher( line )).find( ) ) { appendInfo( matcher.group( 1 ), matcher.group( 2 ) ); } //start of frame else if( (matcher = startOfFrame.matcher( line )).find( ) ) { duration = Integer.parseInt( matcher.group( 1 ) ); //create new frame and append it to movie frame = new BlinkenFrame( this.height, this.width, 1, 1, duration ); frame.clear( ); appendFrame( frame ); y = 0; } //data line else if( (matcher = dataLine.matcher( line )).find( ) ) { x = 0; while( true ) { pixel = matcher.group( 1 ); val = Integer.parseInt( pixel ); frame.setPixel( y, x, 0, (byte)val ); //set pixel if( ! matcher.find( ) ) //get next pixel break; x++; //next pixel } y++; //next row } } //while( (line = ... } //if( matcher = header..matcher( ... } //if( (line = ... //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean loadBmm( String filename ) { Pattern header, infoLine, startOfFrame, dataLine; BufferedReader file; String line, pixel; Matcher matcher; int width, height, duration, y, x, val; BlinkenFrame frame; //initialize needed regexp patterns header = Pattern.compile( "^ *# BlinkenMini Movie ([0-9]+)x([0-9]+)" ); infoLine = Pattern.compile( "^ *# ?([A-Za-z0-9]+)(?: *= *|: *)(.*)" ); startOfFrame = Pattern.compile( "^ *@([0-9]+)" ); dataLine = Pattern.compile( " *(0x[0-9A-Fa-f]+|[0-9]+)" ); //delete all frames deleteInfos( ); deleteFrames( ); resize( 0, 0, 0, 0 ); //try to read file try { //open file file = new BufferedReader( new FileReader( filename ) ); //read magic and size if( (line = file.readLine( )) != null ) { if( (matcher = header.matcher( line )).find( ) ) { width = Integer.parseInt( matcher.group( 1 ) ); height = Integer.parseInt( matcher.group( 2 ) ); resize( height, width, 1, 255 ); //create unused dummy frame for beginning frame = new BlinkenFrame( height, width, 1, 255, 0 ); y = 0; //read frames while( (line = file.readLine( )) != null ) { //info line if( (matcher = infoLine.matcher( line )).find( ) ) { appendInfo( matcher.group( 1 ), matcher.group( 2 ) ); } //start of frame else if( (matcher = startOfFrame.matcher( line )).find( ) ) { duration = Integer.parseInt( matcher.group( 1 ) ); //create new frame and append it to movie frame = new BlinkenFrame( this.height, this.width, 1, 255, duration ); frame.clear( ); appendFrame( frame ); y = 0; } //data line else if( (matcher = dataLine.matcher( line )).find( ) ) { x = 0; while( true ) { pixel = matcher.group( 1 ); if( pixel.length( ) >= 2 && pixel.substring( 0, 2 ).equals( "0x" ) ) val = Integer.parseInt( pixel.substring( 2 ), 0x10 ); else val = Integer.parseInt( pixel ); frame.setPixel( y, x, 0, (byte)val ); //set pixel if( ! matcher.find( ) ) //get next pixel break; x++; //next pixel } y++; //next row } } //while( (line = ... } //if( matcher = header..matcher( ... } //if( (line = ... //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean loadBml( String filename ) { Pattern blmTag, blmHeight, blmWidth, blmChannels, blmBits; Pattern infoTitle, infoDescription, infoGeneric, infoCreator, infoAuthor, infoEmail, infoUrl; Pattern frameTag, frameDuration, rowTag, tag; BufferedReader file; String line, data, row; boolean blmTagFound; Matcher matcher, submatcher; int height, width, channels, bits, maxval, chrs, duration, y, x, c, len, i, val; BlinkenFrame frame; //initialize needed regexp patterns blmTag = Pattern.compile( "^[^<]*<blm([^>]*)>" ); blmHeight = Pattern.compile( "height=\"?([0-9]*)\"?" ); blmWidth = Pattern.compile( "width=\"?([0-9]*)\"?" ); blmChannels = Pattern.compile( "channels=\"?([0-9]*)\"?" ); blmBits = Pattern.compile( "bits=\"?([0-9]*)\"?" ); infoTitle = Pattern.compile( "^[^<]*<title>([^<]*)</title>" ); infoDescription = Pattern.compile( "[^<]*<description>([^<]*)</description>" ); infoGeneric = Pattern.compile( "^([A-Za-z0-9]+)(?: *= *|: *)(.*)" ); infoCreator = Pattern.compile( "^[^<]*<creator>([^<]*)</creator>" ); infoAuthor = Pattern.compile( "^[^<]*<author>([^<]*)</author>" ); infoEmail = Pattern.compile( "^[^<]*<email>([^<]*)</email>" ); infoUrl = Pattern.compile( "^[^<]*<url>([^<]*)</url>" ); frameTag = Pattern.compile( "^[^<]*<frame([^>]*)>" ); frameDuration = Pattern.compile( "duration=\"?([0-9]*)\"?" ); rowTag = Pattern.compile( "^[^<]*<row>([0-9A-Fa-f]*)</row>" ); tag = Pattern.compile( "^[^<]*<[^>]*>" ); //delete all frames deleteInfos( ); deleteFrames( ); resize( 0, 0, 0, 0 ); //try to read file try { //open file file = new BufferedReader( new FileReader( filename ) ); //create unused dummy frame for beginning frame = new BlinkenFrame( 0, 0, 0, 0, 0 ); y = 0; chrs = 1; //read file data = ""; blmTagFound = false; while( (line = file.readLine( )) != null ) { data += " " + line; //add new line to data //match tags while( true ) { //no blm tag yet if( ! blmTagFound ) { //blm tag if( (matcher = blmTag.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //get attributes width = 0; height = 0; channels = 1; bits = 4; maxval = 15; if( (submatcher = blmHeight.matcher( matcher.group( 1 ) )).find( ) ) //height height = Integer.parseInt( submatcher.group( 1 ) ); if( (submatcher = blmWidth.matcher( matcher.group( 1 ) )).find( ) ) //width width = Integer.parseInt( submatcher.group( 1 ) ); if( (submatcher = blmChannels.matcher( matcher.group( 1 ) )).find( ) ) //channels channels = Integer.parseInt( submatcher.group( 1 ) ); if( (submatcher = blmBits.matcher( matcher.group( 1 ) )).find( ) ) //bits maxval = (1 << (bits = Integer.parseInt( submatcher.group( 1 ) ))) - 1; //remember that blm tag was found blmTagFound = true; //set movie size resize( height, width, channels, maxval ); //get number of characters per channel chrs = (bits + 3) >> 2; } //unknown tag else if( (matcher = tag.matcher( data )).find( ) ) //remove matched part data = data.substring( matcher.end( ) ); //nothing matches else //end loop break; } //if( ! blmTagFound ) //blm tag was already found else { //title tag if( (matcher = infoTitle.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //add info to movie appendInfo( "title", matcher.group( 1 ) ); } //description tag else if( (matcher = infoDescription.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //check if generic info if( (submatcher = infoGeneric.matcher( matcher.group( 1 ) )).find( ) ) //add info to movie appendInfo( submatcher.group( 1 ), submatcher.group( 2 ) ); else //add info to movie appendInfo( "description", matcher.group( 1 ) ); } //creator tag else if( (matcher = infoCreator.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //add info to movie appendInfo( "creator", matcher.group( 1 ) ); } //author tag else if( (matcher = infoAuthor.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //add info to movie appendInfo( "author", matcher.group( 1 ) ); } //email tag else if( (matcher = infoEmail.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //add info to movie appendInfo( "email", matcher.group( 1 ) ); } //url tag else if( (matcher = infoUrl.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //add info to movie appendInfo( "url", matcher.group( 1 ) ); } //frame tag else if( (matcher = frameTag.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //get attributes duration = 0; if( (submatcher = frameDuration.matcher( matcher.group( 1 ) )).find( ) ) //duration duration = Integer.parseInt( submatcher.group( 1 ) ); //create new frame and append it to movie frame = new BlinkenFrame( this.height, this.width, this.channels, this.maxval, duration ); frame.clear( ); appendFrame( frame ); y = 0; } //row tag else if( (matcher = rowTag.matcher( data )).find( ) ) { //remove matched part data = data.substring( matcher.end( ) ); //parse row row = matcher.group( 1 ); len = row.length( ); i = 0; for( x = 0; x < this.width && i + chrs <= len; x++ ) { for( c = 0; c < this.channels && i + chrs <= len; c++, i += chrs ) { val = Integer.parseInt( row.substring( i, i + chrs ), 0x10 ); frame.setPixel( y, x, c, (byte)val ); //set pixel } } y++; //next row } //unknown tag else if( (matcher = tag.matcher( data )).find( ) ) //remove matched part data = data.substring( matcher.end( ) ); //nothing matches else //end loop break; } //if( ! blmTagFound ) ... else } //while( true ) } //while( (line = ... //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean loadBbm( String filename ) { RandomAccessFile file; byte[] header, subHeader, infoHeader, frameStartMarker, frameData; int headerMagic, headerHeight, headerWidth, headerChannels, headerMaxval; int headerFrameCnt, headerDuration, headerFramePtr; int subHeaderMagic, subHeaderSize; int frameStartMarkerMagic; StringTokenizer tokenizer; String infoType, infoData; int fileLength, frameLength; int duration, i, y, x, c; BlinkenFrame frame; //delete all frames deleteInfos( ); deleteFrames( ); resize( 0, 0, 0, 0 ); //try to read file try { //open file file = new RandomAccessFile( filename, "r" ); //read header header = new byte[24]; file.readFully( header ); headerMagic = ((int)header[0] & 0xFF) << 24 | ((int)header[1] & 0xFF) << 16 | ((int)header[2] & 0xFF) << 8 | ((int)header[3] & 0xFF); headerHeight = ((int)header[4] & 0xFF) << 8 | ((int)header[5] & 0xFF); headerWidth = ((int)header[6] & 0xFF) << 8 | ((int)header[7] & 0xFF); headerChannels = ((int)header[8] & 0xFF) << 8 | ((int)header[9] & 0xFF); headerMaxval = ((int)header[10] & 0xFF) << 8 | ((int)header[11] & 0xFF); headerFrameCnt = ((int)header[12] & 0xFF) << 24 | ((int)header[13] & 0xFF) << 16 | ((int)header[14] & 0xFF) << 8 | ((int)header[15] & 0xFF); headerDuration = ((int)header[16] & 0xFF) << 24 | ((int)header[17] & 0xFF) << 16 | ((int)header[18] & 0xFF) << 8 | ((int)header[19] & 0xFF); headerFramePtr = ((int)header[20] & 0xFF) << 24 | ((int)header[21] & 0xFF) << 16 | ((int)header[22] & 0xFF) << 8 | ((int)header[23] & 0xFF); //check magic if( headerMagic == 0x23542666 ) { //adapt movie format resize( headerHeight, headerWidth, headerChannels, headerMaxval ); //read subheaders subHeader = new byte[6]; while( file.getFilePointer( ) + 6 <= headerFramePtr ) { file.readFully( subHeader ); subHeaderMagic = ((int)subHeader[0] & 0xFF) << 24 | ((int)subHeader[1] & 0xFF) << 16 | ((int)subHeader[2] & 0xFF) << 8 | ((int)subHeader[3] & 0xFF); subHeaderSize = ((int)subHeader[4] & 0xFF) << 8 | ((int)subHeader[5] & 0xFF); //header fits into gap to frame start if( subHeaderSize >= 6 && file.getFilePointer( ) + subHeaderSize - 6 <= headerFramePtr ) { //info header if( subHeaderMagic == 0x696E666F ) //'i' 'n' 'f' 'o' { //read rest of info header infoHeader = new byte[subHeaderSize - 6]; file.readFully( infoHeader ); //parse information tokenizer = new StringTokenizer( new String( infoHeader ), "\000" ); if( tokenizer.countTokens( ) >= 2 ) { infoType = tokenizer.nextToken(); infoData = tokenizer.nextToken(); appendInfo( infoType, infoData ); } } //unknown subHeader else //skip file.skipBytes( subHeaderSize - 6 ); } //if( file.getFilePointer( ) ... } //while( file.getFilePointer( ) ... //seek to start of frames file.seek( headerFramePtr ); //read frame start marker frameStartMarker = new byte[4]; file.readFully( frameStartMarker ); frameStartMarkerMagic = ((int)frameStartMarker[0] & 0xFF) << 24 | ((int)frameStartMarker[1] & 0xFF) << 16 | ((int)frameStartMarker[2] & 0xFF) << 8 | ((int)frameStartMarker[3] & 0xFF); if( frameStartMarkerMagic == 0x66726D73 ) //'f' 'r' 'm' 's' { //read frames fileLength = (int)file.length( ); frameLength = 2 + headerHeight * headerWidth * headerChannels; frameData = new byte[frameLength]; while( file.getFilePointer( ) + frameLength <= fileLength ) { //read frame file.readFully( frameData ); duration = ((int)frameData[0] & 0xFF) << 8 | ((int)frameData[1] & 0xFF); //build frame and append it to movie frame = new BlinkenFrame( this.height, this.width, this.channels, this.maxval, duration ); i = 2; for( y = 0; y < headerHeight; y++ ) for( x = 0; x < headerWidth; x++ ) for( c = 0; c < headerChannels; c++, i++ ) frame.setPixel( y, x, c, frameData[i] ); appendFrame( frame ); } //while( file.getFilePointer ... } //if( frameStartMarkerMagic ... } //if( headerMagic ... //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean load( String filename ) { if( filename.endsWith( ".blm" ) ) return loadBlm( filename ); if( filename.endsWith( ".bmm" ) ) return loadBmm( filename ); if( filename.endsWith( ".bml" ) ) return loadBml( filename ); if( filename.endsWith( ".bbm" ) ) return loadBbm( filename ); deleteFrames( ); return false; } public boolean saveBlm( String filename ) { BlinkenMovie movie; BufferedWriter file; int cnt, i, y, x; String line; //convert movie to suitable format movie = new BlinkenMovie( this ); movie.resize( movie.height, movie.width, 1, 1 ); try { //open file file = new BufferedWriter( new FileWriter( filename ) ); //write header line file.write( "# BlinkenLights Movie " + movie.width + "x" + movie.height + "\n" ); //write information lines cnt = movie.getInfoCnt( ); for( i = 0; i < cnt; i++ ) file.write( "# " + movie.getInfoType( i ) + " = " + movie.getInfoData( i ) + "\n" ); //write frames cnt = movie.getFrameCnt( ); for( i = 0; i < cnt; i++ ) { file.write( "\n@" + movie.frames[i].getDuration( ) + "\n" ); for( y = 0; y < movie.height; y++ ) { line = ""; for( x = 0; x < movie.width; x++ ) { if( movie.frames[i].getPixel( y, x, 0 ) != 0 ) line = line + "1"; else line = line + "0"; } file.write( line + "\n" ); } } //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean saveBmm( String filename ) { BlinkenMovie movie; BufferedWriter file; int cnt, i, y, x, val; String line; //convert movie to suitable format movie = new BlinkenMovie( this ); movie.resize( movie.height, movie.width, 1, 255 ); try { //open file file = new BufferedWriter( new FileWriter( filename ) ); //write header line file.write( "# BlinkenMini Movie " + movie.width + "x" + movie.height + "\n" ); //write information lines cnt = movie.getInfoCnt( ); for( i = 0; i < cnt; i++ ) file.write( "# " + movie.getInfoType( i ) + " = " + movie.getInfoData( i ) + "\n" ); //write frames cnt = movie.getFrameCnt( ); for( i = 0; i < cnt; i++ ) { file.write( "\n@" + movie.frames[i].getDuration( ) + "\n" ); for( y = 0; y < movie.height; y++ ) { line = ""; for( x = 0; x < movie.width; x++ ) { val = (int)movie.frames[i].getPixel( y, x, 0 ) & 0xFF; if( val < 0x10 ) line = line + " 0x0" + Integer.toHexString( val ).toUpperCase( ); else line = line + " 0x" + Integer.toHexString( val ).toUpperCase( ); } file.write( line.substring( 1 ) + "\n" ); } } //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean saveBml( String filename ) { BlinkenMovie movie; BufferedWriter file; int bits, cnt, i, y, x, c, val; String infoType, infoData, line; //convert movie to suitable format movie = new BlinkenMovie( this ); val = movie.maxval; //get number of bits for( bits = 0; val != 0; val >>= 1, bits++ ); movie.resize( movie.height, movie.width, movie.channels, (1 << bits) - 1 ); try { //open file file = new BufferedWriter( new FileWriter( filename ) ); //write header line file.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); //write blm start tag file.write( "<blm width=\"" + movie.width + "\" height=\"" + movie.height + "\" bits=\"" + bits + "\" channels=\"" + movie.channels + "\">\n" ); //write information lines file.write( "\t<header>\n" ); cnt = movie.getInfoCnt( ); for( i = 0; i < cnt; i++ ) { infoType = movie.getInfoType( i ); infoData = movie.getInfoData( i ); if( infoType.equals( "title" ) ) file.write( "\t\t<title>" + infoData + "</title>\n" ); else if( infoType.equals( "description" ) ) file.write( "\t\t<description>" + infoData + "</description>\n" ); else if( infoType.equals( "creator" ) ) file.write( "\t\t<creator>" + infoData + "</creator>\n" ); else if( infoType.equals( "author" ) ) file.write( "\t\t<author>" + infoData + "</author>\n" ); else if( infoType.equals( "email" ) ) file.write( "\t\t<email>" + infoData + "</email>\n" ); else if( infoType.equals( "url" ) ) file.write( "\t\t<url>" + infoData + "</url>\n" ); else file.write( "\t\t<description>" + infoType + ": " + infoData + "</description>\n" ); } file.write( "\t</header>\n" ); //write frames cnt = movie.getFrameCnt( ); for( i = 0; i < cnt; i++ ) { file.write( "\n\t<frame duration=\"" + movie.frames[i].getDuration( ) + "\">\n" ); for( y = 0; y < movie.height; y++ ) { line = ""; for( x = 0; x < movie.width; x++ ) { for( c = 0; c < movie.channels; c++ ) { val = (int)movie.frames[i].getPixel( y, x, c ) & 0xFF; if( bits > 4 && val < 0x10 ) line = line + "0" + Integer.toHexString( val ).toUpperCase( ); else line = line + Integer.toHexString( val ).toUpperCase( ); } } file.write( "\t\t<row>" + line + "</row>\n" ); } file.write( "\t</frame>\n" ); } //write blm end tag file.write( "</blm>\n" ); //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean saveBbm( String filename ) { RandomAccessFile file; byte[] header, infoHeader, framePointer, frameStartMarker, frameData; int cnt, duration, i, j, len, y, x, c, val; String infoType, infoData, line; try { //open file file = new RandomAccessFile( filename, "rw" ); //write header header = new byte[24]; header[0] = 0x23; //magic header[1] = 0x54; header[2] = 0x26; header[3] = 0x66; header[4] = (byte)(this.height >> 8); header[5] = (byte)this.height; header[6] = (byte)(this.width >> 8); header[7] = (byte)this.width; header[8] = (byte)(this.channels >> 8); header[9] = (byte)this.channels; header[10] = (byte)(this.maxval >> 8); header[11] = (byte)this.maxval; cnt = this.getFrameCnt( ); header[12] = (byte)(cnt >> 24); header[13] = (byte)(cnt >> 16); header[14] = (byte)(cnt >> 8); header[15] = (byte)cnt; duration = 0; for( i = 0; i < cnt; i++ ) duration += this.frames[i].getDuration( ); header[16] = (byte)(duration >> 24); header[17] = (byte)(duration >> 16); header[18] = (byte)(duration >> 8); header[19] = (byte)duration; header[20] = 0; //frame pointer is written later header[21] = 0; header[22] = 0; header[23] = 0; file.write( header ); //write information cnt = this.getInfoCnt( ); for( i = 0; i < cnt; i++ ) { infoType = this.getInfoType( i ); if( infoType.length( ) > 32760 ) infoType = infoType.substring( 0, 32760 ); infoData = this.getInfoData( i ); if( infoData.length( ) > 32760 ) infoData = infoData.substring( 0, 32760 ); len = 8 + infoType.length( ) + infoData.length( ); infoHeader = new byte[6]; infoHeader[0] = 0x69; //'i' infoHeader[1] = 0x6E; //'n' infoHeader[2] = 0x66; //'f' infoHeader[3] = 0x6F; //'o' infoHeader[4] = (byte)(len >> 8); infoHeader[5] = (byte)len; file.write( infoHeader ); file.write( (infoType + "\000" + infoData + "\000").getBytes( ) ); } //write frame pointer framePointer = new byte[4]; val = (int)file.getFilePointer( ); framePointer[0] = (byte)(val >> 24); framePointer[1] = (byte)(val >> 16); framePointer[2] = (byte)(val >> 8); framePointer[3] = (byte)val; file.seek( 20 ); file.write( framePointer ); file.seek( val ); //write frame start marker frameStartMarker = new byte[4]; frameStartMarker[0] = 0x66; //'f' frameStartMarker[1] = 0x72; //'r' frameStartMarker[2] = 0x6D; //'m' frameStartMarker[3] = 0x73; //'s' file.write( frameStartMarker ); //write frames len = 2 + this.height * this.width * this.channels; frameData = new byte[len]; cnt = this.getFrameCnt( ); for( i = 0; i < cnt; i++ ) { val = this.frames[i].getDuration( ); frameData[0] = (byte)(val >> 8); frameData[1] = (byte)val; for( j = 2, y = 0; y < this.height; y++ ) for( x = 0; x < this.width; x++ ) for( c = 0; c < this.channels; c++, j++ ) frameData[j] = this.frames[i].getPixel( y, x, c ); file.write( frameData ); } //close file file.close( ); //success return true; } catch( IOException e ) { } //some error return false; } public boolean save( String filename ) { if( filename.endsWith( ".blm" ) ) return saveBlm( filename ); if( filename.endsWith( ".bmm" ) ) return saveBmm( filename ); if( filename.endsWith( ".bml" ) ) return saveBml( filename ); if( filename.endsWith( ".bbm" ) ) return saveBbm( filename ); return false; } } //public class BlinkenMovie