@json-to-office/core-pptx 0.8.0 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,8 +12,8 @@ interface ImageComponentProps {
12
12
  h?: number | string;
13
13
  sizing?: {
14
14
  type: string;
15
- w?: number;
16
- h?: number;
15
+ w?: number | string;
16
+ h?: number | string;
17
17
  };
18
18
  rotate?: number;
19
19
  rounding?: boolean;
@@ -32,6 +32,6 @@ interface ImageComponentProps {
32
32
  };
33
33
  alt?: string;
34
34
  }
35
- export declare function renderImageComponent(slide: PptxGenJS.Slide, props: ImageComponentProps, theme: PptxThemeConfig, warnings?: PipelineWarning[]): Promise<void>;
35
+ export declare function renderImageComponent(slide: PptxGenJS.Slide, props: ImageComponentProps, theme: PptxThemeConfig, warnings?: PipelineWarning[], slideWidth?: number, slideHeight?: number): Promise<void>;
36
36
  export {};
37
37
  //# sourceMappingURL=image.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/components/image.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,SAAS,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AA2BjE,UAAU,mBAAmB;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAqCD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,eAAe,EACtB,QAAQ,CAAC,EAAE,eAAe,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CA8Gf"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/components/image.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,SAAS,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AA8BjE,UAAU,mBAAmB;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA2DD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,eAAe,EACtB,QAAQ,CAAC,EAAE,eAAe,EAAE,EAC5B,UAAU,SAAK,EACf,WAAW,SAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA+Jf"}
@@ -2,13 +2,12 @@
2
2
  * PPTX Component Renderers
3
3
  */
4
4
  import type PptxGenJS from 'pptxgenjs';
5
- import type { PptxThemeConfig, PptxComponentInput, PipelineWarning, SlideContext } from '../types';
6
- import type { ServicesConfig } from '@json-to-office/shared';
5
+ import type { PptxThemeConfig, PptxComponentInput, PipelineWarning, SlideRenderContext } from '../types';
7
6
  export { renderTextComponent } from './text';
8
7
  export { renderImageComponent } from './image';
9
8
  export { renderShapeComponent } from './shape';
10
9
  export { renderTableComponent } from './table';
11
10
  export { renderHighchartsComponent } from './highcharts';
12
11
  export { renderChartComponent } from './chart';
13
- export declare function renderComponent(slide: PptxGenJS.Slide, component: PptxComponentInput, theme: PptxThemeConfig, pptx: PptxGenJS, warnings?: PipelineWarning[], slideCtx?: SlideContext, services?: ServicesConfig): Promise<void>;
12
+ export declare function renderComponent(slide: PptxGenJS.Slide, component: PptxComponentInput, theme: PptxThemeConfig, pptx: PptxGenJS, warnings?: PipelineWarning[], ctx?: SlideRenderContext): Promise<void>;
14
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,SAAS,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,YAAY,EACb,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAS7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,wBAAsB,eAAe,CACnC,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,SAAS,EAAE,kBAAkB,EAC7B,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,SAAS,EACf,QAAQ,CAAC,EAAE,eAAe,EAAE,EAC5B,QAAQ,CAAC,EAAE,YAAY,EACvB,QAAQ,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,IAAI,CAAC,CAuCf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,SAAS,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EACnB,MAAM,UAAU,CAAC;AASlB,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,wBAAsB,eAAe,CACnC,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,SAAS,EAAE,kBAAkB,EAC7B,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,SAAS,EACf,QAAQ,CAAC,EAAE,eAAe,EAAE,EAC5B,GAAG,CAAC,EAAE,kBAAkB,GACvB,OAAO,CAAC,IAAI,CAAC,CA8Cf"}
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,SAAS,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EAEhB,MAAM,UAAU,CAAC;AAUlB,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,qBAAqB,EAChC,QAAQ,CAAC,EAAE,eAAe,EAAE,GAC3B,OAAO,CAAC,SAAS,CAAC,CAuOpB"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,SAAS,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EAGhB,MAAM,UAAU,CAAC;AAUlB,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,qBAAqB,EAChC,QAAQ,CAAC,EAAE,eAAe,EAAE,GAC3B,OAAO,CAAC,SAAS,CAAC,CAyOpB"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export declare function getPptxCoreVersion(): string;
2
2
  export { generatePresentation, generateBufferFromJson, generateBufferWithWarnings, generateAndSaveFromJson, generateFromFile, savePresentation, isPresentationComponentDefinition, PresentationGenerator, } from './core/generator';
3
3
  export type { GenerationOptions, GenerationResult } from './core/generator';
4
- export type { PptxComponentInput, PresentationComponentDefinition, SlideComponentDefinition, ProcessedPresentation, ProcessedSlide, PptxThemeConfig, PipelineWarning, SlideContext, } from './types';
4
+ export type { PptxComponentInput, PresentationComponentDefinition, SlideComponentDefinition, ProcessedPresentation, ProcessedSlide, PptxThemeConfig, PipelineWarning, SlideContext, SlideRenderContext, } from './types';
5
5
  export { isPresentationComponent, isSlideComponent } from './types';
6
6
  export { W as WarningCodes } from './utils/warn';
7
7
  export type { WarningCode } from './utils/warn';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAGD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,iCAAiC,EACjC,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,YAAY,EACV,kBAAkB,EAClB,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,eAAe,EACf,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGpE,OAAO,EAAE,CAAC,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxE,OAAO,EACL,eAAe,EACf,aAAa,EACb,2BAA2B,EAC3B,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,4BAA4B,EAC5B,qBAAqB,IAAI,2BAA2B,EACpD,4BAA4B,EAC5B,sBAAsB,IAAI,4BAA4B,EACtD,oBAAoB,IAAI,0BAA0B,EAClD,gBAAgB,IAAI,sBAAsB,EAC1C,0BAA0B,EAC1B,oBAAoB,EACpB,0BAA0B,EAC1B,6BAA6B,EAC7B,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,IAAI,qBAAqB,GACzC,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,GAChB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAGD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,iCAAiC,EACjC,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,YAAY,EACV,kBAAkB,EAClB,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,eAAe,EACf,YAAY,EACZ,kBAAkB,GACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGpE,OAAO,EAAE,CAAC,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxE,OAAO,EACL,eAAe,EACf,aAAa,EACb,2BAA2B,EAC3B,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,4BAA4B,EAC5B,qBAAqB,IAAI,2BAA2B,EACpD,4BAA4B,EAC5B,sBAAsB,IAAI,4BAA4B,EACtD,oBAAoB,IAAI,0BAA0B,EAClD,gBAAgB,IAAI,sBAAsB,EAC1C,0BAA0B,EAC1B,oBAAoB,EACpB,0BAA0B,EAC1B,6BAA6B,EAC7B,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,IAAI,qBAAqB,GACzC,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,GAChB,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -25,7 +25,8 @@ var W = {
25
25
  PLACEHOLDER_NO_POSITION: "PLACEHOLDER_NO_POSITION",
26
26
  THEME_COLOR_FALLBACK: "THEME_COLOR_FALLBACK",
27
27
  UNKNOWN_COLOR: "UNKNOWN_COLOR",
28
- GRID_POSITION_CLAMPED: "GRID_POSITION_CLAMPED"
28
+ GRID_POSITION_CLAMPED: "GRID_POSITION_CLAMPED",
29
+ IMAGE_ZERO_BOX: "IMAGE_ZERO_BOX"
29
30
  };
30
31
  function warn(warnings, code, message, extra) {
31
32
  if (warnings) {
@@ -516,7 +517,8 @@ import probe from "probe-image-size";
516
517
  function isPrivateUrl(urlStr) {
517
518
  try {
518
519
  const { hostname } = new URL(urlStr);
519
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]" || hostname.startsWith("10.") || hostname.startsWith("192.168.") || hostname.startsWith("169.254.") || hostname.endsWith(".local") || hostname.endsWith(".internal")) return true;
520
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]" || hostname.startsWith("10.") || hostname.startsWith("192.168.") || hostname.startsWith("169.254.") || hostname.endsWith(".local") || hostname.endsWith(".internal"))
521
+ return true;
520
522
  if (hostname.startsWith("172.")) {
521
523
  const second = parseInt(hostname.split(".")[1], 10);
522
524
  if (second >= 16 && second <= 31) return true;
@@ -546,30 +548,75 @@ async function probeImageSize(imagePath, warnings) {
546
548
  const result = await probe(createReadStream(resolved));
547
549
  return result ? { width: result.width, height: result.height } : void 0;
548
550
  } catch (err) {
549
- warn(warnings, W.IMAGE_PROBE_FAILED, `Image probe failed: ${err instanceof Error ? err.message : String(err)}`, { component: "image" });
551
+ warn(
552
+ warnings,
553
+ W.IMAGE_PROBE_FAILED,
554
+ `Image probe failed: ${err instanceof Error ? err.message : String(err)}`,
555
+ { component: "image" }
556
+ );
550
557
  return void 0;
551
558
  }
552
559
  }
553
- async function renderImageComponent(slide, props, theme, warnings) {
560
+ function resolveDimension(value, axisLength) {
561
+ if (typeof value === "number") return value;
562
+ if (value.endsWith("%")) {
563
+ const pct = parseFloat(value);
564
+ return !Number.isNaN(pct) && pct >= 0 ? pct / 100 * axisLength : 0;
565
+ }
566
+ const n = Number(value);
567
+ return Number.isNaN(n) ? 0 : n;
568
+ }
569
+ async function renderImageComponent(slide, props, theme, warnings, slideWidth = 10, slideHeight = 7.5) {
554
570
  const opts = {};
571
+ const source = props.path || props.base64;
572
+ if (!source) {
573
+ warn(
574
+ warnings,
575
+ W.IMAGE_NO_SOURCE,
576
+ "Image component missing both path and base64",
577
+ { component: "image" }
578
+ );
579
+ return;
580
+ }
555
581
  if (props.path) {
556
582
  opts.path = props.path;
557
- } else if (props.base64) {
558
- opts.data = props.base64;
559
583
  } else {
560
- warn(warnings, W.IMAGE_NO_SOURCE, "Image component missing both path and base64", { component: "image" });
561
- return;
584
+ opts.data = props.base64;
562
585
  }
563
586
  if (props.x !== void 0) opts.x = props.x;
564
587
  if (props.y !== void 0) opts.y = props.y;
565
588
  if (props.w !== void 0) opts.w = props.w;
566
589
  if (props.h !== void 0) opts.h = props.h;
590
+ const hasW = props.w !== void 0;
591
+ const hasH = props.h !== void 0;
592
+ const needsProbe = hasW !== hasH && !props.sizing || props.sizing?.type === "contain" || props.sizing?.type === "cover";
593
+ const intrinsic = needsProbe ? await probeImageSize(source, warnings) : void 0;
594
+ if (hasW !== hasH && !props.sizing) {
595
+ if (intrinsic && intrinsic.width > 0 && intrinsic.height > 0) {
596
+ const aspect = intrinsic.width / intrinsic.height;
597
+ if (hasW && !hasH) {
598
+ const wInches = resolveDimension(props.w, slideWidth);
599
+ opts.w = wInches;
600
+ opts.h = wInches / aspect;
601
+ } else {
602
+ const hInches = resolveDimension(props.h, slideHeight);
603
+ opts.h = hInches;
604
+ opts.w = hInches * aspect;
605
+ }
606
+ }
607
+ }
567
608
  if (props.sizing && (props.sizing.type === "contain" || props.sizing.type === "cover")) {
568
- const source = props.path || props.base64;
569
- const intrinsic = source ? await probeImageSize(source, warnings) : void 0;
570
- const boxW = Number(props.sizing.w ?? props.w);
571
- const boxH = Number(props.sizing.h ?? props.h);
572
- if (intrinsic && !isNaN(boxW) && !isNaN(boxH)) {
609
+ const boxW = resolveDimension(props.sizing.w ?? props.w ?? 0, slideWidth);
610
+ const boxH = resolveDimension(props.sizing.h ?? props.h ?? 0, slideHeight);
611
+ if (boxW <= 0 || boxH <= 0) {
612
+ warn(
613
+ warnings,
614
+ W.IMAGE_ZERO_BOX,
615
+ `Image sizing box resolved to zero (${boxW}x${boxH})`,
616
+ { component: "image" }
617
+ );
618
+ }
619
+ if (intrinsic && intrinsic.width > 0 && intrinsic.height > 0 && boxW > 0 && boxH > 0) {
573
620
  const imgAspect = intrinsic.width / intrinsic.height;
574
621
  if (props.sizing.type === "contain") {
575
622
  const boxAspect = boxW / boxH;
@@ -581,8 +628,8 @@ async function renderImageComponent(slide, props, theme, warnings) {
581
628
  fitH = boxH;
582
629
  fitW = boxH * imgAspect;
583
630
  }
584
- const baseX = Number(props.x ?? 0);
585
- const baseY = Number(props.y ?? 0);
631
+ const baseX = resolveDimension(props.x ?? 0, slideWidth);
632
+ const baseY = resolveDimension(props.y ?? 0, slideHeight);
586
633
  opts.x = baseX + (boxW - fitW) / 2;
587
634
  opts.y = baseY + (boxH - fitH) / 2;
588
635
  opts.w = fitW;
@@ -598,8 +645,8 @@ async function renderImageComponent(slide, props, theme, warnings) {
598
645
  } else if (props.sizing) {
599
646
  opts.sizing = {
600
647
  ...props.sizing,
601
- w: props.sizing.w ?? props.w,
602
- h: props.sizing.h ?? props.h
648
+ w: resolveDimension(props.sizing.w ?? props.w ?? 0, slideWidth),
649
+ h: resolveDimension(props.sizing.h ?? props.h ?? 0, slideHeight)
603
650
  };
604
651
  }
605
652
  if (props.rotate !== void 0) opts.rotate = props.rotate;
@@ -1050,16 +1097,23 @@ function renderChartComponent(slide, props, theme, _pptx, warnings) {
1050
1097
  }
1051
1098
 
1052
1099
  // src/components/index.ts
1053
- async function renderComponent(slide, component, theme, pptx, warnings, slideCtx, services) {
1100
+ async function renderComponent(slide, component, theme, pptx, warnings, ctx) {
1054
1101
  if (component.enabled === false) return;
1055
1102
  const { name, props } = component;
1056
1103
  const p = props;
1057
1104
  switch (name) {
1058
1105
  case "text":
1059
- renderTextComponent(slide, p, theme, warnings, slideCtx);
1106
+ renderTextComponent(slide, p, theme, warnings, ctx?.slideCtx);
1060
1107
  break;
1061
1108
  case "image":
1062
- await renderImageComponent(slide, p, theme, warnings);
1109
+ await renderImageComponent(
1110
+ slide,
1111
+ p,
1112
+ theme,
1113
+ warnings,
1114
+ ctx?.slideWidth,
1115
+ ctx?.slideHeight
1116
+ );
1063
1117
  break;
1064
1118
  case "shape":
1065
1119
  renderShapeComponent(slide, p, theme, pptx, warnings);
@@ -1073,7 +1127,7 @@ async function renderComponent(slide, component, theme, pptx, warnings, slideCtx
1073
1127
  p,
1074
1128
  theme,
1075
1129
  warnings,
1076
- services?.highcharts
1130
+ ctx?.services?.highcharts
1077
1131
  );
1078
1132
  break;
1079
1133
  case "chart":
@@ -1159,6 +1213,12 @@ async function renderPresentation(processed, warnings) {
1159
1213
  totalSlides,
1160
1214
  pageNumberFormat: processed.pageNumberFormat
1161
1215
  };
1216
+ const renderCtx = {
1217
+ slideCtx,
1218
+ services: processed.services,
1219
+ slideWidth: processed.slideWidth,
1220
+ slideHeight: processed.slideHeight
1221
+ };
1162
1222
  const slide = slideData.template ? pptx.addSlide({ masterName: slideData.template }) : pptx.addSlide();
1163
1223
  if (slideData.background) {
1164
1224
  if (slideData.background.color) {
@@ -1198,8 +1258,7 @@ async function renderPresentation(processed, warnings) {
1198
1258
  processed.theme,
1199
1259
  pptx,
1200
1260
  warnings,
1201
- slideCtx,
1202
- processed.services
1261
+ renderCtx
1203
1262
  );
1204
1263
  }
1205
1264
  }
@@ -1217,8 +1276,7 @@ async function renderPresentation(processed, warnings) {
1217
1276
  processed.theme,
1218
1277
  pptx,
1219
1278
  warnings,
1220
- slideCtx,
1221
- processed.services
1279
+ renderCtx
1222
1280
  );
1223
1281
  }
1224
1282
  if (slideData.placeholders) {
@@ -1264,8 +1322,7 @@ async function renderPresentation(processed, warnings) {
1264
1322
  processed.theme,
1265
1323
  pptx,
1266
1324
  warnings,
1267
- slideCtx,
1268
- processed.services
1325
+ renderCtx
1269
1326
  );
1270
1327
  }
1271
1328
  } else {
@@ -1291,8 +1348,7 @@ async function renderPresentation(processed, warnings) {
1291
1348
  processed.theme,
1292
1349
  pptx,
1293
1350
  warnings,
1294
- slideCtx,
1295
- processed.services
1351
+ renderCtx
1296
1352
  );
1297
1353
  } else {
1298
1354
  warn(