don't depend on sharedrawweb

use directly sharedrawweb java code here

Signed-off-by: philippe lhardy <philippe.lhardy@astrolabe.coop>
This commit is contained in:
2025-11-02 18:03:10 +01:00
parent e78da6ec76
commit 36e58808d5
16 changed files with 1383 additions and 13 deletions

View File

@@ -13,7 +13,6 @@
<!-- Fill me please / todo
see fetch_dependencies
-->
<property name="artgraphicslib" value="artgaphics-0.2.0"/>
<property name="zstd-jnilib" value="zstd-jni-1.5.2-2"/>
<target name="gather_project_params">
<!-- original source parameter is in project_params project_version -->
@@ -41,7 +40,7 @@
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}" includeantruntime="false" classpath="libs/${artgraphicslib}.jar:libs/${zstd-jnilib}.jar">
<javac srcdir="${src}" destdir="${build}" includeantruntime="false" classpath="libs/${zstd-jnilib}.jar">
<exclude name="org/artisanlogiciel/games/javafx/*"/>
<compilerarg value="-Xlint:deprecation,unchecked" />
</javac>

View File

@@ -52,7 +52,10 @@ do
use_jackson=$1
;;
use_zstd)
use_zstd=1
use_zstd=$1
;;
use_artgraphic)
use_artgraphic=$1
;;
*)
parsemetaarg "$1"
@@ -73,18 +76,19 @@ then
$metarun mkdir libs
fi
libversion_artgaphic=0.2.0
lib_artgaphic=artgaphics-${libversion_artgaphic}.jar
if [[ ! -e libs/$lib_artgaphic ]]
if [[ -n $user_artgraphic ]]
then
lib_artgaphic_source_file=sharedrawweb/dist/lib/$lib_artgaphic
if [[ -f $lib_artgaphic_source_file ]]
if [[ ! -e libs/$lib_artgaphic ]]
then
# ../ since libs is one level below current project
$metarun ln -s ../$lib_artgaphic_source_file libs/
else
log_error "Missing $lib_artgaphic_source_file"
log_info "It is required to build sharedrawweb project first"
lib_artgaphic_source_file=sharedrawweb/dist/lib/$lib_artgaphic
if [[ -f $lib_artgaphic_source_file ]]
then
# ../ since libs is one level below current project
$metarun ln -s ../$lib_artgaphic_source_file libs/
else
log_error "Missing $lib_artgaphic_source_file"
log_info "It is required to build sharedrawweb project first"
fi
fi
fi

View File

@@ -0,0 +1,92 @@
package org.artisanlogiciel.compression;
import java.io.DataInputStream;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.artisanlogiciel.graphics.SvgWriter;
import org.artisanlogiciel.graphics.Drawing;
/**
* Very simple utility to convert from .imc to svg.
*
* TODO : could be more clever and not load full image into memory to save it afterwards ( for very small embedded systems ).
*/
public class Main
{
Drawing mLocalImage;
public static void main(String[] args) {
Main m = new Main();
if ( args.length > 1 )
{
m.loadExpanded(args[0]);
try {
File out = new File(args[1]);
if (out.exists())
{
System.err.println("File already exists" + out + " Not overriding it");
}
else
{
//m.saveSvg(new DataOutputStream(new FileOutputStream(out)));
FileOutputStream fout = new FileOutputStream(out);
m.saveSvg(fout);
fout.flush();
fout.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
else
{
System.out.println("Very simple utility to convert from .imc to svg.");
System.out.println("first argument is compressed file, second is svg output file (should not already exist)");
}
}
public void saveSvg(OutputStream s)
throws IOException
{
SvgWriter writer = new SvgWriter(mLocalImage.getLines());
writer.writeTo(s);
}
public void saveKompressed( String ref) {
try {
FileOutputStream fi = new FileOutputStream( ref);
mLocalImage.saveLinesKompressed( new DataOutputStream( fi));
}
catch( java.io.FileNotFoundException fnfe)
{
fnfe.printStackTrace(System.err);
}
catch ( java.io.IOException ioe) {
ioe.printStackTrace(System.err);
}
}
public void loadExpanded( String ref) {
try {
FileInputStream fi = new FileInputStream( ref);
mLocalImage = new Drawing();
mLocalImage.loadLinesExpanded( new DataInputStream( fi));
}
catch( java.io.FileNotFoundException fnfe) {
fnfe.printStackTrace(System.err);
}
catch ( java.io.IOException ioe) {
ioe.printStackTrace(System.err);
}
}
}

View File

@@ -0,0 +1,146 @@
/*
This file is part of ShareDrawWeb.
ShareDrawWeb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ShareDrawWeb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ShareDrawWeb; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.artisanlogiciel.compression.graphics;
/*
simple class to read bitfields
@see BitFieldWriter
@author Philippe Lhardy
*/
import java.io.*;
class BitFieldReader {
// size of nextWord
final int dataSize = 32;
/* offset of next bit to be read in current word
should ensure bitOffset < dataSize
*/
private int bitOffset = 0;
/* word used waiting to be fully read
dataSize is bit size of currentWord
currentWord is part of word read that begins at bitOffset.
*/
private int currentWord = 0;
private DataInputStream inputStream;
/* value returned is an int between 0 and 2^bits-1 */
public int read( int bits) throws java.io.IOException {
int field = 0;
int head = 0;
// a new word is needed
if ( bitOffset == 0 ) {
nextWord();
}
// if more bits needed that word currently used.
if ( bits + bitOffset > dataSize) {
// warning recursive call ( not terminal )
int bitsize = dataSize - bitOffset;
head = read( dataSize - bitOffset);
// current word had entirely been read, need a new one
// don't do that... nextWord() will be done by next read...
field = read( bits - bitsize);
// reconstruct all
// more significant bits in first word, least in last
field = field | ( head << (bits - bitsize));
}
else {
// terminal part do the job
if ( bits == dataSize) {
// special case to keep sign
field = currentWord;
currentWord = 0;
bitOffset = 0;
}
else {
field = ( currentWord >> ( dataSize - bits) )
& ( 0x7fffffff >> ( dataSize - 1 - bits) );
// bits are read then remove them from currentWord
currentWord <<= bits;
bitOffset = ( bitOffset + bits ) % dataSize;
/*
System.out.println( "size " + Integer.toString(bits)
+ " value " + Integer.toString(field)
+ " offset " + Integer.toString(bitOffset)
+ " currentWord " + Integer.toString( currentWord)
);
*/
}
}
return field;
}
private int getInt( byte[] pBytes)
{
long field = 0;
field = pBytes[0]<<24 | pBytes[1]<<16 | pBytes[2]<<8 | pBytes[3];
return (int) field;
}
/**
* doesn't work correctly as readInt
*/
private int readInt()
throws IOException
{
byte bytes[]=new byte[4];
int nr=0;
int index = 0;
/* read at least 4 bytes */
while ( ( nr != -1) && ( index < 4 ) )
{
nr = inputStream.read( bytes, index, 4 - index);
index +=nr;
}
return getInt( bytes);
}
private void nextWord() throws java.io.IOException {
// read next word
// currentWord = readInt();
currentWord= inputStream.readInt();
bitOffset = 0;
}
/*
go to next entire word.
*/
public void padToWord() throws java.io.IOException {
if ( bitOffset != 0) {
nextWord();
}
}
/* set InputStream */
public void setInputStream( InputStream input) {
inputStream = new DataInputStream(input);
}
}

View File

@@ -0,0 +1,125 @@
/*
This file is part of ShareDrawWeb.
ShareDrawWeb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ShareDrawWeb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ShareDrawWeb; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.artisanlogiciel.compression.graphics;
/*
simple class to write bitfields
@see BitFieldReader
@author Philippe Lhardy
*/
import java.io.*;
class BitFieldWriter {
// size of nextWord
final int dataSize = 32;
/* bitOffset is number of bits already used in word
should ensure bitOffset < dataSize
*/
private int bitOffset;
/* word used waiting to be filled to be written
dataSize is bit size of nextWord
*/
private int nextWord;
private DataOutputStream outputStream;
public void write( int field, int bits) throws java.io.IOException {
// if more bits needed that word currently used.
if ( bits + bitOffset > dataSize) {
// warning recursive call ( not terminal )
// fill and write current word
int bitsize = dataSize - bitOffset;
int head;
// most significant bits first
// suppress at left least significant bits
head = field >> (bits - bitsize);
write( head, dataSize - bitOffset);
// no need of newWord() previous write already done it
// least significant bits last
field = field & ( 0x7FFFFFFF >> ( bitsize - 1));
write( field, bits - bitsize);
}
else {
if ( bits == dataSize ) {
// special case to keep sign
nextWord = field;
bitOffset = 0;
}
else {
// keep only meaning part of field
field = field & ( 0x7FFFFFFF >> ( dataSize - 1 - bits));
nextWord = nextWord | ( field << ( dataSize - bits - bitOffset));
bitOffset = ( bitOffset + bits ) % dataSize;
}
// a new word is needed
if ( bitOffset == 0 ) {
newWord();
}
}
/*
System.out.println( "nextWord " + Integer.toString( nextWord) + " size "
+ Integer.toString( bits) + " field " + Integer.toString( field));
*/
}
/**
* seems to works correctly as DataOutputStream.writeInt()
*/
private void writeInt( int i)
throws IOException
{
long j = i;
byte bytes[]=new byte[4];
bytes[0] = (byte) ((j & 0xFF000000) >> 24);
bytes[1] = (byte) ((j & 0x00FF0000) >> 16);
bytes[2] = (byte) ((j & 0x0000FF00) >> 8);
bytes[3] = (byte) (j & 0x000000FF);
outputStream.write( bytes, 0, 4);
}
private void newWord() throws java.io.IOException {
// do really write current word;
//writeInt( nextWord);
outputStream.writeInt(nextWord);
// reset nextWord
bitOffset = 0;
nextWord = 0;
}
/*
write all current datas if any
to have a clean word ready.
*/
public void padToWord() throws java.io.IOException {
if ( bitOffset != 0) {
newWord();
}
}
/* set OutputStream */
public void setOutputStream( OutputStream output) {
outputStream = new DataOutputStream(output);
}
}

View File

@@ -0,0 +1,149 @@
/*
This file is part of ShareDrawWeb.
ShareDrawWeb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ShareDrawWeb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ShareDrawWeb; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
DrawingLineExpander
decompress a draw line from a stream
main algorithm is to code only delta displacement in littlest possible size.
*/
package org.artisanlogiciel.compression.graphics;
import java.awt.Point;
import java.io.InputStream;
import java.util.ArrayList;
public class DrawLineExpander {
ArrayList<Point> expandedLines;
int currentSize;
int scode[] = {3,6,14,30,64};
final static int SCODE_MAX = 4;
private BitFieldReader fieldReader = null;
public DrawLineExpander() {
expandedLines = new ArrayList<>();
fieldReader = new BitFieldReader();
}
/* create a List of points */
public ArrayList<Point> expand( InputStream input ) throws java.io.IOException {
fieldReader.setInputStream( input);
int point_count = fieldReader.read( 32);
// System.out.println( point_count);
expandedLines.add( readAbs( 64));
for ( int i = 1; i < point_count; i ++ ) {
Point point = readRel();
if ( currentSize == 64 ) {
// absolute
expandedLines.add( point);
}
else {
// relative
Point previous = (Point) expandedLines.get(expandedLines.size()-1);
point.x = point.x + previous.x;
point.y = point.y + previous.y;
expandedLines.add( point);
}
}
return expandedLines;
}
/*
read point with size encoding depending on first bits
*/
private Point readRel() throws java.io.IOException {
int index;
/* 11 : next, 10 : previous ; 0* : same
6 -> 14->30
^ |
| v
3 <- 64
*/
// find index of current size
for ( index = 0; index < SCODE_MAX; index ++) {
if ( scode[index] == currentSize ) break;
}
// read size modifier until it is good one
while ( fieldReader.read(1) != 0 ) {
index = index + ( ( fieldReader.read(1) == 0 ) ? -1 : 1);
// handle circularity
if ( index > SCODE_MAX ) {
index = 0;
}
if ( index < 0 ) {
index = SCODE_MAX;
}
}
return readAbs( scode[index]);
}
/* write given Point with size */
Point readAbs( int size) throws java.io.IOException {
int codeval;
int center, max;
currentSize = size;
Point point = new Point();
if ( size > 32 ) {
point.x = fieldReader.read(32);
point.y = fieldReader.read(32);
}
else {
boolean nocenter=false;
codeval = fieldReader.read( size);
// System.out.println( codeval);
/*
for coding/decoding scheme see
org.artisanlogiciel.graphics.DrawLineKompressor.java
*/
if ( size == 3 ) {
max = 3;
center = 1;
nocenter=true;
}
else {
max = ( 1 << ( size / 2 ) );
center = (max / 2) - 1;
}
// central hole impossible but we don't really care
if ( nocenter )
{
if ( codeval > ( center * max ) ) {
codeval ++;
}
if ( codeval >= ( max * max )) {
System.out.println(
"!!! reserved value for decompression should not occur !!!");
}
}
point.x = ( codeval % max) - center;
point.y = ( codeval / max) - center;
// System.out.println( point.toString());
}
return point;
}
}

View File

@@ -0,0 +1,256 @@
/*
This file is part of ShareDrawWeb.
ShareDrawWeb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ShareDrawWeb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ShareDrawWeb; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
DrawingLineKompressor
compress a draw line over a stream
main algorithm is to code only delta displacement in littlest possible size.
*/
package org.artisanlogiciel.compression.graphics;
import java.awt.Point;
import java.io.OutputStream;
import java.util.ArrayList;
public class DrawLineKompressor {
ArrayList<Point> fromLines;
int previousSize;
int scode[] = {3,6,14,30,64};
final static int SCODE_MAX = 4;
private BitFieldWriter fieldWriter = null;
public DrawLineKompressor( ArrayList<Point> lines) {
fromLines = lines;
fieldWriter = new BitFieldWriter();
}
public void kompress( OutputStream output ) throws java.io.IOException {
fieldWriter.setOutputStream( output);
int skipsame=0;
if ( ( fromLines != null) && ( fromLines.size() > 0)) {
Point topoint = null;
for ( int i = 1; i < fromLines.size(); i++) {
Point frompoint = (Point) fromLines.get( i);
if ( ( topoint != null ) && ( topoint.x == frompoint.x ) && ( topoint.y == frompoint.y ) )
{
skipsame ++;
}
topoint=frompoint;
}
if ( skipsame > 0 )
{
System.out.println("[WARNING] lines contains " + skipsame + " duplicates points");
}
}
if ( ( fromLines != null) && ( fromLines.size() > 0)) {
Point frompoint = (Point) fromLines.get(0);
Point point, topoint;
topoint = new Point();
int center, size;
fieldWriter.write( fromLines.size() - skipsame, 32);
writeAbs( frompoint, 64);
for ( int i = 1; i < fromLines.size(); i++) {
point = (Point) fromLines.get( i);
topoint.x = point.x - frompoint.x;
topoint.y = point.y - frompoint.y;
// find wich size to use...
if (( topoint.x == 0 ) && ( topoint.y == 0 ))
{
// ARGH THIS IS INVALID !
System.out.println("[ERROR] (0,0) point is invalid for compression !!!");
continue;
}
if ( (Math.abs( topoint.x) < 2) && (Math.abs(topoint.y) < 2)) {
writeRel( topoint, 3);
}
else {
size = 64;
for ( int index = 1; index < ( SCODE_MAX - 1 ); index ++) {
/* center = ( ( 1 << ( scode[index] / 2 ) ) - 1 ) / 2;
if ( (Math.abs(topoint.x) <= center)
&& (Math.abs(topoint.y) <= center))
{
size = scode[index];
}
*/
// center is biased there are more + than - , ex for 6bits :(x,y) within ( -3,4 ) x (-3,4)
center = 1 << ( ( scode[index] / 2 ) - 1 );
if ( ( topoint.x <= center ) && ( topoint.x > -center )
&& ( topoint.y <= center ) && ( topoint.y > -center ) )
{
size = scode[index];
// always take the smaller size.
break;
}
}
if ( size < 32 ) {
writeRel( topoint, size);
}
else {
// warning absolute
writeRel( point, 64);
}
}
// new frompoint is previous point
frompoint = point;
}
fieldWriter.padToWord();
}
}
/*
compute bits of size
*/
void writeRel( Point point, int size) throws java.io.IOException {
/*
System.out.println( "point " + point.toString());
System.out.println( "size " + Integer.toString( size));
*/
/* 11 : next, 10 : previous ; 0* : same
6 -> 14
^ |
| v
3 <- 64
*/
if ( size != previousSize) {
int cindex, pindex;
// find index of size
for ( cindex = 0; cindex < SCODE_MAX; cindex ++) {
if ( scode[cindex] == size ) break;
}
// find index of previous size
for ( pindex = 0; pindex < SCODE_MAX; pindex ++) {
if ( scode[pindex] == previousSize ) break;
}
if ( pindex < cindex ) {
/*
if way with = is better than - then use = next
else use - previous
0--<--pindex===>==cindex---<---SCODE_MAX
*/
if ( ((SCODE_MAX - cindex) + pindex ) > ( pindex - cindex ) ) {
// ( pindex - cindex ) times next
for ( ; pindex < cindex; pindex ++) {
fieldWriter.write( 3,2);
}
}
else {
// ((SCODE_MAX -cindex) + pindex ) fois previous
for ( pindex = SCODE_MAX - cindex + pindex; pindex > 0; pindex --) {
fieldWriter.write( 2,2);
}
}
}
else {
/*
if way with = is better than - then use = previous
else use - next
0-->--cindex===<==pindex--->---SCODE_MAX
*/
if ( ((SCODE_MAX - pindex) + cindex ) > cindex - pindex ) {
// ( cindex - pindex ) fois previous
for ( ; cindex < pindex; pindex --) {
fieldWriter.write( 2,2);
}
}
else {
// ((SCODE_MAX - pindex) + cindex ) fois next
for ( pindex = SCODE_MAX - pindex + cindex; pindex > 0; pindex --)
{
fieldWriter.write( 3,2);
}
}
}
}
// this is good size.
fieldWriter.write( 0,1);
writeAbs( point, size);
}
/* write given Point with size */
void writeAbs( Point point, int size) throws java.io.IOException {
int codeval;
int center, max;
previousSize = size;
if ( size > 32 ) {
fieldWriter.write( point.x, 32);
fieldWriter.write( point.y, 32);
}
else {
boolean nocenter = false;
/* size == 3 example :
X - >
Y 0 1 2
| 3 . 4-
v 5 6 7
specific application of general case bellow.
*/
/* X ->
Y 0
| 0 center max
v max
0 1 2 ...center.... (max - 1)
max 2 * max - 1
. (0,0) center * ( max + 1)
(max-1)*max -1 (max ^ 2) - 1
2 */
if ( size == 3 ) {
max = 3;
center = 1;
nocenter = true;
}
else {
max = ( 1 << ( size / 2 ) );
// biased center ( -center +1, center )
center = (max / 2) - 1;
}
/*
System.out.println( "size" + Integer.toString( size));
System.out.println( "max, center " + Integer.toString( max) + " " + Integer.toString( center));
System.out.println( "x, y " + Integer.toString( point.x) + " " + Integer.toString( point.y));
*/
codeval = point.x + center + (( point.y + center ) * max );
// central hole impossible BUT we should not really care ( in fact whole center square is impossible since covered by encoding with lower number of bits ) , avoid it only for size 3.
if (nocenter) {
if ( codeval == ( center * max ) + 1 ) {
System.out.println("!!! warning (0,0) point is invalid for compression !!!");
}
if ( codeval > (center * max) ){
codeval --;
}
}
// System.out.println( "code " + Integer.toString( codeval));
fieldWriter.write( codeval, size);
}
}
}

View File

@@ -0,0 +1,28 @@
/*
This file is part of ShareDrawWeb.
ShareDrawWeb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ShareDrawWeb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ShareDrawWeb; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.artisanlogiciel.graphics;
import java.io.Serializable;
public class DrawException extends Exception implements Serializable {
public DrawException() {
super();
}
}

View File

@@ -0,0 +1,106 @@
/**
Drawing
contains a set of DrawingLine to create a Drawing
- feature of load / save
*/
package org.artisanlogiciel.graphics;
import java.awt.Graphics;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.ArrayList;
import org.artisanlogiciel.graphics.Importer;
import org.artisanlogiciel.graphics.ResetException;
import org.artisanlogiciel.graphics.NoMoreLineException;
public class Drawing
{
private ArrayList<DrawingLine> lines;
public Drawing()
{
reset();
}
public void reset() {
lines = new ArrayList<DrawingLine>(10);
}
public void addLine( DrawingLine line) {
lines.add( line);
}
public void saveLines( DataOutputStream destination) throws
java.io.IOException {
destination.writeInt( lines.size());
for ( DrawingLine line : lines )
{
line.save( destination);
}
}
public void loadLines( DataInputStream source) throws
java.io.IOException {
int nb_lines = source.readInt();
DrawingLine line;
for ( int i = 0; i < nb_lines; i++ ) {
line = new DrawingLine();
line.load( source);
lines.add( line);
}
}
public void importImage( Importer importer) throws
java.io.IOException
{
importer.importInto(this);
}
public void saveLinesKompressed( DataOutputStream destination) throws
java.io.IOException {
destination.writeInt( lines.size());
for ( DrawingLine line : lines )
{
line.saveKompressed( destination);
}
}
public void loadLinesExpanded( DataInputStream source) throws
java.io.IOException {
// DrawLineExpander expander = new DrawLineExpander();
int nb_lines = source.readInt();
DrawingLine line;
for ( int i = 0; i < nb_lines; i++ ) {
line = new DrawingLine();
line.loadExpanded( source);
lines.add( line);
}
}
public int length() {
return lines.size();
}
public DrawingLine getLine( int line) throws ResetException, NoMoreLineException {
if ( line == lines.size() ) {
throw new NoMoreLineException();
}
if ( line > lines.size() ) {
throw new ResetException();
}
return lines.get( line);
}
public ArrayList<DrawingLine> getLines() {
return new ArrayList<DrawingLine>(lines);
}
/** Not a copy, use with care */
public ArrayList<DrawingLine> getInternLines() {
return lines;
}
}

View File

@@ -0,0 +1,96 @@
/**
DrawingLine
keep track of list of Points constituting a line
*/
package org.artisanlogiciel.graphics;
import java.awt.Point;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import org.artisanlogiciel.compression.graphics.DrawLineExpander;
import org.artisanlogiciel.compression.graphics.DrawLineKompressor;
public class DrawingLine implements Cloneable, Serializable
{
ArrayList<Point> lines;
public DrawingLine() {
lines = new ArrayList<>();
}
public void addPoint( Point point) {
lines.add( point);
}
public void setPoints( ArrayList<Point> points) {
lines = points;
}
public Object clone() throws java.lang.CloneNotSupportedException {
return super.clone();
}
private void writePoint( Point p, DataOutputStream destination) throws
java.io.IOException {
destination.writeInt( p.x);
destination.writeInt( p.y);
}
private void readPoint( DataInputStream source) throws java.io.IOException {
Point point = new Point( source.readInt(), source.readInt());
lines.add( point);
}
public void save( DataOutputStream destination) throws
java.io.IOException {
destination.writeInt( lines.size());
for (int i=0; i < lines.size(); i++) {
writePoint( (Point) lines.get(i), destination);
}
}
public void load( DataInputStream source) throws
java.io.IOException {
int point_number = source.readInt();
for (int i=0; i < point_number; i++) {
readPoint( source);
}
}
/**
* send over the stream a compressed version of this line
*/
public void saveKompressed( OutputStream destination) throws
java.io.IOException {
DrawLineKompressor kompressor = new DrawLineKompressor( lines);
kompressor.kompress( destination);
}
/**
* load form the stream a compressed version of this line
*/
public void loadExpanded( InputStream source) throws
java.io.IOException {
DrawLineExpander expander = new DrawLineExpander();
lines = expander.expand( source);
}
public ArrayList<Point> getPoints() {
return new ArrayList<Point>(lines);
}
public ArrayList<Point> internalGetPoints() {
return lines;
}
}

View File

@@ -0,0 +1,94 @@
package org.artisanlogiciel.graphics;
import java.awt.Point;
import java.io.DataInputStream;
/**
.IMA format is an old proprietary format for laser show program
it contain a list of point the laser beam should goe through,
x=255 has a special meaning to hide (255,254) ( send beam into the box) or show it (255,255): let is flow outside.
*/
public class IMAImporter implements Importer
{
final DataInputStream mStream;
boolean mBeanOn = false;
int mIndex =0;
boolean mDebug = false;
public IMAImporter(DataInputStream inputStream)
{
mStream=inputStream;
}
public void setDebug(boolean pDebug)
{
mDebug=pDebug;
}
@Override
public void importInto(Drawing drawing)
{
int x,y;
DrawingLine line = null;
mBeanOn = false;
try {
// little endian unsigned short
int pointCount = mStream.readUnsignedByte();
pointCount = ( 256 * mStream.readUnsignedByte() ) + pointCount;
if ( mDebug )
{
System.out.println("point count :" + pointCount);
}
for (int j = 0 ; j < pointCount; j+=2)
{
mIndex=j;
x = mStream.readUnsignedByte();
y = mStream.readUnsignedByte();
// special beam on/off
if ( ( x == 0xff ) && ( y >= 0xfe ) )
{
mBeanOn = ( y == 0xff);
if ( mDebug )
{
System.out.println("beam change at " + mIndex + " " + mBeanOn);
}
}
else
{
y = 255-y;
if ( mDebug )
{
System.out.println("point at " + mIndex + " " + mBeanOn + " x " + x + " y " + y);
}
if ( mBeanOn )
{
if (line == null )
{
line = new DrawingLine();
}
line.addPoint(new Point(x,y));
}
else
{
if ( line != null )
{
drawing.addLine(line);
line = null;
}
}
}
}
if ( line != null )
{
drawing.addLine(line);
line = null;
}
}
catch( Exception any)
{
System.err.println(" error at index " + mIndex);
any.printStackTrace(System.err);
}
}
}

View File

@@ -0,0 +1,143 @@
package org.artisanlogiciel.graphics;
import java.awt.Point;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* Write a DrawLine (using its internal Vector representation) into IMA format
* this is with loss ( ima is a 255x255 point resolution )
*
* @author philippe
*
*/
public class IMAWriter {
private final ArrayList<DrawingLine> mLines;
private int mByteCount = 0;
// need to compute bounding box and normalize to 255x255
private Point mOrig = new Point(100000,100000);
private Point mMax = new Point(-100000,-100000);
double ratioX = .1;
double ratioY = .1;
public IMAWriter(ArrayList<DrawingLine> pLines)
{
mLines = pLines;
setup();
}
private void updateOrigMax(Point p)
{
double ox = mOrig.getX(), oy = mOrig.getY(), mx = mMax.getX(), my = mMax.getY();
if (p.getX() < ox )
{
ox = p.getX();
}
if (p.getX() > mx)
{
mx = p.getX();
}
if (p.getY() < oy )
{
oy = p.getY();
}
if (p.getY() > my)
{
my = p.getY();
}
mOrig.setLocation(ox,oy);
mMax.setLocation(mx,my);
}
private void setup()
{
int count = 0;
for (DrawingLine line : mLines)
{
for (Point p : line.getPoints())
{
updateOrigMax(p);
count+=2;
}
// beam on + off
count+=4;
}
mByteCount=count;
if ( mMax.getX() != mOrig.getX())
{
ratioX = 255 / (mMax.getX() - mOrig.getX());
}
else
{
ratioX = 1.;
}
if ( mMax.getY() != mOrig.getY())
{
ratioY = 255 / (mMax.getY() - mOrig.getY());
}
else
{
ratioY = 1.;
}
}
public void writeTo(DataOutputStream pData)
throws IOException
{
int wrote = 0;
// writeheader : number of points ...
// little endian unsigned short.
pData.writeByte(mByteCount%256);
pData.writeByte(mByteCount/256);
for (DrawingLine line : mLines)
{
// write ima line
wrote += writeLine(pData, line.getPoints());
}
}
void writeBeamOnOff(DataOutputStream pData,boolean pOn)
throws IOException
{
pData.writeByte(0xff);
pData.writeByte(pOn ? 0xff : 0xfe);
}
void writePoint(DataOutputStream pData,Point pPoint)
throws IOException
{
int x = (int) ((pPoint.getX()-mOrig.getX()) * ratioX);
int y = 255 - ((int) ((pPoint.getY()-mOrig.getY()) * ratioY));
if ( x == 0xff )
{
x=0xfe;
}
pData.writeByte(x);
pData.writeByte(y);
}
int writeLine(DataOutputStream pData,ArrayList<Point> pPoints)
throws IOException
{
int count = 0;
for (Point p : pPoints)
{
writePoint(pData,p);
if ( count == 0 )
{
writeBeamOnOff(pData,true);
}
count++;
}
writeBeamOnOff(pData,false);
return 2*(count +2);
}
}

View File

@@ -0,0 +1,8 @@
package org.artisanlogiciel.graphics;
public interface Importer {
void importInto(Drawing drawing);
void setDebug(boolean pDebug);
}

View File

@@ -0,0 +1,31 @@
/*
This file is part of ShareDrawWeb.
ShareDrawWeb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ShareDrawWeb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ShareDrawWeb; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.artisanlogiciel.graphics;
import java.io.Serializable;
public class NoMoreLineException
extends DrawException
implements Serializable
{
public NoMoreLineException() {
super();
}
}

View File

@@ -0,0 +1,28 @@
/*
This file is part of ShareDrawWeb.
ShareDrawWeb is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
ShareDrawWeb is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ShareDrawWeb; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.artisanlogiciel.graphics;
public class ResetException
extends DrawException
{
public ResetException() {
super();
}
}

View File

@@ -0,0 +1,65 @@
package org.artisanlogiciel.graphics;
import java.awt.Point;
//import java.io.DataOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* Write a DrawLine (using its internal Vector representation) into svg
*
* @author philippe
*
*/
public class SvgWriter {
private final ArrayList<DrawingLine> mLines;
public SvgWriter(ArrayList<DrawingLine> pLines)
{
mLines = pLines;
}
public void writeTo(OutputStream pData)
throws IOException
{
pData.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>".getBytes("UTF8"));
pData.write("<svg>".getBytes("UTF8"));
for (DrawingLine line : mLines)
{
pData.write("<g><path ".getBytes("UTF8"));
pData.write("style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\" d=\"".getBytes("UTF8"));
pData.write( getSvgPathString(line.getPoints()).getBytes("UTF8"));
pData.write(" \" /></g>".getBytes("UTF8"));
}
pData.write("</svg>".getBytes("UTF8"));
}
String getSvgPathString(ArrayList<Point> pPoints)
{
StringBuilder sb = new StringBuilder(pPoints.size() * 10);
Point second = null;
Point previous = null;
for ( Point p : pPoints)
{
if ( previous != null )
{
if ( second == null )
{
second = p;
// 'l' a line ( 'c' woudl be a curve )
sb.append(" l ");
}
sb.append( "" + (p.getX() - previous.getX()) + "," + (p.getY() - previous.getY()) );
previous = p;
}
else
{
sb.append("m " + p.getX() + "," + p.getY());
previous = p;
}
}
return sb.toString();
}
}