3030import java .util .Locale ;
3131
3232/**
33- * A five -slide carousel sized for a LinkedIn document post, composed through the
33+ * A six -slide carousel sized for a LinkedIn document post, composed through the
3434 * canonical DSL and rendered by the engine it describes.
3535 *
36- * <p>Portrait 1080×1350 (4:5), which is the tallest frame LinkedIn shows
37- * without cropping and therefore the most readable on a phone. Type is sized for
38- * that phone, not for a desktop preview: the smallest text on a slide is 18pt at
39- * a 1080-wide page, so it survives the reduction.</p>
36+ * <p>Portrait 1280×1600 (4:5), which is the tallest frame LinkedIn shows
37+ * without cropping and therefore the most readable on a phone. The width is set
38+ * by the opening slide: it carries {@link SocialCardExample}'s card at native
39+ * size rather than a scaled copy. Type is sized for that phone, not for a
40+ * desktop preview.</p>
4041 *
4142 * <p>Every figure is read at render time — the version from the filtered
4243 * {@code banner.properties}, the comparative timings from the committed
@@ -59,8 +60,10 @@ public final class LinkedInCarouselExample {
5960
6061 /**
6162 * Everything below was drawn against a 1080-wide page. Rather than restate
62- * every size, the type helpers scale by this ratio, so the slides keep their
63- * proportions on the wider frame.
63+ * every size, the type helpers and the box metrics scale by this ratio, so
64+ * the slides keep their proportions on the wider frame. Apply it to any
65+ * length that was eyeballed against the narrower page; the only literals
66+ * that stay absolute are ones derived from the page itself.
6467 */
6568 private static final double SCALE = PAGE_WIDTH / 1080.0 ;
6669
@@ -172,7 +175,7 @@ private static DocumentSession session(Path outputFile) {
172175 }
173176
174177 /**
175- * Composes all five slides.
178+ * Composes all six slides.
176179 *
177180 * @param document the open session to compose into
178181 */
@@ -213,8 +216,10 @@ static void compose(DocumentSession document) {
213216
214217 private static void cardSlide (SectionBuilder slide ) {
215218 slide .spacing (0 );
216- slide .addSpacer (sp -> sp .width (PAGE_WIDTH )
217- .height ((PAGE_HEIGHT - SocialCardExample .CARD_HEIGHT ) / 2 ));
219+ // Floored: a card taller than the page would otherwise ask for a
220+ // negative spacer rather than simply filling the frame.
221+ double bleed = Math .max (0 , (PAGE_HEIGHT - SocialCardExample .CARD_HEIGHT ) / 2 );
222+ slide .addSpacer (sp -> sp .width (PAGE_WIDTH ).height (bleed ));
218223 slide .add (SocialCardExample .scene ());
219224 }
220225
@@ -237,7 +242,7 @@ private static void cover(SectionBuilder slide) {
237242 .lineSpacing (1.45 )
238243 .margin (DocumentInsets .zero ()));
239244 slide .addRow ("Formats" , row -> {
240- row .spacing (14 ).evenWeights ();
245+ row .spacing (14 * SCALE ).evenWeights ();
241246 formatChip (row , "PDF" , "fixed layout" , "PDFBox" , MINT );
242247 formatChip (row , "PPTX" , "fixed layout" , "Apache POI" , VIOLET_LIGHT );
243248 formatChip (row , "DOCX" , "semantic" , "Apache POI" , AMBER );
@@ -282,15 +287,15 @@ private static void numbersSlide(SectionBuilder slide, EngineDeckData.BenchRun b
282287 slide .addParagraph (p -> p
283288 .text ("Average render latency, milliseconds — lower is faster." )
284289 .textStyle (body (30 , ON_DARK_MUTED ))
285- .margin (DocumentInsets .bottom (10 )));
290+ .margin (DocumentInsets .bottom (10 * SCALE )));
286291
287292 slide .addSection ("Chart" , card -> card
288- .softPanel (SURFACE , 20 , 26 )
289- .stroke (DocumentStroke .of (LINE , 1 ))
293+ .softPanel (SURFACE , 20 * SCALE , 26 * SCALE )
294+ .stroke (DocumentStroke .of (LINE , 1 * SCALE ))
290295 .chart (latencyChart (bench ), latencyStyle ()));
291296
292297 slide .addRow ("Ratios" , row -> {
293- row .spacing (14 ).evenWeights ();
298+ row .spacing (14 * SCALE ).evenWeights ();
294299 ratio (row , times (bench .timeMs ("iText 9" , TIER ) / bench .timeMs ("GraphCompose" , TIER )),
295300 "faster than iText 9" , VIOLET_LIGHT );
296301 ratio (row , times (bench .heapMb ("iText 9" , TIER ) / bench .heapMb ("GraphCompose" , TIER )),
@@ -339,9 +344,9 @@ private static void closeSlide(SectionBuilder slide) {
339344 .textStyle (headline (132 ))
340345 .margin (DocumentInsets .zero ()));
341346 slide .addSection ("Coords" , card -> {
342- card .softPanel (SURFACE , 20 , CARD_PAD )
343- .stroke (DocumentStroke .of (LINE , 1 ))
344- .spacing (4 );
347+ card .softPanel (SURFACE , 20 * SCALE , CARD_PAD )
348+ .stroke (DocumentStroke .of (LINE , 1 * SCALE ))
349+ .spacing (4 * SCALE );
345350 card .addSpacer (sp -> sp .width (CARD_INNER ).height (0 ));
346351 // Split on the colon rather than set in one line: the coordinate is
347352 // wider than the card at this size and broke mid-artifact.
@@ -362,9 +367,9 @@ private static void closeSlide(SectionBuilder slide) {
362367 .margin (DocumentInsets .zero ()));
363368 });
364369 slide .addSection ("Snippet" , card -> {
365- card .softPanel (SURFACE_2 , 20 , CARD_PAD )
366- .accentLeft (VIOLET , 4 )
367- .spacing (2 );
370+ card .softPanel (SURFACE_2 , 20 * SCALE , CARD_PAD )
371+ .accentLeft (VIOLET , 4 * SCALE )
372+ .spacing (2 * SCALE );
368373 card .addSpacer (sp -> sp .width (CARD_INNER ).height (0 ));
369374 for (String line : SNIPPET ) {
370375 card .addParagraph (p -> p
@@ -377,7 +382,7 @@ private static void closeSlide(SectionBuilder slide) {
377382 slide .addParagraph (p -> p
378383 .text ("github.com/DemchaAV/GraphCompose" )
379384 .textStyle (body (46 , VIOLET_LIGHT ))
380- .margin (DocumentInsets .top (4 )));
385+ .margin (DocumentInsets .top (4 * SCALE )));
381386 slide .addParagraph (p -> footnote (p ,
382387 "Java 17+. Every slide in this carousel was composed with the library "
383388 + "and rendered by its own PDF backend - the PPTX beside it comes from "
@@ -398,9 +403,9 @@ private static void point(SectionBuilder slide, String title, DocumentColor acce
398403 // longest line, which leaves a stack of cards with ragged right edges.
399404 // An even-weighted row gives every card the full content width.
400405 slide .addSection ("Point" , card -> {
401- card .softPanel (SURFACE , 26 , CARD_PAD )
402- .accentLeft (accent , 4 )
403- .spacing (6 );
406+ card .softPanel (SURFACE , 26 * SCALE , CARD_PAD )
407+ .accentLeft (accent , 4 * SCALE )
408+ .spacing (6 * SCALE );
404409 card .addSpacer (sp -> sp .width (CARD_INNER ).height (0 ));
405410 card .addParagraph (p -> p
406411 .text (title )
@@ -422,8 +427,8 @@ private static void formatChip(RowBuilder row, String name, String lane,
422427 String engine , DocumentColor accent ) {
423428 row .addSection (name , card -> {
424429 card .softPanel (SURFACE_2 , 20 , 24 )
425- .stroke (DocumentStroke .of (LINE , 1 ))
426- .spacing (2 );
430+ .stroke (DocumentStroke .of (LINE , 1 * SCALE ))
431+ .spacing (2 * SCALE );
427432 card .addParagraph (p -> p
428433 .text (name )
429434 .textStyle (DocumentTextStyle .builder ()
@@ -442,15 +447,15 @@ private static void formatChip(RowBuilder row, String name, String lane,
442447 .text (engine )
443448 .textStyle (mono (23 , DocumentColor .rgb (122 , 131 , 162 )))
444449 .align (TextAlign .CENTER )
445- .margin (DocumentInsets .top (4 )));
450+ .margin (DocumentInsets .top (4 * SCALE )));
446451 });
447452 }
448453
449454 private static void ratio (RowBuilder row , String value , String label , DocumentColor accent ) {
450455 row .addSection ("Ratio" , card -> {
451- card .softPanel (SURFACE_2 , 14 , 24 )
452- .accentTop (accent , 3 )
453- .spacing (2 );
456+ card .softPanel (SURFACE_2 , 14 * SCALE , 24 * SCALE )
457+ .accentTop (accent , 3 * SCALE )
458+ .spacing (2 * SCALE );
454459 card .addParagraph (p -> p
455460 .text (value )
456461 .textStyle (DocumentTextStyle .builder ()
@@ -487,7 +492,7 @@ private static ChartSpec latencyChart(EngineDeckData.BenchRun bench) {
487492 private static ChartStyle latencyStyle () {
488493 return ChartStyle .builder ()
489494 .seriesPaint (0 , DocumentPaint .solid (VIOLET ))
490- .barCornerRadius (DocumentCornerRadius .of (4 ))
495+ .barCornerRadius (DocumentCornerRadius .of (4 * SCALE ))
491496 .barWidthRatio (0.5 )
492497 .axisTextStyle (mono (22 , ON_DARK_MUTED ))
493498 .valueLabelTextStyle (mono (25 , ON_DARK ))
@@ -498,7 +503,7 @@ private static ParagraphBuilder footnote(ParagraphBuilder p, String text) {
498503 return p .text (text )
499504 .textStyle (body (22 , DocumentColor .rgb (130 , 139 , 170 )))
500505 .lineSpacing (1.4 )
501- .margin (DocumentInsets .top (6 ));
506+ .margin (DocumentInsets .top (6 * SCALE ));
502507 }
503508
504509 private static String times (double ratio ) {
0 commit comments