IDML Filter (M34): NoSuchElementException if Polygon element does not have AnchorPoints

Issue #618 resolved
Jan Pascal Maas created an issue

We discovered an issue with the new IDML-Filter which is introduced with M34. Especially, this differs from the old IDML-Filter. A minimal breaking example can be found in the attachments.

Consider the following Polygon element:

<Polygon Self="uadf" ContentType="Unassigned" StoryTitle="$ID/" FillColor="Color/S-GE Cadmium Red" OverprintFill="true" StrokeWeight="1" MiterLimit="10" GradientFillStart="0 0" GradientFillLength="0" GradientFillAngle="0" GradientStrokeStart="0 0" GradientStrokeLength="0" GradientStrokeAngle="0" ItemLayer="u189" Locked="false" LocalDisplaySetting="Default" GradientFillHiliteLength="0" GradientFillHiliteAngle="0" GradientStrokeHiliteLength="0" GradientStrokeHiliteAngle="0" AppliedObjectStyle="ObjectStyle/$ID/[None]" Visible="true" Name="$ID/" ItemTransform="1 0 0 1 583.9227852069107 264.5312725317937">
    <Properties>
        <PathGeometry>
            <GeometryPathType PathOpen="false">
                <PathPointArray>
                </PathPointArray>
            </GeometryPathType>
        </PathGeometry>
    </Properties>
    <TextWrapPreference Inverse="false" ApplyToMasterPageOnly="false" TextWrapSide="BothSides" TextWrapMode="None">
        <Properties>
            <TextWrapOffset Top="0" Left="0" Bottom="0" Right="0"/>
        </Properties>
    </TextWrapPreference>
    <InCopyExportOption IncludeGraphicProxies="true" IncludeAllResources="false"/>
</Polygon>

Note that the PathPointArrayis empty. This leads to an NoSuchElementException when searching for the minimum AnchorPoint by direction. Stacktrace:

Exception!java.util.NoSuchElementException: null
    at java.util.ArrayList$Itr.next(ArrayList.java:854) ~[na:1.8.0_121]
    at java.util.Collections.min(Collections.java:635) ~[na:1.8.0_121]
    at net.sf.okapi.filters.idml.PasteboardItem.getMinAnchorPointByDirection(PasteboardItem.java:73) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.filters.idml.PasteboardItem$PasteboardItemComparator.compare(PasteboardItem.java:121) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.filters.idml.PasteboardItem$PasteboardItemComparator.compare(PasteboardItem.java:97) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at java.util.TimSort.binarySort(TimSort.java:296) ~[na:1.8.0_121]
    at java.util.TimSort.sort(TimSort.java:239) ~[na:1.8.0_121]
    at java.util.Arrays.sort(Arrays.java:1512) ~[na:1.8.0_121]
    at java.util.ArrayList.sort(ArrayList.java:1454) ~[na:1.8.0_121]
    at java.util.Collections.sort(Collections.java:175) ~[na:1.8.0_121]
    at net.sf.okapi.filters.idml.OrderingIdioms.sortPasteboardItems(OrderingIdioms.java:106) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.filters.idml.OrderingIdioms.getOrderedPasteboardItems(OrderingIdioms.java:48) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.filters.idml.Document.open(Document.java:110) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.filters.idml.IDMLFilter.openDocument(IDMLFilter.java:276) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.filters.idml.IDMLFilter.next(IDMLFilter.java:202) ~[okapi-filter-idml-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.steps.common.RawDocumentToFilterEventsStep.handleEvent(RawDocumentToFilterEventsStep.java:136) ~[okapi-step-common-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.common.pipeline.Pipeline.execute(Pipeline.java:119) ~[okapi-core-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.common.pipeline.Pipeline.process(Pipeline.java:231) ~[okapi-core-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.common.pipeline.Pipeline.process(Pipeline.java:201) ~[okapi-core-0.34.24t.20170523.01.jar!/:na]
    at net.sf.okapi.common.pipelinedriver.PipelineDriver.processBatch(PipelineDriver.java:182) ~[okapi-core-0.34.24t.20170523.01.jar!/:na]

Comments (8)

  1. Chase Tingley

    Thanks Jan Pascal. This looks like a straightforward fix, but I would like @DenisKonovalyenko to take a look since this is in his ordering code and I'm not 100% sure of the correct behavior here without doing a bunch of research. Denis is on vacation for a couple weeks but should be able to look at this in July. Let me know if you want to try to fix it yourself.

  2. Denis Konovalyenko

    I have taken a look at the issue from UX prospective and would like to share the results.

    Firstly, I was able to export to IDML format of 6.0(352) version with my InDesign CS4. The original document was marked as 7.0(553) version and the resulted output was strange on opening (but will give it one more try on my working place with the latest InDesign).

    By now, I have found out that the objects, which do not have any path point, are not shown at all, and if those have text, an error message appears. For more details please refer to the attached before/after-manually-removed-path-points files.

    Furthermore, if all path points are removed with the help of InDesign tool, the objects are not even present in the document structures after saving a document. For more details please refer to the before/after-removed-by-indesign-path-points files.

    So, taking all the above into account, I think, it would be safe to skip such objects early on spreads parsing stage.

    @jpmaas_24t, @tingley, what are your thoughts on all that?

  3. Denis Konovalyenko
  4. Denis Konovalyenko

    The InDesign on my working machine renders the same strange output (for more details please refer to the MBE3-opened-with-missing-fonts.png).

    After surfing over the code base, I ended up with a solution which simply compares spread items with empty path points. There is a simple ability to mimic the InDesign behaviour of not showing objects without path points, but that would be only possible for objects which are not anchored or placed inline:

           List<PasteboardItem> filterVisible(List<PasteboardItem> pasteboardItems) {
    
                List<PasteboardItem> visiblePasteboardItems = new ArrayList<>(pasteboardItems.size());
    
                for (PasteboardItem pasteboardItem : pasteboardItems) {
                    if (pasteboardItem.getAnchorPoints().isEmpty()) {
                        continue;
                    }
    
                    Layer layer = getLayerById(pasteboardItem.getTextualSpreadItem().getLayerId(), layers);
    ...
    

    A full blown solution will require us to provide a better grained ordering for inline or anchored story element (Frame, Rectangular, etc) first. Currently, there is the following known limitation - the referent story is not placed right after the one, which has such "anchor reference" to it, but put at the end of all stories instead.

    Will create a pull request shortly.

  5. Log in to comment