Skip to content

Commit 15ddf41

Browse files
authored
ICML writer support for image object styles (#11498)
This change allows users to style images in InDesign bysetting the `object-style` attribute in a pandoc Image, which is mapped to the AppliedObjectStyle attribute in the Rectangle element around an Image element in the resulting ICML.
1 parent aab9965 commit 15ddf41

5 files changed

Lines changed: 182 additions & 19 deletions

File tree

MANUAL.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7717,6 +7717,14 @@ custom-style `span`.
77177717
For docx or odt output, you don't need to enable any extensions for
77187718
custom styles to work.
77197719

7720+
For icml output, you can also set an `object-style` in images:
7721+
7722+
![Image with object style](myImage.jpg){object-style="fixedSizeImage"}
7723+
7724+
In InDesign you'll see that object style given to the image,
7725+
and you'll be able to customize it, or load its definition from
7726+
a template of yours.
7727+
77207728
[pandoc filters]: https://pandoc.org/filters.html
77217729

77227730
## Input

data/templates/default.icml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
<RootCellStyleGroup Self="pandoc_cell_styles">
2929
<CellStyle Self="CellStyle/Cell" AppliedParagraphStyle="ParagraphStyle/$$ID/[No paragraph style]" Name="Cell" />
3030
</RootCellStyleGroup>
31+
$if(objectStyles)$
32+
<RootObjectStyleGroup Self="pandoc_object_styles">
33+
$objectStyles$
34+
</RootObjectStyleGroup>
35+
$endif$
3136
<Story Self="pandoc_story"
3237
TrackChanges="false"
3338
StoryTitle="$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$"

src/Text/Pandoc/Writers/ICML.hs

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Hyperlink = [(Int, Text)]
4444
data WriterState = WriterState{
4545
blockStyles :: Set.Set Text
4646
, inlineStyles :: Set.Set Text
47+
, objectStyles :: Set.Set Text
4748
, links :: Hyperlink
4849
, listDepth :: Int
4950
, maxListDepth :: Int
@@ -55,6 +56,7 @@ defaultWriterState :: WriterState
5556
defaultWriterState = WriterState{
5657
blockStyles = Set.empty
5758
, inlineStyles = Set.empty
59+
, objectStyles = Set.empty
5860
, links = []
5961
, listDepth = 1
6062
, maxListDepth = 0
@@ -147,9 +149,10 @@ writeICML opts doc = do
147149
meta
148150
(main, st) <- runStateT (blocksToICML opts [] blocks) defaultWriterState
149151
let context = defField "body" main
150-
$ defField "charStyles" (charStylesToDoc st)
151-
$ defField "parStyles" (parStylesToDoc st)
152-
$ defField "hyperlinks" (hyperlinksToDoc $ links st) metadata
152+
$ defField "charStyles" (charStylesToDoc st)
153+
$ defField "parStyles" (parStylesToDoc st)
154+
$ defField "objectStyles" (objectStylesToDoc st)
155+
$ defField "hyperlinks" (hyperlinksToDoc $ links st) metadata
153156
return $ render colwidth $
154157
(if writerPreferAscii opts then fmap toEntities else id) $
155158
case writerTemplate opts of
@@ -272,6 +275,16 @@ charStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ inlineStyles st
272275
else empty
273276
in inTags True "CharacterStyle" ([("Self", "CharacterStyle/"<>s), ("Name", s)] ++ attrs') props
274277

278+
-- | Convert a WriterState with its object styles to the ICML listing of Object Styles.
279+
objectStylesToDoc :: WriterState -> Doc Text
280+
objectStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ objectStyles st
281+
where
282+
makeStyle s =
283+
let attrs = []
284+
props = inTags True "Properties" [] $
285+
inTags False "BasedOn" [("type", "string")] (text "$ID/None")
286+
in inTags True "ObjectStyle" ([("Self", "ObjectStyle/"<>s), ("Name", s)] ++ attrs) props
287+
275288
-- | Escape colon characters as %3a
276289
escapeColons :: Text -> Text
277290
escapeColons txt = Text.replace ":" "%3a" txt
@@ -601,6 +614,10 @@ styleToStrAttr style =
601614
attrs = [("AppliedCharacterStyle", stl)]
602615
in (stlStr, attrs)
603616

617+
-- | Key for specifying user-defined object (image) styles
618+
objectStyleKey :: Text
619+
objectStyleKey = "object-style"
620+
604621
-- | Assemble an ICML Image.
605622
imageICML :: PandocMonad m => WriterOptions -> Style -> Attr -> Target -> WS m (Doc Text)
606623
imageICML opts style attr (src, _) = do
@@ -647,19 +664,31 @@ imageICML opts style attr (src, _) = do
647664
then mempty
648665
else selfClosingTag "Link" [("Self", "ueb"),
649666
("LinkResourceURI", src')]
650-
image = inTags True "Image"
651-
[("Self","ue6"), ("ItemTransform", scale<>" -"<>hw<>" -"<>hh)]
652-
$ vcat [
653-
inTags True "Properties" [] $ vcat [
654-
inTags True "Profile" [("type","string")] $ text "$ID/Embedded"
655-
, selfClosingTag "GraphicBounds" [("Left","0"), ("Top","0")
656-
, ("Right", showFl $ ow*ow / imgWidth)
657-
, ("Bottom", showFl $ oh*oh / imgHeight)]
658-
, contents
659-
]
660-
, link
661-
]
662-
doc = inTags True "CharacterStyleRange" attrs
663-
$ inTags True "Rectangle" [("Self","uec"), ("StrokeWeight", "0"),
664-
("ItemTransform", scale<>" "<>hw<>" -"<>hh)] (props $$ image)
665-
state $ \st -> (doc, st{ inlineStyles = Set.insert stlStr $ inlineStyles st } )
667+
(_,_,kvs) = attr
668+
applyObjectStyle = lookup objectStyleKey kvs
669+
image = inTags True "Image"
670+
[("Self","ue6"), ("ItemTransform", scale <> " -" <> hw <> " -" <> hh)]
671+
$ vcat [
672+
inTags True "Properties" [] $ vcat [
673+
inTags True "Profile" [("type","string")] $ text "$ID/Embedded",
674+
selfClosingTag "GraphicBounds" [("Left","0"), ("Top","0"),
675+
("Right", showFl $ ow * ow / imgWidth),
676+
("Bottom", showFl $ oh * oh / imgHeight)],
677+
contents
678+
],
679+
link
680+
]
681+
doc = inTags True "CharacterStyleRange" attrs
682+
$ inTags True "Rectangle"
683+
([("Self","uec"),
684+
("StrokeWeight", "0"),
685+
("ItemTransform", scale <> " " <> hw <> " -" <> hh)] ++
686+
maybe [] (\aos -> [("AppliedObjectStyle", "ObjectStyle/" <> aos)]) applyObjectStyle
687+
)
688+
(props $$ image)
689+
state $ \st -> (doc, st{
690+
inlineStyles = Set.insert stlStr $ inlineStyles st,
691+
objectStyles = case applyObjectStyle of
692+
Just styleName -> Set.insert styleName $ objectStyles st
693+
Nothing -> objectStyles st
694+
})

test/command/11498.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
```
2+
% pandoc -f markdown -t icml
3+
![](command/11498.png){object-style="myStyle"}
4+
^D
5+
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
6+
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
7+
<Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 32 -32" AppliedObjectStyle="ObjectStyle/myStyle">
8+
<Properties>
9+
<PathGeometry>
10+
<GeometryPathType PathOpen="false">
11+
<PathPointArray>
12+
<PathPointType Anchor="-32 -32" LeftDirection="-32 -32" RightDirection="-32 -32" />
13+
<PathPointType Anchor="-32 32" LeftDirection="-32 32" RightDirection="-32 32" />
14+
<PathPointType Anchor="32 32" LeftDirection="32 32" RightDirection="32 32" />
15+
<PathPointType Anchor="32 -32" LeftDirection="32 -32" RightDirection="32 -32" />
16+
</PathPointArray>
17+
</GeometryPathType>
18+
</PathGeometry>
19+
</Properties>
20+
<Image Self="ue6" ItemTransform="1 0 0 1 -32 -32">
21+
<Properties>
22+
<Profile type="string">
23+
$ID/Embedded
24+
</Profile>
25+
<GraphicBounds Left="0" Top="0" Right="64" Bottom="64" />
26+
</Properties>
27+
<Link Self="ueb" LinkResourceURI="file:command/11498.png" />
28+
</Image>
29+
</Rectangle>
30+
</CharacterStyleRange>
31+
</ParagraphStyleRange>
32+
```
33+
```
34+
% pandoc -s -f markdown -t icml
35+
![](command/11498.png){object-style="myStyle"}
36+
^D
37+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
38+
<?aid style="50" type="snippet" readerVersion="6.0" featureSet="513" product="8.0(370)" ?>
39+
<?aid SnippetType="InCopyInterchange"?>
40+
<Document DOMVersion="8.0" Self="pandoc_doc">
41+
<RootCharacterStyleGroup Self="pandoc_character_styles">
42+
<CharacterStyle Self="$ID/NormalCharacterStyle" Name="Default" />
43+
<CharacterStyle Self="CharacterStyle/" Name="">
44+
<Properties>
45+
<BasedOn type="object">$ID/NormalCharacterStyle</BasedOn>
46+
</Properties>
47+
</CharacterStyle>
48+
</RootCharacterStyleGroup>
49+
<RootParagraphStyleGroup Self="pandoc_paragraph_styles">
50+
<ParagraphStyle Self="$ID/NormalParagraphStyle" Name="$ID/NormalParagraphStyle"
51+
SpaceBefore="6" SpaceAfter="6"> <!-- paragraph spacing -->
52+
<Properties>
53+
<TabList type="list">
54+
<ListItem type="record">
55+
<Alignment type="enumeration">LeftAlign</Alignment>
56+
<AlignmentCharacter type="string">.</AlignmentCharacter>
57+
<Leader type="string"></Leader>
58+
<Position type="unit">10</Position> <!-- first tab stop -->
59+
</ListItem>
60+
</TabList>
61+
</Properties>
62+
</ParagraphStyle>
63+
<ParagraphStyle Self="ParagraphStyle/Paragraph" Name="Paragraph" LeftIndent="0">
64+
<Properties>
65+
<BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
66+
</Properties>
67+
</ParagraphStyle>
68+
</RootParagraphStyleGroup>
69+
<RootTableStyleGroup Self="pandoc_table_styles">
70+
<TableStyle Self="TableStyle/Table" Name="Table" />
71+
</RootTableStyleGroup>
72+
<RootCellStyleGroup Self="pandoc_cell_styles">
73+
<CellStyle Self="CellStyle/Cell" AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]" Name="Cell" />
74+
</RootCellStyleGroup>
75+
<RootObjectStyleGroup Self="pandoc_object_styles">
76+
<ObjectStyle Self="ObjectStyle/myStyle" Name="myStyle">
77+
<Properties>
78+
<BasedOn type="string">$ID/None</BasedOn>
79+
</Properties>
80+
</ObjectStyle>
81+
</RootObjectStyleGroup>
82+
<Story Self="pandoc_story"
83+
TrackChanges="false"
84+
StoryTitle=""
85+
AppliedTOCStyle="n"
86+
AppliedNamedGrid="n" >
87+
<StoryPreference OpticalMarginAlignment="true" OpticalMarginSize="12" />
88+
89+
<!-- body needs to be non-indented, otherwise code blocks are indented too far -->
90+
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
91+
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
92+
<Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 32 -32" AppliedObjectStyle="ObjectStyle/myStyle">
93+
<Properties>
94+
<PathGeometry>
95+
<GeometryPathType PathOpen="false">
96+
<PathPointArray>
97+
<PathPointType Anchor="-32 -32" LeftDirection="-32 -32" RightDirection="-32 -32" />
98+
<PathPointType Anchor="-32 32" LeftDirection="-32 32" RightDirection="-32 32" />
99+
<PathPointType Anchor="32 32" LeftDirection="32 32" RightDirection="32 32" />
100+
<PathPointType Anchor="32 -32" LeftDirection="32 -32" RightDirection="32 -32" />
101+
</PathPointArray>
102+
</GeometryPathType>
103+
</PathGeometry>
104+
</Properties>
105+
<Image Self="ue6" ItemTransform="1 0 0 1 -32 -32">
106+
<Properties>
107+
<Profile type="string">
108+
$ID/Embedded
109+
</Profile>
110+
<GraphicBounds Left="0" Top="0" Right="64" Bottom="64" />
111+
</Properties>
112+
<Link Self="ueb" LinkResourceURI="file:command/11498.png" />
113+
</Image>
114+
</Rectangle>
115+
</CharacterStyleRange>
116+
</ParagraphStyleRange>
117+
118+
</Story>
119+
120+
</Document>
121+
```

test/command/11498.png

1.28 KB
Loading

0 commit comments

Comments
 (0)