archimatetool / archi

Archi: ArchiMate Modelling Tool
https://www.archimatetool.com
MIT License
970 stars 270 forks source link

Export View as Image - Scale > 100% cuts off text #621

Closed smileham closed 4 years ago

smileham commented 4 years ago

Version of Archi

4.6 (and 4.7 beta 1)

Operating System

Windows 10 (also seen in Windows 7)

Expected Behaviour

Export View as Image to Raster Format, all ArchiMate component labels are visible.

100% export Key (Basic) - 100%

Actual Behaviour

Export View as Image to Raster Format, however, all text elements are trimmed on the right hand side

200% export Key (Basic) - 200%

Steps to Reproduce the Behaviour

  1. Export View as Image
  2. Format PNG/BMP/JPEG
  3. Set scale to 400%
  4. View is exported to Raster Format, however, all text elements are trimmed on the right hand side

Note: Same issue appears when scaling the interface in the view.

Phillipus commented 4 years ago

Are you using a particular font for the elements where the text is trimmed?

Are you using a hi-res monitor?

smileham commented 4 years ago

Seems to happen on any font > size 9, this font is Roboto, but the same happens with many other fonts.

Not a High Res monitor

jbsarrodie commented 4 years ago

This is an issue on the underlaying drawing engine (draw2d) when used with a zoom other than 100%.

Zoom has always had this impact on fonts been zoomed a bit more and then cropped on the right.

When exporting at zoom factor other than 100% I've always had such glitches (that's why I always work at 100%).

@Phillipus This is really annoying but I tried several time to fix it without success :-(

Phillipus commented 4 years ago

Yes, I see the same thing with some fonts (but not all).

If you increase the zoom level in the Archi View to 200% or more you'll also see the same thing.

This is a problem with some fonts on some platforms. You might see clipping on Arial font @ 200% on Windows but not on Mac, for example. Some fonts are OK, while some are not, depending on zoom level and OS.

Unfortunately, the rendering is done by the Eclipse Draw2D library (which is why you will sometimes see clipping at a greater zoom level in Archi)

Phillipus commented 4 years ago

This is an issue on the underlaying drawing engine (draw2d) when used with a zoom other than 100%.

You posted at the same time as me.

but I tried several time to fix it without success

I would put my money on org.eclipse.draw2d.ScaledGraphics.

jbsarrodie commented 4 years ago

You posted at the same time as me.

I was first ;-)

This is a problem with some fonts on some platforms. You might see clipping on Arial font @ 200% on Windows but not on Mac, for example. Some fonts are OK, while some are not, depending on zoom level and OS.

Interesting, I never tested this on different OS, this might help to understand the issue...

I would put my money on org.eclipse.draw2d.ScaledGraphics.

Yes, That's where I looked at...

jbsarrodie commented 4 years ago

FWIW, thee is a similar issue when rendering in SVG in some occasions (text clipping area too short).

Phillipus commented 4 years ago

I was first ;-)

Only because I took a sip of my tea before posting.

I would put my money on org.eclipse.draw2d.ScaledGraphics

There's lots of font handling going on in that class. Even if one were to extend and fix that class to use on image export it is used internally by Draw2D for the editor drawing.

jbsarrodie commented 4 years ago

There's lots of font handling going on in that class. Even if one were to extend and fix that class to use on image export it is used internally by Draw2D for the editor drawing.

But if we understand the issue, maybe we would be able to change the font size we use depending on the zoom factor to compensate ;-)

Phillipus commented 4 years ago

But if we understand the issue

We need a maths/graphics guru... ;-)

jbsarrodie commented 4 years ago

image

jbsarrodie commented 4 years ago

We need a maths/graphics guru... ;-)

You need Jaiguru ;-)

jbsarrodie commented 4 years ago

@Phillipus do you know if simple GEF examples (like the "Logic Diagram") exibit the same issue ?

Phillipus commented 4 years ago

do you know if simple GEF examples (like the "Logic Diagram") exibit the same issue ?

It depends whether it uses a ScalableFreeformLayeredPane or a ScalableLayeredPane. These use scaled graphics, not sure if Logic Diagram does (I can't even get it to run as there is a bug in GEF examples plugin)

jbsarrodie commented 4 years ago

Edit: forgot about it, streching factor is the same (but as each individual label's position is kept, space before a word is not streched).

~I've done several tests, and it seems that when the label runs on several lines, each line gets streched horizontaly with a factor which seems random:~

~This is a superposition of the same figure at 100% and 200%:~ image

~If I shrink the zoomed figure so that the first line superposes here is what I get:~ image

~And if I try to make the bottom line to match:~ image

~Maybe an issue with individual labels in the context of a TextFlow/BlockFlow...~

jbsarrodie commented 4 years ago

So to summarize, font seems to get streched horizontally only (not vertically).

Could it be a side effect of FontFactory.getAdjustedWindowsFont() ?

(all my tests are done on Windows)

Phillipus commented 4 years ago

Could it be a side effect of FontFactory.getAdjustedWindowsFont() ?

That only adjusts the font if the user has set Windows to non-100% scale.

Phillipus commented 4 years ago

Maybe an issue with individual labels in the context of a TextFlow/BlockFlow...

BTW - latest commits in text-render branch eliminate the need for a BlockFlow figure and has simplified Text figures.

Perhaps the way to proceed is to create a class that extends org.eclipse.draw2d.ScaledGraphics and use it in DiagramUtils#createModelReferencedImage() :

if(scale != 1) {
   graphics = new ScaledGraphics(swtGraphics); // Use new class here
   graphics.scale(scale);
}

Then see what's happening when exporting an image at 200%

Edit: or add breakpoints in org.eclipse.draw2d.ScaledGraphics

Phillipus commented 4 years ago

@jbsarrodie Actually it might have something to do with TextFlow figure. A Sketch Actor figure text in a Sketch is not clipping. That uses a org.eclipse.draw2d.Label.

Also worth checking relationship labels before and after recent changes (used to be a Label now is a TextFlow)

Phillipus commented 4 years ago

Also worth checking relationship labels before and after recent changes (used to be a Label now is a TextFlow)

Still the same.

Test case is:

Image 1

Phillipus commented 4 years ago
  1. A bug in org.eclipse.draw2d.ScaledGraphics?
  2. Something to do with TextFlow/FlowPage/Paragraphing?
  3. But text is also clipping when using a org.eclipse.draw2d.Label on a connection
Phillipus commented 4 years ago

@jbsarrodie Edit com.archimatetool.editor.diagram.figures.elements.BusinessActorFigure constructor to use LABEL_CONTROL instead of TEXT_FLOW_CONTROL and there is no clipping.

jbsarrodie commented 4 years ago

@jbsarrodie Edit com.archimatetool.editor.diagram.figures.elements.BusinessActorFigure constructor to use LABEL_CONTROL instead of TEXT_FLOW_CONTROL and there is no clipping.

Yes, but not for a good reason: text is still streched but not clipped by the TextFlow (which is created with its own margin and thus clipping the internal text elements)

jbsarrodie commented 4 years ago

Yes, but not for a good reason: text is still streched but not clipped by the TextFlow (which is created with its own margin and thus clipping the internal text elements)

That being said, this might lead to a kind of workaround: changing the way the margin are set so that clipping only occures on the Figure. This won't fix the root cause, but few people will notice the issue ;-)

Phillipus commented 4 years ago

That being said, this might lead to a kind of workaround: changing the way the margin are set so that clipping only occures on the Figure. This won't fix the root cause, but few people will notice the issue ;-)

Not sure what what you mean? (BTW best to work on figures in text-render branch because of recent changes)

Phillipus commented 4 years ago

Tried this on Mac (10.15.4) and could not get the text to clip at zoom levels > 100% with several fonts and font sizes. Have not tried with Linux.

jbsarrodie commented 4 years ago

Have not tried with Linux.

I did and have the same issue, so this is not OS specific.

jbsarrodie commented 4 years ago

We're not the only one with this bug: https://www.eclipse.org/forums/index.php/t/154575/

(reading it and related issue at the moment)

Phillipus commented 4 years ago

We're not the only one with this bug: https://www.eclipse.org/forums/index.php/t/154575/

That suggests the problem is in TextFlow, however I can see the same problem when we were using a Label in AbstractDiagramConnectionFigure (above https://github.com/archimatetool/archi/issues/621#issuecomment-627322111)

Phillipus commented 4 years ago

Experimented with the version of com.archimatetool.editor.diagram.figures.connections.AbstractDiagramConnectionFigure in master branch that uses a Label

Over-ride Label to add an extra 10 pixels to the text width:

fConnectionLabel = new Label("") {
    protected Dimension calculateTextSize() {
        Dimension d = super.calculateTextSize();
        d.width += 10;
        return d;
    }
};

Fixes the issue in https://github.com/archimatetool/archi/issues/621#issuecomment-627322111

Note that Label#calculateTextSize() is this:

protected Dimension calculateTextSize() {
    return getTextUtilities().getTextExtents(getText(), getFont());
}

So perhaps the issue is in org.eclipse.draw2d.TextUtilities

Phillipus commented 4 years ago

I would say that the issue is in org.eclipse.draw2d.TextUtilities.

However, for a TextFlow it is indirectly accessed via org.eclipse.draw2d.text.FlowUtilities

So, the following hack works:

TextFlow textFlow = new TextFlow() {
    @Override
    protected FlowUtilities getFlowUtilities() {
        FlowUtilities fu = new FlowUtilities() {
            @Override
            protected TextUtilities getTextUtilities() {
                TextUtilities tu = new TextUtilities() {
                    @Override
                    public Dimension getTextExtents(String s, Font f) {
                        Dimension d = super.getTextExtents(s, f);
                        d.width += 8;
                        return d;
                    }
                };
                return tu;
            }
        };
        return fu;
    }
};

This adds on an extra 8 pixels to the text extends width in getTextExtents(). So maybe this should take into account the zoom factor?

Phillipus commented 4 years ago

Actually we should look at org.eclipse.draw2d.FigureUtilities because in org.eclipse.draw2d.TextUtilities:

public Dimension getTextExtents(String s, Font f) {
    return FigureUtilities.getTextExtents(s, f);
}

Which ends up at this:

protected static org.eclipse.swt.graphics.Point getTextDimension(String s,
        Font f) {
    setFont(f);
    return getGC().textExtent(s);
}
Phillipus commented 4 years ago

My money is on org.eclipse.draw2d.FigureUtilities and zoom factor.

Phillipus commented 4 years ago

Here's a hack:

    static FlowUtilities flowUtilities = new FlowUtilities() {
        @Override
        protected TextUtilities getTextUtilities() {
            return textUtilities;
        }
    };

    static TextUtilities textUtilities = new TextUtilities() {
        @Override
        public Dimension getTextExtents(String s, Font f) {
            Dimension d = super.getTextExtents(s, f);
            d.width *= 1.1;
            return d;
        }
    };

    TextFlow textFlow = new TextFlow() {
        @Override
         protected FlowUtilities getFlowUtilities() {
            return flowUtilities;
         }
    };
Phillipus commented 4 years ago

@jbsarrodie There's a new branch with the hack in it text-hack

jbsarrodie commented 4 years ago

You've ended up with almost the same hack as me yesterday evening (mine also shrink a bit the Graphics before drawing the label at zoom factors other than 100%).

But these are hacks and and don't always work (I have seen cases were the width difference is more than 10%).

In fact the issue lies in the way org.eclipse.draw2d.FigureUtilities#getTextExtents() is called and implemented:

So the path I'm following (and I have to experiment) is to find a better way to implement org.eclipse.draw2d.FigureUtilities#getTextExtents() so that it takes the zoom factor into account:

Phillipus commented 4 years ago

How are you getting the zoom factor? graphics#getAbsoluteScale() ?

jbsarrodie commented 4 years ago

How are you getting the zoom factor? graphics#getAbsoluteScale() ?

Yes, that's how I get it (don't know if there's better option or side effects).

Phillipus commented 4 years ago

That's the only way to get it, really, at the point of drawing the graphics.

jbsarrodie commented 4 years ago

Re font zooming in ScaledGraphics this seems to be as simple as return (int) (zoom * height) (see zoomFontHeight), but there might be some hiddent computation on GC.

FWIW:

BTW: What I still really don't know is if it is "normal" for fonts to be a bit stretched or shrinked at some font size (in such case, text layout is impacted by zoom factor and in some occasion TextFlow will have to change the layout based on it), or if this is only an eclipse (or swt) issue (in such case it could be needed to dynamically change the font height depending on the zoom factor so that text layout is not impacted).

Phillipus commented 4 years ago

image

jbsarrodie commented 4 years ago

So the path I'm following (and I have to experiment) is to find a better way to implement org.eclipse.draw2d.FigureUtilities#getTextExtents() so that it takes the zoom factor into account

I have an issue for this: how can I get the current ScaledGraphics object? Any idea?

Phillipus commented 4 years ago

I have an issue for this: how can I get the current ScaledGraphics object? Any idea?

Where are you trying to get it? if(graphics instanceof ScaledGraphics) ?

jbsarrodie commented 4 years ago

Where are you trying to get it? if(graphics instanceof ScaledGraphics) ?

I'm in our patched TextUtilities#getTextExtents() called by our patched TextFlow#getFlowUtilities() called by...

So I'm deep in the code called each time the layout has to be recomputed before painting the figure (Figure#layout()).

Looking at the stack trace, maybe I can get the zoom factor from ScalableFreeformLayeredPane: image

So my only idea atm is to use Figure.getParent() until I reach one which implements org.eclipse.draw2d.ScalableFigure...

Phillipus commented 4 years ago

But you can't use the zoom factor as set in the editor, because it won't work when exporting the image at different scales (that doesn't take the zoom factor into account)

Phillipus commented 4 years ago

Look at DiagramUtils#createModelReferencedImage() it is independent of the GEF Zoom Manager.

jbsarrodie commented 4 years ago

But you can't use the zoom factor as set in the editor, because it won't work when exporting the image at different scales (that doesn't take the zoom factor into account)

Yes, but my first step it to test and see if my idea works. If it does, then I'll see how to do it the right way.

jbsarrodie commented 4 years ago

Still investigating...

Potentially useful references:

In short, ScaledGraphics is deprecated, but someone shared a potential workaround.

Phillipus commented 4 years ago

"and replace its usages with direct scaling of the underlying SWTGraphics."

Interesting.

(Go and drink some wine or something ;-) )

jbsarrodie commented 4 years ago

Interesting

~Just tested but doesn't work. Still investigating...~ It does work. Read below