Skip to content

Honour plot style table color for ACI 7 - #1401

Open
rafaelfrancisco-contato wants to merge 1 commit into
mozman:masterfrom
rafaelfrancisco-contato:fix-ctb-aci7-color
Open

Honour plot style table color for ACI 7#1401
rafaelfrancisco-contato wants to merge 1 commit into
mozman:masterfrom
rafaelfrancisco-contato:fix-ctb-aci7-color

Conversation

@rafaelfrancisco-contato

Copy link
Copy Markdown

Honour plot style table color for ACI 7

Problem

RenderContext(doc, ctb=...) applies the plot style table color for every ACI
except 7. Since ACI 7 is the default color of layer 0 and by far the most common
color in engineering drawings, a CTB that maps ACI 7 to black is silently ignored and
those entities render white — invisible when plotting onto white paper.

Reproducer with the current code:

import tempfile
from pathlib import Path

import ezdxf
from ezdxf.addons import acadctb
from ezdxf.addons.drawing import RenderContext

tmp = Path(tempfile.mkdtemp())
ctb = tmp / "all_red.ctb"
table = acadctb.new_ctb()
for aci in range(1, 256):
    table[aci].color = (255, 0, 0)     # every ACI plots red
table.save(str(ctb))

doc = ezdxf.new("R2018", setup=True)
msp = doc.modelspace()
for aci in (1, 2, 7, 8):
    msp.add_line((0, aci), (10, aci), dxfattribs={"color": aci})

ctx = RenderContext(doc, ctb=str(ctb))
for entity in msp:
    print(entity.dxf.color, ctx.resolve_color(entity)[:7])
1 #ff0000
2 #ff0000
7 #ffffff   <-- expected #ff0000
8 #ff0000

The practical case is BYLAYER on layer 0, which defaults to ACI 7:

msp.add_line((0, 0), (10, 0), dxfattribs={"layer": "0", "color": 256})
# CTB says black -> resolve_color() returns #ffffff

On a real title block this silently dropped 4 ACAD_TABLE/INSERT entities from the plot.
Plotting the same drawing and CTB through AutoCAD 2025 renders them black.

resolve_lineweight() already handles ACI 7 correctly, which is what suggested to me
this is an oversight in the color path rather than intended behaviour.

Cause

Two places bypass the plot style table for ACI 7:

  • RenderContext._aci_to_true_color — direct entity color
  • RenderContext.resolve_layer_properties — sets has_aci_color_7, which later makes
    LayerProperties.get_entity_color_from_layer return the layout foreground instead of
    the layer color (the BYLAYER path)

I understand the special case comes from #227: ACI 7 has to follow the background
(white on dark, black on light). That is right while ACI 7 is ambiguous — but a
plot style table is an explicit instruction that resolves the ambiguity, so it should
win.

Change

Both places now consult the table first and fall back to the background-dependent
default only when the table expresses no opinion for ACI 7.

Detecting "expresses no opinion" needed a small addition: _load_plot_style_table()
fills every entry that has_object_color() with the default AutoCAD palette, so after
loading the table can no longer tell the two cases apart. The set of ACI values the
table really overrides is now recorded during that same pass, as forced_colors.

That method can run more than once over the same table (set_current_layout(),
from_viewport()), so the detection is guarded to happen on the first pass only —
without that guard every ACI ends up looking "forced" on the second run. This is
covered by test_plot_style_without_color_keeps_background_behavior.

Tests

Four new tests in TestPlotStyleOverridesACIColor7:

  • explicit ACI 7 uses the plot style color
  • BYLAYER on layer 0 uses the plot style color
  • other ACI values are unaffected
  • a table with no color for ACI 7 keeps the current background-dependent behaviour
    (both dark and light background)

Verified that the first two fail without this change and pass with it.

Full suite: 7508 passed, 71 skipped, 1 xfailed (7504 before, plus the 4 new ones).
No existing test changed behaviour — in particular TestResolveLayerACIColor7, which
covers the no-CTB case from #227, still passes untouched.

On the real drawing that surfaced this, the title block now resolves 159/159 entities
to black instead of 155 black + 4 white.

RenderContext applied the plot style table color for every ACI except 7. As
ACI 7 is the default color of layer '0' and the most common color in
engineering drawings, a CTB mapping ACI 7 to black was silently ignored and
those entities rendered white - invisible when plotting onto white paper.

Two places bypassed the table:

  - _aci_to_true_color(), for the direct entity color
  - resolve_layer_properties(), which sets has_aci_color_7 and thereby makes
    get_entity_color_from_layer() return the layout foreground instead of the
    layer color (the BYLAYER path)

The ACI 7 special case comes from mozman#227: ACI 7 has to follow the background
color, white on dark and black on light. That holds while ACI 7 is ambiguous,
but a plot style table is an explicit instruction that resolves the ambiguity
and should win - which is what AutoCAD does.

Both places now consult the table first and fall back to the background
dependent default only when the table expresses no opinion for ACI 7.

Detecting "no opinion" needed a small addition: _load_plot_style_table() fills
every entry that has_object_color() with the default AutoCAD palette, so
afterwards the table can no longer tell the two cases apart. The set of ACI
values the table really overrides is now recorded during that same pass, as
forced_colors. That method can run more than once over the same table (see
set_current_layout() and from_viewport()), so the detection is guarded to the
first pass - without the guard every ACI ends up looking forced on the second
run.

Four new tests in TestPlotStyleOverridesACIColor7 cover: explicit ACI 7, the
BYLAYER-on-layer-0 case, other ACI values being unaffected, and a table with no
color for ACI 7 keeping the current background dependent behaviour on both dark
and light backgrounds. The first two fail without this change.

Full suite: 7508 passed, 71 skipped, 1 xfailed. TestResolveLayerACIColor7,
which covers the no-CTB case from mozman#227, passes untouched.
@mozman

mozman commented Aug 19, 2026

Copy link
Copy Markdown
Owner

FYI: This was never planned and never will be a perfect DXF viewer! 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants