Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/render-layer-rotation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@embedpdf/plugin-render': patch
---

Pass the effective page rotation to RenderLayer rendering so rotated PDF pages match their layout dimensions.
1 change: 1 addition & 0 deletions packages/plugin-render/src/lib/render-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export class RenderPlugin extends BasePlugin<RenderPluginConfig, RenderCapabilit
// ─────────────────────────────────────────────────────────

async initialize(_config: RenderPluginConfig): Promise<void> {
void _config;
this.logger.info('RenderPlugin', 'Initialize', 'Render plugin initialized');
}

Expand Down
29 changes: 26 additions & 3 deletions packages/plugin-render/src/shared/components/render-layer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ type RenderLayerProps = Omit<HTMLAttributes<HTMLImageElement>, 'style'> & {
*/
scale?: number;
/**
* Optional device pixel ratio override. If not provided, uses window.devicePixelRatio.
* Optional device pixel ratio override. If not provided, uses the browser device pixel ratio.
*/
dpr?: number;
/**
* Optional rotation override. If not provided, uses page rotation plus document rotation.
*/
rotation?: Rotation;
/**
* Additional styles for the image element
*/
Expand All @@ -44,6 +48,7 @@ export function RenderLayer({
pageIndex,
scale: scaleOverride,
dpr: dprOverride,
rotation: rotationOverride,
style,
...props
}: RenderLayerProps) {
Expand All @@ -67,9 +72,18 @@ export function RenderLayer({

const actualDpr = useMemo(() => {
if (dprOverride !== undefined) return dprOverride;
return window.devicePixelRatio;
return globalThis.devicePixelRatio ?? 1;
}, [dprOverride]);

const actualRotation = useMemo(() => {
if (rotationOverride !== undefined) return rotationOverride;
const pageRotation =
documentState?.document?.pages.find((page) => page.index === pageIndex)?.rotation ??
Rotation.Degree0;
const documentRotation = documentState?.rotation ?? Rotation.Degree0;
return ((pageRotation + documentRotation) % 4) as Rotation;
}, [rotationOverride, documentState?.document, documentState?.rotation, pageIndex]);

useEffect(() => {
if (!renderProvides) return;

Expand All @@ -78,6 +92,7 @@ export function RenderLayer({
options: {
scaleFactor: actualScale,
dpr: actualDpr,
rotation: actualRotation,
},
});

Expand All @@ -98,7 +113,15 @@ export function RenderLayer({
});
}
};
}, [documentId, pageIndex, actualScale, actualDpr, renderProvides, refreshVersion]);
}, [
documentId,
pageIndex,
actualScale,
actualDpr,
actualRotation,
renderProvides,
refreshVersion,
]);

const handleImageLoad = () => {
if (urlRef.current) {
Expand Down
18 changes: 17 additions & 1 deletion packages/plugin-render/src/svelte/components/RenderLayer.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLImgAttributes } from 'svelte/elements';
import { ignore, PdfErrorCode } from '@embedpdf/models';
import { ignore, PdfErrorCode, Rotation } from '@embedpdf/models';
import { useDocumentState } from '@embedpdf/core/svelte';
import { useRenderCapability } from '../hooks';

Expand All @@ -21,6 +21,10 @@
* Optional device pixel ratio override. If not provided, uses window.devicePixelRatio.
*/
dpr?: number;
/**
* Optional rotation override. If not provided, uses page rotation plus document rotation.
*/
rotation?: Rotation;
class?: string;
style?: string;
}
Expand All @@ -33,6 +37,7 @@
documentId,
scale: scaleOverride,
dpr: dprOverride,
rotation: rotationOverride,
class: propsClass,
style: propsStyle,
pageIndex,
Expand Down Expand Up @@ -67,6 +72,15 @@

const actualDpr = $derived(dprOverride !== undefined ? dprOverride : window.devicePixelRatio);

const actualRotation = $derived.by(() => {
if (rotationOverride !== undefined) return rotationOverride;
const pageRotation =
documentState.current?.document?.pages.find((page) => page.index === pageIndex)?.rotation ??
Rotation.Degree0;
const documentRotation = documentState.current?.rotation ?? Rotation.Degree0;
return ((pageRotation + documentRotation) % 4) as Rotation;
});

// Effect: reruns when:
// - documentId changes
// - actualScale changes
Expand All @@ -79,6 +93,7 @@
const docId = documentId;
const scale = actualScale;
const dpr = actualDpr;
const rotation = actualRotation;
const refresh = refreshVersion;
const page = localPageIndex;

Expand All @@ -99,6 +114,7 @@
options: {
scaleFactor: scale,
dpr,
rotation,
},
});

Expand Down
19 changes: 17 additions & 2 deletions packages/plugin-render/src/vue/components/render-layer.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { ignore, PdfErrorCode } from '@embedpdf/models';
import { ignore, PdfErrorCode, Rotation } from '@embedpdf/models';
import { useDocumentState } from '@embedpdf/core/vue';
import { useRenderCapability } from '../hooks';

Expand All @@ -21,6 +21,10 @@ interface RenderLayerProps {
* Optional device pixel ratio override. If not provided, uses window.devicePixelRatio.
*/
dpr?: number;
/**
* Optional rotation override. If not provided, uses page rotation plus document rotation.
*/
rotation?: Rotation;
}

const props = defineProps<RenderLayerProps>();
Expand Down Expand Up @@ -49,17 +53,27 @@ const actualDpr = computed(() => {
return window.devicePixelRatio;
});

const actualRotation = computed(() => {
if (props.rotation !== undefined) return props.rotation;
const pageRotation =
documentState.value?.document?.pages.find((page) => page.index === props.pageIndex)?.rotation ??
Rotation.Degree0;
const documentRotation = documentState.value?.rotation ?? Rotation.Degree0;
return ((pageRotation + documentRotation) % 4) as Rotation;
});

// Render page when dependencies change
watch(
[
() => props.documentId,
() => props.pageIndex,
actualRotation,
actualScale,
actualDpr,
renderProvides,
refreshVersion,
],
([docId, pageIdx, scale, dpr, capability], [prevDocId], onCleanup) => {
([docId, pageIdx, rotation, scale, dpr, capability], [prevDocId], onCleanup) => {
if (!capability) {
imageUrl.value = null;
return;
Expand Down Expand Up @@ -87,6 +101,7 @@ watch(
options: {
scaleFactor: scale,
dpr,
rotation,
},
});

Expand Down