From e4c66591987cd0f2c74240c70b01c10df30b3ab2 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Thu, 28 Jan 2021 14:14:05 +0100 Subject: [PATCH 01/16] Class 9 support This class hold several data but one in particular : HOTSPOT. --- .../core/ApplicationStructureAttribute.java | 53 +++++++++++++++++++ src/net/sf/jcgm/core/Command.java | 9 +++- 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/net/sf/jcgm/core/ApplicationStructureAttribute.java diff --git a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java new file mode 100644 index 0000000..356d8eb --- /dev/null +++ b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java @@ -0,0 +1,53 @@ +package net.sf.jcgm.core; + +import java.io.DataInput; +import java.io.IOException; + + +/** + * Class=9, Element=1 + * @author jpprade (Jean-Philippe Prade) + * @author BBNT Solutions + * @version $Id$ + */ +public class ApplicationStructureAttribute extends Command { + + private String attributeType=""; + + private StructuredDataRecord structuredDataRecord=null; + + public ApplicationStructureAttribute(int ec, int eid, int l, DataInput in) throws IOException { + super(ec, eid, l, in); + + int length = this.args[this.currentArg]; + + if(length == 255) { + //non géré + }else { + + for(int i=0;i Date: Thu, 28 Jan 2021 14:22:46 +0100 Subject: [PATCH 02/16] Cleaning --- .../jcgm/core/ApplicationStructureAttribute.java | 1 - src/net/sf/jcgm/core/Command.java | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java index 356d8eb..00b9b76 100644 --- a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java +++ b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java @@ -7,7 +7,6 @@ /** * Class=9, Element=1 * @author jpprade (Jean-Philippe Prade) - * @author BBNT Solutions * @version $Id$ */ public class ApplicationStructureAttribute extends Command { diff --git a/src/net/sf/jcgm/core/Command.java b/src/net/sf/jcgm/core/Command.java index bf4cf27..3b0ca00 100644 --- a/src/net/sf/jcgm/core/Command.java +++ b/src/net/sf/jcgm/core/Command.java @@ -21,12 +21,8 @@ */ package net.sf.jcgm.core; -import net.sf.jcgm.core.ColourModel.Model; -import net.sf.jcgm.core.RealPrecision.Precision; -import net.sf.jcgm.core.StructuredDataRecord.StructuredDataType; -import net.sf.jcgm.core.VDCRealPrecision.Type; - -import java.awt.*; +import java.awt.Color; +import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; @@ -38,6 +34,11 @@ import java.util.Arrays; import java.util.List; +import net.sf.jcgm.core.ColourModel.Model; +import net.sf.jcgm.core.RealPrecision.Precision; +import net.sf.jcgm.core.StructuredDataRecord.StructuredDataType; +import net.sf.jcgm.core.VDCRealPrecision.Type; + /** * Base class for all the CGM commands. *

@@ -812,8 +813,6 @@ protected static Command readCommand(DataInput in, int ec, int eid, int l) throw return new Command(ec, eid, l, in); case APPLICATION_STRUCTURE_ELEMENTS: // 9 - /*unsupported(ec, eid); - return new Command(ec, eid, l, in);*/ return readAPS(in, ec, eid, l); default: From 1fb975ddd0639674eca729c83b4599abf6588e51 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Thu, 28 Jan 2021 22:34:12 +0100 Subject: [PATCH 03/16] ApplicationStructureAttribute supported ApplicationStructureAttribute is supported, flag are ignored for now --- .../core/ApplicationStructureAttribute.java | 21 ++---------- .../jcgm/core/BeginApplicationStructure.java | 34 +++++++++++++++++++ src/net/sf/jcgm/core/Command.java | 5 ++- 3 files changed, 38 insertions(+), 22 deletions(-) create mode 100644 src/net/sf/jcgm/core/BeginApplicationStructure.java diff --git a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java index 00b9b76..1bbbfcd 100644 --- a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java +++ b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java @@ -17,25 +17,8 @@ public class ApplicationStructureAttribute extends Command { public ApplicationStructureAttribute(int ec, int eid, int l, DataInput in) throws IOException { super(ec, eid, l, in); - - int length = this.args[this.currentArg]; - - if(length == 255) { - //non géré - }else { - - for(int i=0;i Date: Wed, 3 Feb 2021 09:29:28 +0100 Subject: [PATCH 04/16] Get & Setter Adding getter & setter & making a class public, to be able to get it outside of the library. The goal is to access HOTSPOT data to render them separately --- .../core/ApplicationStructureAttribute.java | 19 ++++++++ .../jcgm/core/BeginApplicationStructure.java | 12 +++++ src/net/sf/jcgm/core/Member.java | 48 +++++++++++++++++++ .../sf/jcgm/core/StructuredDataRecord.java | 35 ++------------ 4 files changed, 83 insertions(+), 31 deletions(-) create mode 100644 src/net/sf/jcgm/core/Member.java diff --git a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java index 1bbbfcd..1d0247c 100644 --- a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java +++ b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java @@ -1,7 +1,12 @@ package net.sf.jcgm.core; +import java.awt.Graphics2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; import java.io.DataInput; import java.io.IOException; +import java.util.List; + /** @@ -32,4 +37,18 @@ public String toString() { return sb.toString(); } + + + + public String getAttributeType() { + return this.attributeType; + } + + public StructuredDataRecord getStructuredDataRecord() { + return this.structuredDataRecord; + } + + + + } diff --git a/src/net/sf/jcgm/core/BeginApplicationStructure.java b/src/net/sf/jcgm/core/BeginApplicationStructure.java index 92199b4..80716df 100644 --- a/src/net/sf/jcgm/core/BeginApplicationStructure.java +++ b/src/net/sf/jcgm/core/BeginApplicationStructure.java @@ -31,4 +31,16 @@ public String toString() { return sb.toString(); } + + public String getIdentifier() { + return this.identifier; + } + + + public String getType() { + return this.type; + } + + + } diff --git a/src/net/sf/jcgm/core/Member.java b/src/net/sf/jcgm/core/Member.java new file mode 100644 index 0000000..486a556 --- /dev/null +++ b/src/net/sf/jcgm/core/Member.java @@ -0,0 +1,48 @@ +package net.sf.jcgm.core; + +import java.util.List; + +import net.sf.jcgm.core.StructuredDataRecord.StructuredDataType; + +/** + * One entry in the structured data record + * @version $Id: $ + * @author xphc + * @since Oct 5, 2010 + */ +public class Member { + private final StructuredDataType type; + private final int count; + private final List data; + + Member(StructuredDataType type, int count, List data) { + this.type = type; + this.count = count; + this.data = data; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("[type="); + builder.append(this.type); + builder.append(", count="); + builder.append(this.count); + builder.append(", data="); + builder.append(this.data); + builder.append("]"); + return builder.toString(); + } + + public StructuredDataType getType() { + return this.type; + } + + public int getCount() { + return this.count; + } + + public List getData() { + return this.data; + } +} diff --git a/src/net/sf/jcgm/core/StructuredDataRecord.java b/src/net/sf/jcgm/core/StructuredDataRecord.java index 4c69ccf..d4cd8bb 100644 --- a/src/net/sf/jcgm/core/StructuredDataRecord.java +++ b/src/net/sf/jcgm/core/StructuredDataRecord.java @@ -77,37 +77,6 @@ static StructuredDataType get(int index) { } } - /** - * One entry in the structured data record - * @version $Id: $ - * @author xphc - * @since Oct 5, 2010 - */ - class Member { - private final StructuredDataType type; - private final int count; - private final List data; - - Member(StructuredDataType type, int count, List data) { - this.type = type; - this.count = count; - this.data = data; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("[type="); - builder.append(this.type); - builder.append(", count="); - builder.append(this.count); - builder.append(", data="); - builder.append(this.data); - builder.append("]"); - return builder.toString(); - } - } - private final List members = new ArrayList(); void add(StructuredDataType type, int count, List data) { @@ -123,4 +92,8 @@ public String toString() { return builder.toString(); } + public List getMembers() { + return this.members; + } + } From 6fa7163e0aad89da23f595fe20b0561c51f86771 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Mon, 8 Feb 2021 21:48:13 +0100 Subject: [PATCH 05/16] Raw Bitmap are now read and painted --- .../core/ApplicationStructureAttribute.java | 79 ++++++++++++++++++- src/net/sf/jcgm/core/Tile.java | 41 +++++++++- src/net/sf/jcgm/core/TileElement.java | 4 +- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java index 1d0247c..3624ca0 100644 --- a/src/net/sf/jcgm/core/ApplicationStructureAttribute.java +++ b/src/net/sf/jcgm/core/ApplicationStructureAttribute.java @@ -48,7 +48,84 @@ public StructuredDataRecord getStructuredDataRecord() { return this.structuredDataRecord; } - + @Override + public void paint(CGMDisplay d) { + if("region".equals(this.attributeType)) { + List members = this.structuredDataRecord.getMembers(); + if(members!=null && members.size() ==2) { + if(members.get(0).getCount() > 0) { + if(members.get(0).getData().get(0).toString().equals("4")) { + List objects = (List)(Object)members.get(1).getData(); + + int n = (objects.size()-2)/6; + + Point2D.Double[] p1; + Point2D.Double[] p2; + Point2D.Double[] p3; + Point2D.Double[] p4; + + p1 = new Point2D.Double[n]; + p2 = new Point2D.Double[n]; + p3 = new Point2D.Double[n]; + p4 = new Point2D.Double[n]; + + int point = 0; + int pos =0; + while (point < n) { + if (point == 0) { + p1[point] = new Point2D.Double(objects.get(pos), objects.get(pos+1)); + pos+=2; + } + else { + p1[point] = p4[point-1]; + } + p2[point] = new Point2D.Double(objects.get(pos), objects.get(pos+1)); + pos+=2; + p3[point] = new Point2D.Double(objects.get(pos), objects.get(pos+1)); + pos+=2; + p4[point] = new Point2D.Double(objects.get(pos), objects.get(pos+1)); + pos+=2; + point++; + } + + + Graphics2D g2d = d.getGraphics2D(); + g2d.setStroke(d.getLineStroke()); + g2d.setColor(d.getLineColor()); + + + + //svgGenerator.getTopLevelGroup().setAttribute("id", "whatever") + + GeneralPath gp = new GeneralPath(); + + for (int i = 0; i < p1.length; i++) { + if(i==0) { + gp.moveTo(p1[i].x, p1[i].y); + } + + gp.curveTo(p2[i].x, p2[i].y, p3[i].x, p3[i].y, p4[i].x, p4[i].y); + + if(i==p1.length-1) { + gp.closePath(); + } + } + g2d.draw(gp); + } + } + } + }else if("name".equals(this.attributeType)) { + List members = this.structuredDataRecord.getMembers(); + if(members!=null && members.size() ==1) { + if(members.get(0).getCount() > 0) { + if(members.get(0).getData().get(0).toString().equalsIgnoreCase("Hotspot")) { + d.setLineWidth(0); + } + } + } + } + } + } diff --git a/src/net/sf/jcgm/core/Tile.java b/src/net/sf/jcgm/core/Tile.java index 1c8faca..b1f62d6 100644 --- a/src/net/sf/jcgm/core/Tile.java +++ b/src/net/sf/jcgm/core/Tile.java @@ -27,6 +27,10 @@ */ package net.sf.jcgm.core; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; import java.io.DataInput; import java.io.IOException; @@ -59,7 +63,42 @@ public class Tile extends TileElement { @Override protected void readBitmap() { - unsupported("BITMAP for Tile"); + this.bytes = readBytes(); + + } + + @Override + public void paint(CGMDisplay d) { + TileArrayInfo tileArrayInfo = d.getTileArrayInfo(); + int width = tileArrayInfo.getNCellsPerTileInPathDirection(); + int height = tileArrayInfo.getNCellsPerTileInLineDirection(); + BufferedImage imageOut = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); + + byte[] imgdata = this.bytes.array(); + + int x = 0; + int y = 0; + for(int i=0;i=width) { + x=0; + y++; + } + } + Graphics2D g2d = d.getGraphics2D(); + Point2D.Double position = tileArrayInfo.getCurrentTilePosition(); + + + AffineTransform xform = AffineTransform.getTranslateInstance(position.x, position.y); + xform.scale(tileArrayInfo.getTileSizeInPathDirection() / width, + -tileArrayInfo.getTileSizeInLineDirection() / height); + g2d.drawImage(imageOut, xform, null); + + } @Override diff --git a/src/net/sf/jcgm/core/TileElement.java b/src/net/sf/jcgm/core/TileElement.java index 5c6d108..8ef574a 100644 --- a/src/net/sf/jcgm/core/TileElement.java +++ b/src/net/sf/jcgm/core/TileElement.java @@ -56,7 +56,7 @@ abstract class TileElement extends Command { protected int rowPaddingIndicator; protected StructuredDataRecord sdr; protected BufferedImage bufferedImage = null; - private ByteBuffer bytes; + protected ByteBuffer bytes; protected TileElement(int ec, int eid, int l, DataInput in) throws IOException { super(ec, eid, l, in); @@ -96,7 +96,7 @@ protected void readSdrAndBitStream() throws IOException { } } - private ByteBuffer readBytes() { + protected ByteBuffer readBytes() { ByteBuffer buffer = ByteBuffer.allocate(this.args.length - this.currentArg); while (this.currentArg < this.args.length) { buffer.put(makeByte()); From d2e5bbb6f96c0a2423802653ebff16ce83e40f3b Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Mon, 8 Feb 2021 22:11:51 +0100 Subject: [PATCH 06/16] JPEG fixed --- src/net/sf/jcgm/core/Tile.java | 60 +++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/net/sf/jcgm/core/Tile.java b/src/net/sf/jcgm/core/Tile.java index b1f62d6..1ef9285 100644 --- a/src/net/sf/jcgm/core/Tile.java +++ b/src/net/sf/jcgm/core/Tile.java @@ -42,6 +42,7 @@ * @since Oct 5, 2010 */ public class Tile extends TileElement { + Tile(int ec, int eid, int l, DataInput in) throws IOException { super(ec, eid, l, in); @@ -72,31 +73,44 @@ public void paint(CGMDisplay d) { TileArrayInfo tileArrayInfo = d.getTileArrayInfo(); int width = tileArrayInfo.getNCellsPerTileInPathDirection(); int height = tileArrayInfo.getNCellsPerTileInLineDirection(); - BufferedImage imageOut = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); - - byte[] imgdata = this.bytes.array(); - - int x = 0; - int y = 0; - for(int i=0;i=width) { - x=0; - y++; - } - } - Graphics2D g2d = d.getGraphics2D(); - Point2D.Double position = tileArrayInfo.getCurrentTilePosition(); + if(this.bytes!=null && this.compressionType==CompressionType.BITMAP) { + BufferedImage imageOut = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); + + byte[] imgdata = this.bytes.array(); + + int x = 0; + int y = 0; + for(int i=0;i=width) { + x=0; + y++; + } + } + Graphics2D g2d = d.getGraphics2D(); + Point2D.Double position = tileArrayInfo.getCurrentTilePosition(); - AffineTransform xform = AffineTransform.getTranslateInstance(position.x, position.y); - xform.scale(tileArrayInfo.getTileSizeInPathDirection() / width, - -tileArrayInfo.getTileSizeInLineDirection() / height); - g2d.drawImage(imageOut, xform, null); + AffineTransform xform = AffineTransform.getTranslateInstance(position.x, position.y); + xform.scale(tileArrayInfo.getTileSizeInPathDirection() / width, + -tileArrayInfo.getTileSizeInLineDirection() / height); + g2d.drawImage(imageOut, xform, null); + }else { + super.paint(d); + } + /*if(this.bytes!=null && this.compressionType==CompressionType.BASELINE_JPEG) { + Path path = Paths.get("C:/temp/picture"+imgcount+".jpg"); + try { + Files.write(path, this.bytes.array()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }*/ } From 12fef7b4d58a991d5036a746fb5e95918a1199bf Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Mon, 8 Feb 2021 22:13:17 +0100 Subject: [PATCH 07/16] cleaner --- src/net/sf/jcgm/core/Tile.java | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/net/sf/jcgm/core/Tile.java b/src/net/sf/jcgm/core/Tile.java index 1ef9285..17eb1d7 100644 --- a/src/net/sf/jcgm/core/Tile.java +++ b/src/net/sf/jcgm/core/Tile.java @@ -27,9 +27,6 @@ */ package net.sf.jcgm.core; -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.io.DataInput; import java.io.IOException; @@ -91,26 +88,13 @@ public void paint(CGMDisplay d) { y++; } } - Graphics2D g2d = d.getGraphics2D(); - Point2D.Double position = tileArrayInfo.getCurrentTilePosition(); - - AffineTransform xform = AffineTransform.getTranslateInstance(position.x, position.y); - xform.scale(tileArrayInfo.getTileSizeInPathDirection() / width, - -tileArrayInfo.getTileSizeInLineDirection() / height); - g2d.drawImage(imageOut, xform, null); + this.bufferedImage=imageOut; + super.paint(d); }else { super.paint(d); } - /*if(this.bytes!=null && this.compressionType==CompressionType.BASELINE_JPEG) { - Path path = Paths.get("C:/temp/picture"+imgcount+".jpg"); - try { - Files.write(path, this.bytes.array()); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - }*/ + } From 0b333c07aac97f973e1654340cd2858e0e5f8d3f Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Wed, 10 Feb 2021 22:15:11 +0100 Subject: [PATCH 08/16] PNG Tiles are now read --- src/net/sf/jcgm/core/Command.java | 5 ++ src/net/sf/jcgm/core/TileElement.java | 93 ++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/net/sf/jcgm/core/Command.java b/src/net/sf/jcgm/core/Command.java index c47216e..6185bc2 100644 --- a/src/net/sf/jcgm/core/Command.java +++ b/src/net/sf/jcgm/core/Command.java @@ -717,6 +717,7 @@ final protected StructuredDataRecord makeSDR() { data.add(makeUInt32()); break; case BS: + data.add(bitStream()); // bit stream? XXX how do we know how many bits to read? break; case CL: @@ -735,6 +736,10 @@ final protected StructuredDataRecord makeSDR() { return ret; } + protected Object bitStream() { + return null;//see subimplementation + } + /** * Align on a word boundary */ diff --git a/src/net/sf/jcgm/core/TileElement.java b/src/net/sf/jcgm/core/TileElement.java index 8ef574a..9468a01 100644 --- a/src/net/sf/jcgm/core/TileElement.java +++ b/src/net/sf/jcgm/core/TileElement.java @@ -32,10 +32,12 @@ import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataInput; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Iterator; +import java.util.List; import javax.imageio.ImageIO; import javax.imageio.ImageReader; @@ -75,7 +77,33 @@ protected void readSdrAndBitStream() throws IOException { // the first one will do ImageReader reader = imageReaders.next(); - ByteBuffer buffer = readBytes(); + ByteBuffer buffer = readBytes(); + + + if(this.compressionType == CompressionType.PNG) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] pngSignature = new byte[] { (byte)0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; + baos.write(pngSignature); + //the PNG chunks are a in the SDR as bit stream we have to merge it + List members = this.sdr.getMembers(); + if(members!=null) { + for(Member member: members) { + for(int i = 0; i < member.getCount();i++) { + Object data = member.getData().get(i); + if(data!=null && data instanceof byte[]) { + baos.write((byte[])data); + } + } + } + } + baos.write(buffer.array()); + buffer = ByteBuffer.allocate(baos.size()); + buffer.put(baos.toByteArray()); + + } + + + //debugByte(buffer.array(),"img","png"); ByteArrayInputStream input = new ByteArrayInputStream(buffer.array()); ImageInputStream imageInputStream = ImageIO.createImageInputStream(input); @@ -187,4 +215,67 @@ private void readImageDelayed(TileArrayInfo tileArrayInfo) { } } + @Override + protected Object bitStream() { + + if(this.compressionType == CompressionType.PNG) { + //translated in java from : https://github.com/BhaaLseN/CgmInfo + + byte[] dataLength = new byte[4]; + for (int i = 0; i < dataLength.length; i++) + dataLength[i] = makeByte(); + + int length = 0; + + //length = java.nio.ByteBuffer.wrap(dataLength).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt(); + length = java.nio.ByteBuffer.wrap(dataLength).getInt(); + + byte[] type = new byte[4]; + for (int i = 0; i < dataLength.length; i++) + type[i] = makeByte(); + + byte[] data = new byte[length]; + for (int i = 0; i < data.length; i++) + data[i] = makeByte(); + + byte[] crc = new byte[4]; + for (int i = 0; i < dataLength.length; i++) + crc[i] = makeByte(); + + // bitstream is a series of unsigned integer at fixed 16-bit precision [ISO/IEC 8632-3 7, Table 1, BS / Note 15] + // 16 bits per entry is chosen for portability reasons and need not be filled completely; the remainder is set to 0. + // we'll have to advance the stream to be aligned at a 16-bit boundary before we leave. + if (length % 2 != 0) + { + byte shouldBeZero = makeByte(); + + } + + byte[] result = new byte[dataLength.length + type.length + data.length + crc.length]; + + System.arraycopy(dataLength, 0, result, 0, dataLength.length); + System.arraycopy(type, 0, result, dataLength.length, type.length); + System.arraycopy(data, 0, result, dataLength.length + type.length, data.length); + System.arraycopy(crc, 0, result, dataLength.length + type.length + data.length, crc.length); + + return result; + }else { + return null; + } + } + + + /*private void debugByte(byte[] data, String name,String type) { + try (FileOutputStream fos = new FileOutputStream("c:/temp/name_"+UUID.randomUUID().toString()+"."+type)) { + fos.write(data); + + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }*/ + } \ No newline at end of file From 8b289e5cf7020d4ed05e981f51af324f0d1aa3be Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Tue, 1 Jun 2021 15:48:11 +0200 Subject: [PATCH 09/16] Add management : - for CAP alignement not sure if it is technicaly good, but visualy it is - for begin and end figure these are needed, because there is an issue with this lib : the filling of polybezier is never done. I noticed that Polybezier which are inside figure, are closed shape, and so a Genaralpath must be used instead of a basic shape. I added a error message warning the user when encoutering a tiff --- src/net/sf/jcgm/core/BeginFigure.java | 25 ++++++++++++++++++++++++ src/net/sf/jcgm/core/Command.java | 4 ++-- src/net/sf/jcgm/core/EndFigure.java | 25 ++++++++++++++++++++++++ src/net/sf/jcgm/core/RestrictedText.java | 1 + src/net/sf/jcgm/core/TileElement.java | 3 +++ 5 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/net/sf/jcgm/core/BeginFigure.java create mode 100644 src/net/sf/jcgm/core/EndFigure.java diff --git a/src/net/sf/jcgm/core/BeginFigure.java b/src/net/sf/jcgm/core/BeginFigure.java new file mode 100644 index 0000000..f8d9e1c --- /dev/null +++ b/src/net/sf/jcgm/core/BeginFigure.java @@ -0,0 +1,25 @@ +package net.sf.jcgm.core; + +import java.io.DataInput; +import java.io.IOException; + +/** + * Class=0, Element=8 + * @author jpprade (Jean-Philippe Prade) + * @version $Id$ + */ +public class BeginFigure extends Command { + + public BeginFigure(int ec, int eid, int l, DataInput in) throws IOException { + super(ec, eid, l, in); + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("BeginFigure "); + return sb.toString(); + } + +} diff --git a/src/net/sf/jcgm/core/Command.java b/src/net/sf/jcgm/core/Command.java index 6185bc2..9dc5bc9 100644 --- a/src/net/sf/jcgm/core/Command.java +++ b/src/net/sf/jcgm/core/Command.java @@ -867,9 +867,9 @@ private static Command readDelimiterElements(DataInput in, int ec, int eid, int case END_SEGMENT: // 0, 8 case BEGIN_FIGURE: - // 0, 9 + return new BeginFigure(ec, eid, l, in); case END_FIGURE: - // 0, 13 + return new EndFigure(ec, eid, l, in); case BEGIN_PROTECTION_REGION: // 0, 14 case END_PROTECTION_REGION: diff --git a/src/net/sf/jcgm/core/EndFigure.java b/src/net/sf/jcgm/core/EndFigure.java new file mode 100644 index 0000000..cb0d577 --- /dev/null +++ b/src/net/sf/jcgm/core/EndFigure.java @@ -0,0 +1,25 @@ +package net.sf.jcgm.core; + +import java.io.DataInput; +import java.io.IOException; + +/** + * Class=0, Element=9 + * @author jpprade (Jean-Philippe Prade) + * @version $Id$ + */ +public class EndFigure extends Command { + + public EndFigure(int ec, int eid, int l, DataInput in) throws IOException { + super(ec, eid, l, in); + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("EndFigure "); + return sb.toString(); + } + +} diff --git a/src/net/sf/jcgm/core/RestrictedText.java b/src/net/sf/jcgm/core/RestrictedText.java index c456349..f9a8613 100644 --- a/src/net/sf/jcgm/core/RestrictedText.java +++ b/src/net/sf/jcgm/core/RestrictedText.java @@ -231,6 +231,7 @@ else if (VerticalAlignment.TOP.equals(verticalAlignment)) { } else if (VerticalAlignment.CAP.equals(verticalAlignment)) { // TODO + yPos = this.deltaHeight; } else if (VerticalAlignment.HALF.equals(verticalAlignment)) { yPos = this.deltaHeight/2; diff --git a/src/net/sf/jcgm/core/TileElement.java b/src/net/sf/jcgm/core/TileElement.java index 9468a01..36ee95c 100644 --- a/src/net/sf/jcgm/core/TileElement.java +++ b/src/net/sf/jcgm/core/TileElement.java @@ -204,6 +204,9 @@ private void readImageDelayed(TileArrayInfo tileArrayInfo) { reader.setInput(imageInputStream); this.bufferedImage = reader.read(0); } + }else { + Messages.getInstance() + .add(new Message(Severity.UNSUPPORTED, getElementClass(), getElementCode(), "No tiff support found add jai-core to classpath", toString())); } } catch (IOException | CgmException e) { Messages.getInstance() From d9c228d97b7e828f8f7850836b9d4608fed31404 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Thu, 3 Jun 2021 15:33:42 +0200 Subject: [PATCH 10/16] Paint Support of BITONAL Tile using bitmap compression --- src/net/sf/jcgm/core/BitonalTile.java | 47 ++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/net/sf/jcgm/core/BitonalTile.java b/src/net/sf/jcgm/core/BitonalTile.java index 94041f3..93ce891 100644 --- a/src/net/sf/jcgm/core/BitonalTile.java +++ b/src/net/sf/jcgm/core/BitonalTile.java @@ -28,6 +28,7 @@ package net.sf.jcgm.core; import java.awt.Color; +import java.awt.image.BufferedImage; import java.io.DataInput; import java.io.IOException; @@ -69,7 +70,51 @@ else if (ColourSelectionMode.getType().equals(ColourSelectionMode.Type.INDEXED)) @Override protected void readBitmap() { - unsupported("BITMAP for BitonalTile"); + this.bytes = readBytes(); + + } + + @Override + public void paint(CGMDisplay d) { + TileArrayInfo tileArrayInfo = d.getTileArrayInfo(); + int width = tileArrayInfo.getNCellsPerTileInPathDirection(); + int height = tileArrayInfo.getNCellsPerTileInLineDirection(); + + + if(this.bytes!=null && this.compressionType==CompressionType.BITMAP) { + BufferedImage imageOut = new BufferedImage(width , height, BufferedImage.TYPE_BYTE_BINARY); + + byte[] imgdata = this.bytes.array(); + + int x = 0; + int y = 0; + for(int i=0;i=0;j--) { + byte colorIndex = getBit(rgb2, j); + Color color = d.getIndexedColor(colorIndex); + imageOut.setRGB(x, y, color.getRGB()); + x=x+1; + } + + if(x>=width) { + x=0; + y++; + } + } + + this.bufferedImage=imageOut; + + super.paint(d); + }else { + super.paint(d); + } + } + + public byte getBit(byte octect, int position) + { + return (byte) ((octect >> position) & 1); } @Override From a15b03d43f6d95c7d82bc300c937fe2aaa59fcf6 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Mon, 21 Jun 2021 11:21:20 +0200 Subject: [PATCH 11/16] FIX : integer divided by integer give integer: so 0,x value id rounded to 0 making Text (Class=4, Element=4) to be invisible --- src/net/sf/jcgm/core/TextCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/sf/jcgm/core/TextCommand.java b/src/net/sf/jcgm/core/TextCommand.java index e3c1801..ac6762c 100644 --- a/src/net/sf/jcgm/core/TextCommand.java +++ b/src/net/sf/jcgm/core/TextCommand.java @@ -126,7 +126,7 @@ public void paint(CGMDisplay d) { screenResolution = Toolkit.getDefaultToolkit() .getScreenResolution(); } - double height = fontMetrics.getAscent() * 72 / screenResolution; + double height = fontMetrics.getAscent() * 72 / (double) screenResolution; scaleText(d, fontMetrics, glyphVector, logicalBounds.getWidth(), height); From 6d39cbb45e676a9adecbdc45b63a571881254b6c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Wed, 7 Jul 2021 22:28:27 +0200 Subject: [PATCH 12/16] Correct color on bitmap --- src/net/sf/jcgm/core/Tile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/sf/jcgm/core/Tile.java b/src/net/sf/jcgm/core/Tile.java index 17eb1d7..08eba7f 100644 --- a/src/net/sf/jcgm/core/Tile.java +++ b/src/net/sf/jcgm/core/Tile.java @@ -71,7 +71,7 @@ public void paint(CGMDisplay d) { int width = tileArrayInfo.getNCellsPerTileInPathDirection(); int height = tileArrayInfo.getNCellsPerTileInLineDirection(); if(this.bytes!=null && this.compressionType==CompressionType.BITMAP) { - BufferedImage imageOut = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); + BufferedImage imageOut = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); byte[] imgdata = this.bytes.array(); @@ -81,7 +81,7 @@ public void paint(CGMDisplay d) { byte r = imgdata[i]; byte g = imgdata[i+1]; byte b = imgdata[i+2]; - imageOut.setRGB(x, y, (r <<16) | (g <<8) | b); + imageOut.setRGB(x, y, (r <<16) + (g <<8) + b); x=x+1; if(x>=width) { x=0; From 14e66e805e0da86c9c65f044a5b9c34860fe12e4 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Fri, 9 Jul 2021 14:44:04 +0200 Subject: [PATCH 13/16] Support for RUN LENGTH image decoding --- src/net/sf/jcgm/core/Tile.java | 29 ++++++++++++++++++++++++--- src/net/sf/jcgm/core/TileElement.java | 3 +++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/net/sf/jcgm/core/Tile.java b/src/net/sf/jcgm/core/Tile.java index 08eba7f..a5b52a3 100644 --- a/src/net/sf/jcgm/core/Tile.java +++ b/src/net/sf/jcgm/core/Tile.java @@ -91,12 +91,35 @@ public void paint(CGMDisplay d) { this.bufferedImage=imageOut; super.paint(d); - }else { + }else if(this.bytes!=null && this.compressionType==CompressionType.RUN_LENGTH) { + BufferedImage imageOut = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + byte[] imgdata = this.bytes.array(); + int x = 0; + int y = 0; + for(int i=0;i=width) { + x=0; + y++; + } + } + } + + this.bufferedImage=imageOut; + super.paint(d); + } else { super.paint(d); } + } - - + public static int unsignedToBytes(byte b) { + return b & 0xFF; } @Override diff --git a/src/net/sf/jcgm/core/TileElement.java b/src/net/sf/jcgm/core/TileElement.java index 36ee95c..bd52871 100644 --- a/src/net/sf/jcgm/core/TileElement.java +++ b/src/net/sf/jcgm/core/TileElement.java @@ -118,6 +118,9 @@ protected void readSdrAndBitStream() throws IOException { case T6: readT6(); break; + case RUN_LENGTH: + this.bytes = readBytes(); + break; default: unsupported("unsupported compression type " + this.compressionType); } From e9e760457c70ed5f64ed31dc97182eaa9ab3d38c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Thu, 15 Jul 2021 20:59:22 +0200 Subject: [PATCH 14/16] Support for AppendText (4,6) --- src/net/sf/jcgm/core/AppendText.java | 37 ++++++++++++++++++++++++++++ src/net/sf/jcgm/core/CGM.java | 6 +++++ src/net/sf/jcgm/core/Command.java | 3 +-- 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/net/sf/jcgm/core/AppendText.java diff --git a/src/net/sf/jcgm/core/AppendText.java b/src/net/sf/jcgm/core/AppendText.java new file mode 100644 index 0000000..ea75669 --- /dev/null +++ b/src/net/sf/jcgm/core/AppendText.java @@ -0,0 +1,37 @@ +package net.sf.jcgm.core; + +import java.awt.geom.Point2D.Double; +import java.io.DataInput; +import java.io.IOException; + +/** + * Class=4, Element=6 + * @author jpprade (Jean-Philippe Prade) + * @version $Id$ + */ +public class AppendText extends TextCommand { + + protected int isFinal = 0; + + public AppendText(int ec, int eid, int l, DataInput in) throws IOException { + super(ec, eid, l, in); + this.isFinal = makeInt(); + this.string = makeString(); + + } + + @Override + Double getTextOffset(CGMDisplay d) { + // TODO Auto-generated method stub + return null; + } + + /** + * This element is painted in the preceeding TextElement + */ + @Override + public void paint(CGMDisplay d) { + return; + } + +} diff --git a/src/net/sf/jcgm/core/CGM.java b/src/net/sf/jcgm/core/CGM.java index 1e16d48..ec663ae 100644 --- a/src/net/sf/jcgm/core/CGM.java +++ b/src/net/sf/jcgm/core/CGM.java @@ -85,6 +85,12 @@ public void read(DataInput in) throws IOException { Command c = Command.read(in); if (c == null) break; + if(c instanceof AppendText) { + Command lastCommand = this.commands.get(this.commands.size()-1); + if(lastCommand instanceof TextCommand ) { + ((TextCommand)lastCommand).appendString(((AppendText) c).getString()); + } + } for (ICommandListener listener : this.commandListeners) { listener.commandProcessed(c); diff --git a/src/net/sf/jcgm/core/Command.java b/src/net/sf/jcgm/core/Command.java index 9dc5bc9..1a1bda2 100644 --- a/src/net/sf/jcgm/core/Command.java +++ b/src/net/sf/jcgm/core/Command.java @@ -1101,8 +1101,7 @@ private static Command readGraphicalPrimitiveElements(DataInput in, int ec, int return new RestrictedText(ec, eid, l, in); case APPEND_TEXT: // 6 - unsupported(ec, eid); - return new Command(ec, eid, l, in); + return new AppendText(ec, eid, l, in); case POLYGON: // 7 return new PolygonElement(ec, eid, l, in); From 5389751532ff46a830e7d890d3a311c37d626926 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Fri, 16 Jul 2021 09:32:47 +0200 Subject: [PATCH 15/16] file forgoten in previous commit --- src/net/sf/jcgm/core/TextCommand.java | 110 +++++++++++++------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/src/net/sf/jcgm/core/TextCommand.java b/src/net/sf/jcgm/core/TextCommand.java index ac6762c..f004ff3 100644 --- a/src/net/sf/jcgm/core/TextCommand.java +++ b/src/net/sf/jcgm/core/TextCommand.java @@ -30,8 +30,8 @@ import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; import java.awt.geom.Point2D.Double; +import java.awt.geom.Rectangle2D; import java.io.DataInput; import java.io.IOException; @@ -44,14 +44,14 @@ public abstract class TextCommand extends Command { /** The string to display */ protected String string; - + /** The position at which the string should be displayed */ protected Point2D.Double position; public TextCommand(int ec, int eid, int l, DataInput in) throws IOException { super(ec, eid, l, in); } - + /** * Returns an offset to apply to the defined text position * @param d @@ -95,50 +95,50 @@ public void paint(CGMDisplay d) { String decodedString = d.useSymbolEncoding() ? SymbolDecoder .decode(this.string) : this.string; - // the text path left is easy: just flip the string - if (TextPath.Type.LEFT.equals(d.getTextPath())) { - decodedString = flipString(decodedString); - } - - Font font = g2d.getFont(); - - // adjust the size of the font depending on the extent. If the extent is - // very big, having small font sizes may create problems - Point2D.Double[] extent = d.getExtent(); - Font adjustedFont = font.deriveFont((float) (Math.abs(extent[0].y - - extent[1].y) / 100)); - g2d.setFont(adjustedFont); - FontRenderContext fontRenderContext = g2d.getFontRenderContext(); - GlyphVector glyphVector = adjustedFont.createGlyphVector( - fontRenderContext, decodedString); - Rectangle2D logicalBounds = glyphVector.getLogicalBounds(); - - FontMetrics fontMetrics = g2d.getFontMetrics(adjustedFont); - // XXX: unfortunately, getAscent() does not return correct values, - // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6623223 - // so we are always going to be a bit off - int screenResolution; - if (GraphicsEnvironment.isHeadless()) { - // if we're in a headless environment, assume 96 dots per inch - // (default setting for Windows XP) - screenResolution = 96; - } else { - screenResolution = Toolkit.getDefaultToolkit() - .getScreenResolution(); - } - double height = fontMetrics.getAscent() * 72 / (double) screenResolution; - - scaleText(d, fontMetrics, glyphVector, logicalBounds.getWidth(), height); - - if (TextPath.Type.UP.equals(d.getTextPath()) - || TextPath.Type.DOWN.equals(d.getTextPath())) { - applyTextPath(d, glyphVector); - } - - g2d.drawGlyphVector(glyphVector, 0, 0); - - // restore the transformation that existed before painting the string - g2d.setTransform(savedTransform); + // the text path left is easy: just flip the string + if (TextPath.Type.LEFT.equals(d.getTextPath())) { + decodedString = flipString(decodedString); + } + + Font font = g2d.getFont(); + + // adjust the size of the font depending on the extent. If the extent is + // very big, having small font sizes may create problems + Point2D.Double[] extent = d.getExtent(); + Font adjustedFont = font.deriveFont((float) (Math.abs(extent[0].y + - extent[1].y) / 100)); + g2d.setFont(adjustedFont); + FontRenderContext fontRenderContext = g2d.getFontRenderContext(); + GlyphVector glyphVector = adjustedFont.createGlyphVector( + fontRenderContext, decodedString); + Rectangle2D logicalBounds = glyphVector.getLogicalBounds(); + + FontMetrics fontMetrics = g2d.getFontMetrics(adjustedFont); + // XXX: unfortunately, getAscent() does not return correct values, + // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6623223 + // so we are always going to be a bit off + int screenResolution; + if (GraphicsEnvironment.isHeadless()) { + // if we're in a headless environment, assume 96 dots per inch + // (default setting for Windows XP) + screenResolution = 96; + } else { + screenResolution = Toolkit.getDefaultToolkit() + .getScreenResolution(); + } + double height = fontMetrics.getAscent() * 72 / (double) screenResolution; + + scaleText(d, fontMetrics, glyphVector, logicalBounds.getWidth(), height); + + if (TextPath.Type.UP.equals(d.getTextPath()) + || TextPath.Type.DOWN.equals(d.getTextPath())) { + applyTextPath(d, glyphVector); + } + + g2d.drawGlyphVector(glyphVector, 0, 0); + + // restore the transformation that existed before painting the string + g2d.setTransform(savedTransform); } /** @@ -159,10 +159,10 @@ protected String flipString(String s) { */ protected void applyTextPath(CGMDisplay d, GlyphVector glyphVector) { double height = glyphVector.getLogicalBounds().getHeight(); - + if (TextPath.Type.DOWN.equals(d.getTextPath())) { float[] glyphPositions = glyphVector.getGlyphPositions(0, glyphVector.getNumGlyphs(), null); - + int glyphIndex = 0; for (int i = 0; i < (glyphPositions.length / 2); i++) { Point2D.Float newPos = new Point2D.Float(glyphPositions[0], (float)(i*height)); @@ -170,11 +170,15 @@ protected void applyTextPath(CGMDisplay d, GlyphVector glyphVector) { } } else if (TextPath.Type.DOWN.equals(d.getTextPath())) { - + } } - public String getString() { - return string; - } + public String getString() { + return this.string; + } + + public void appendString(String toAppend) { + this.string = this.string + toAppend; + } } \ No newline at end of file From a623c5db6a5a5eb1f71a0e44ab7c9c02f23ab478 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Prade Date: Fri, 16 Jul 2021 18:38:07 +0200 Subject: [PATCH 16/16] Implementation of DashType 6 & 8 (for polyline) Possibility to access hatchtype to overload Hatch type can be negative in my samples protection on Tile element when there is more data than image resolution --- src/net/sf/jcgm/core/CGMDisplay.java | 155 +++++++++++++++++++++++++-- src/net/sf/jcgm/core/DashType.java | 14 ++- src/net/sf/jcgm/core/HatchIndex.java | 12 ++- src/net/sf/jcgm/core/Polyline.java | 80 +++++++++----- src/net/sf/jcgm/core/Tile.java | 5 +- 5 files changed, 225 insertions(+), 41 deletions(-) diff --git a/src/net/sf/jcgm/core/CGMDisplay.java b/src/net/sf/jcgm/core/CGMDisplay.java index 0b74647..688ff19 100644 --- a/src/net/sf/jcgm/core/CGMDisplay.java +++ b/src/net/sf/jcgm/core/CGMDisplay.java @@ -30,6 +30,7 @@ import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Line2D; +import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.awt.geom.Point2D.Double; import java.awt.geom.Rectangle2D; @@ -100,7 +101,7 @@ public class CGMDisplay { private VerticalAlignment verticalTextAlignment = VerticalAlignment.NORMAL_VERTICAL; - private final Map lineDashes; + protected final Map lineDashes; /** The color table */ private Color[] colorTable; @@ -144,6 +145,8 @@ public class CGMDisplay { private boolean isTransparent = false; + protected int lineType = DashType.SOLID; + /** * Whether the view has been cleared. FIXME: how the view is cleared depends * on the profile we're using. We are not supporting profiles at this point, @@ -160,6 +163,9 @@ public CGMDisplay(CGM cgm) { this.lineDashes.put(DashType.DOT, new float[] { 13, 13 }); // dot this.lineDashes.put(DashType.DASH_DOT, new float[] { 55, 20, 13, 20 }); // dash-dot this.lineDashes.put(DashType.DASH_DOT_DOT, new float[] { 55, 20, 13, 20, 13, 20 }); // dash-dot-dot + //seems visualy good : + this.lineDashes.put(DashType.STITCH_LINE, new float[] {2, 2 }); + this.lineDashes.put(DashType.CENTER_LINE, new float[] { 4, 1, 1.3f, 1 }); // https://www.aircraftsystemstech.com/2019/11/lines-and-drawing-symbols-aircraft.html if (VDCType.getType().equals(VDCType.Type.INTEGER)) { this.extent = new Point2D.Double[] { new Point2D.Double(0, 0), new Point2D.Double(32767, 32767) }; @@ -515,8 +521,8 @@ public void reset() { this.characterHeight = 32; this.additionalInterCharacterSpace = 0; - this.lineStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); - this.edgeStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); + this.lineStroke = new BasicStroke(0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); + this.edgeStroke = new BasicStroke(0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); this.drawEdge = false; this.hatchType = HatchType.HORIZONTAL_LINES; setInteriorStyle(Style.HOLLOW); @@ -592,6 +598,11 @@ public void setLineType(int type) { this.lineStroke.getMiterLimit(), this.lineDashes.get(type), this.lineStroke.getDashPhase()); + this.lineType=type; + } + + public int getLineType() { + return this.lineType; } public BasicStroke getLineStroke() { @@ -837,7 +848,127 @@ else if (InteriorStyle.Style.HATCH.equals(getInteriorStyle())) { } } - private void drawHatch(Shape s) { + protected void drawArrow(Point2D.Double dest,Point2D.Double source) { + + double arrowHeight = Math.sqrt(2); + double arrowLength = 4.0f; + + double vx= source.x - dest.x; + double vy= source.y - dest.y; + + Point2D.Double arrowVectorInv = new Point2D.Double(vx, vy); + + Point2D.Double intersec = getCoordinate(arrowVectorInv,arrowLength,dest); + + /*double length = Math.sqrt((intersec.x - dest.x) * (intersec.x - dest.x) + (intersec.y - dest.y) * (intersec.y - dest.y)); + System.out.println("taille " + length);*/ + + + Point2D.Double arrowVectorBase = new Point2D.Double(-1 * arrowVectorInv.y, arrowVectorInv.x); + Point2D.Double arrowVectorBaseNegatif = new Point2D.Double(arrowVectorInv.y, -1 * arrowVectorInv.x); + + Point2D.Double base1 = getCoordinate(arrowVectorBase,arrowHeight / 2 ,intersec); + Point2D.Double base2 = getCoordinate(arrowVectorBaseNegatif,arrowHeight / 2 ,intersec); + + Path2D.Float path = new Path2D.Float(); + + + + path.moveTo ( dest.x, dest.y ); + path.lineTo ( base1.x, base1.y ); + path.lineTo ( base2.x, base2.y ); + path.lineTo ( dest.x, dest.y ); + + + //this.g2d.draw ( path ); + this.g2d.fill(path); + + + /* + AffineTransform tx = new AffineTransform(); + Line2D.Double line = new Line2D.Double(source.x,source.y,dest.x,dest.y); + + Polygon arrowHead = new Polygon(); + arrowHead.addPoint( 0,5); + arrowHead.addPoint( -5, -5); + arrowHead.addPoint( 5,-5); + + tx.setToIdentity(); + double angle = Math.atan2(line.y2-line.y1, line.x2-line.x1); + tx.translate(line.x2, line.y2); + tx.rotate((angle-Math.PI/2d)); + + Graphics2D g = (Graphics2D) this.g2d.create(); + + if( line.x2< 20) + g.setColor(Color.BLUE); + else if( line.x2< 100) + g.setColor(Color.RED); + else if( line.x2< 200) + g.setColor(Color.YELLOW); + g.setTransform(tx); + g.fill(arrowHead); + */ + + + /*BasicStroke stroke = getLineStroke(); + + double endX = point.x; + + double veeX; + + switch ( stroke.getLineJoin() ) { + case BasicStroke.JOIN_BEVEL: + // IIRC, bevel varies system to system, this is approximate + veeX = endX - stroke.getLineWidth() * 0.25f; + break; + default: + case BasicStroke.JOIN_MITER: + veeX = endX - stroke.getLineWidth() * 0.5f / arrowRatio; + break; + case BasicStroke.JOIN_ROUND: + veeX = endX - stroke.getLineWidth() * 0.5f; + break; + } + + // vee + Path2D.Float path = new Path2D.Float(); + + double startX = veeX - arrowLength; + double startY = point.y + -arrowRatio*arrowLength; + + path.moveTo ( startX, startY ); + path.lineTo ( veeX, point.y ); + path.lineTo ( veeX - arrowLength, point.y + arrowRatio*arrowLength ); + path.lineTo ( startX, startY ); + + + this.g2d.draw ( path );*/ + + } + + private Point2D.Double getCoordinate(Point2D.Double vector, double distance,Point2D.Double source){ + double bs = distance * distance / ( ((vector.y * vector.y) / (vector.x * vector.x)) +1 ); + double as = distance * distance - bs; + + double b = Math.sqrt(bs); + double a = Math.sqrt(as); + + if(vector.x < 0) { + b = b * -1; + } + + if(vector.y < 0) { + a = a * -1; + } + System.out.println(Math.sqrt(bs + as)); + + Point2D.Double db = new Point2D.Double(source.x + b, source.y + a); + + return db; + } + + protected void drawHatch(Shape s) { // remember the clip and the stroke since we're overwriting them here Shape previousClippingArea = this.g2d.getClip(); Stroke previousStroke = this.g2d.getStroke(); @@ -879,19 +1010,19 @@ else if (HatchType.POSITIVE_NEGATIVE_CROSSHATCH.equals(this.hatchType)) { this.g2d.setStroke(previousStroke); } - private void drawVerticalLines(Rectangle2D bounds, final double stepX) { + protected void drawVerticalLines(Rectangle2D bounds, final double stepX) { for (double x = bounds.getX(); x < bounds.getX() + bounds.getWidth(); x += stepX) { this.g2d.draw(new Line2D.Double(x, bounds.getY(), x, bounds.getY() + bounds.getHeight())); } } - private void drawHorizontalLines(Rectangle2D bounds, final double stepY) { + protected void drawHorizontalLines(Rectangle2D bounds, final double stepY) { for (double y = bounds.getY(); y < bounds.getY() + bounds.getHeight(); y += stepY) { this.g2d.draw(new Line2D.Double(bounds.getX(), y, bounds.getX() + bounds.getWidth(), y)); } } - private void drawPositiveSlopeLines(Rectangle2D bounds, final double slopeStep) { + protected void drawPositiveSlopeLines(Rectangle2D bounds, final double slopeStep) { Point2D.Double currentBegin = new Point2D.Double(bounds.getX(), bounds.getY() + bounds.getHeight()); Point2D.Double currentEnd = currentBegin; @@ -925,7 +1056,7 @@ private void drawPositiveSlopeLines(Rectangle2D bounds, final double slopeStep) } } - private void drawNegativeSlopeLines(Rectangle2D bounds, final double slopeStep) { + protected void drawNegativeSlopeLines(Rectangle2D bounds, final double slopeStep) { Point2D.Double currentBegin = new Point2D.Double(bounds.getX(), bounds.getY()); Point2D.Double currentEnd = currentBegin; @@ -966,6 +1097,10 @@ public void setHatchStyle(HatchType type) { this.hatchType = type; } + public HatchType getHatchType() { + return this.hatchType; + } + /** * @param flag */ @@ -1003,6 +1138,10 @@ public void setViewCleared(boolean b) { this.isViewCleared = b; } + public Graphics2D getG2d() { + return this.g2d; + } + } /* diff --git a/src/net/sf/jcgm/core/DashType.java b/src/net/sf/jcgm/core/DashType.java index d02531b..95144b0 100644 --- a/src/net/sf/jcgm/core/DashType.java +++ b/src/net/sf/jcgm/core/DashType.java @@ -31,7 +31,19 @@ public class DashType { public final static int DASH = 2; public final static int DOT = 3; public final static int DASH_DOT = 4; - public final static int DASH_DOT_DOT = 5; + public final static int DASH_DOT_DOT = 5; + // line types later registered with the ISO/IEC 9973 Items Register + public final static int SINGLE_ARROW = 6; + public final static int SINGLE_DOT = 7; + public final static int DOUBLE_ARROW = 8; + public final static int STITCH_LINE = 9; + public final static int CHAIN_LINE = 10; + public final static int CENTER_LINE = 11; + public final static int HIDDEN_LINE = 12; + public final static int PHANTOM_LINE = 13; + public final static int BREAK_LINE_1_FREE_HAND = 14; + public final static int BREAK_LINE_1_ZIG_ZAG = 15; + } /* diff --git a/src/net/sf/jcgm/core/HatchIndex.java b/src/net/sf/jcgm/core/HatchIndex.java index 2bb7444..dbd67d1 100644 --- a/src/net/sf/jcgm/core/HatchIndex.java +++ b/src/net/sf/jcgm/core/HatchIndex.java @@ -32,33 +32,39 @@ * @since Jun 10, 2009 */ public class HatchIndex extends Command { - enum HatchType { + public enum HatchType { HORIZONTAL_LINES, VERTICAL_LINES, POSITIVE_SLOPE_LINES, NEGATIVE_SLOPE_LINES, HORIZONTAL_VERTICAL_CROSSHATCH, POSITIVE_NEGATIVE_CROSSHATCH } - + HatchType type = HatchType.HORIZONTAL_LINES; public HatchIndex(int ec, int eid, int l, DataInput in) throws IOException { super(ec, eid, l, in); - + int index = makeIndex(); switch (index) { + case -1: case 1: this.type = HatchType.HORIZONTAL_LINES; break; + case -2: case 2: this.type = HatchType.VERTICAL_LINES; break; + case -3: case 3: this.type = HatchType.POSITIVE_SLOPE_LINES; break; + case -4: case 4: this.type = HatchType.NEGATIVE_SLOPE_LINES; break; + case -5: case 5: this.type = HatchType.HORIZONTAL_VERTICAL_CROSSHATCH; break; + case -6: case 6: this.type = HatchType.POSITIVE_NEGATIVE_CROSSHATCH; break; diff --git a/src/net/sf/jcgm/core/Polyline.java b/src/net/sf/jcgm/core/Polyline.java index 1f26365..7a96d98 100644 --- a/src/net/sf/jcgm/core/Polyline.java +++ b/src/net/sf/jcgm/core/Polyline.java @@ -36,45 +36,69 @@ */ public class Polyline extends Command { private final Path2D.Double path; + private Point2D.Double firstPoint = null; + private Point2D.Double secondPoint = null; - public Polyline(int ec, int eid, int l, DataInput in) - throws IOException { - super(ec, eid, l, in); + private Point2D.Double beforelastPoint = null; + private Point2D.Double lastPoint = null; - int n = this.args.length / sizeOfPoint(); + public Polyline(int ec, int eid, int l, DataInput in) + throws IOException { + super(ec, eid, l, in); - this.path = new Path2D.Double(); + int n = this.args.length / sizeOfPoint(); - for (int i = 0; i < n; i++) { - Point2D.Double point = makePoint(); - if (i == 0) { - this.path.moveTo(point.x, point.y); - } - else { - this.path.lineTo(point.x, point.y); - } - } + this.path = new Path2D.Double(); - // make sure all the arguments were read - assert (this.currentArg == this.args.length); - } + for (int i = 0; i < n; i++) { + Point2D.Double point = makePoint(); + if (i == 0) { + this.path.moveTo(point.x, point.y); + } + else { + this.path.lineTo(point.x, point.y); + } + if(i==0) + this.firstPoint=point; + if(i==1) + this.secondPoint=point; + if(i==n-2) + this.beforelastPoint=point; + if(i==n-1) + this.lastPoint=point; - @Override + } + + // make sure all the arguments were read + assert (this.currentArg == this.args.length); + } + + @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Polyline ["); - sb.append(printShape(this.path)); - sb.append("]"); - return sb.toString(); - } - - @Override + StringBuilder sb = new StringBuilder(); + sb.append("Polyline ["); + sb.append(printShape(this.path)); + sb.append("]"); + return sb.toString(); + } + + @Override public void paint(CGMDisplay d) { - Graphics2D g2d = d.getGraphics2D(); + Graphics2D g2d = d.getGraphics2D(); g2d.setColor(d.getLineColor()); g2d.setStroke(d.getLineStroke()); g2d.draw(this.path); - } + + + + if(d.getLineType() == DashType.SINGLE_ARROW) { + d.drawArrow(this.lastPoint,this.beforelastPoint); + } + if(d.getLineType() == DashType.DOUBLE_ARROW) { + d.drawArrow(this.lastPoint,this.beforelastPoint); + d.drawArrow(this.firstPoint,this.secondPoint); + } + } } /* diff --git a/src/net/sf/jcgm/core/Tile.java b/src/net/sf/jcgm/core/Tile.java index a5b52a3..5cdca23 100644 --- a/src/net/sf/jcgm/core/Tile.java +++ b/src/net/sf/jcgm/core/Tile.java @@ -86,7 +86,10 @@ public void paint(CGMDisplay d) { if(x>=width) { x=0; y++; - } + } + if(y>=height) { + break; + } } this.bufferedImage=imageOut;