Skip to content

Commit

Permalink
fix: WaterMark clip logic (ant-design#44321)
Browse files Browse the repository at this point in the history
* fix: cut logic

* chore: fix size

* test: update snapshot

* chore: rm useless code
  • Loading branch information
zombieJ authored Aug 21, 2023
1 parent 21a2265 commit b26e3a7
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exports[`renders components/watermark/demo/basic.tsx extend context correctly 1`
style="height: 500px;"
/>
<div
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 220px;"
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 218px;"
/>
</div>
`;
Expand Down Expand Up @@ -49,7 +49,7 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
style="z-index: 10; width: 100%; max-width: 800px; position: relative;"
/>
<div
style="z-index: 11; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 220px;"
style="z-index: 11; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 218px;"
/>
</div>
<form
Expand Down Expand Up @@ -536,19 +536,19 @@ exports[`renders components/watermark/demo/custom.tsx extend context correctly 1
/>
<div
class="ant-slider-track"
style="left: 0%; width: 16%;"
style="left: 0%; width: 15.151515151515152%;"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-valuemax="100"
aria-valuemin="0"
aria-valuemin="1"
aria-valuenow="16"
class="ant-slider-handle"
role="slider"
style="left: 16%; transform: translateX(-50%);"
style="left: 15.151515151515152%; transform: translateX(-50%);"
tabindex="0"
/>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,19 +163,19 @@ exports[`renders components/watermark/demo/custom.tsx correctly 1`] = `
/>
<div
class="ant-slider-track"
style="left:0%;width:16%"
style="left:0%;width:15.151515151515152%"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-valuemax="100"
aria-valuemin="0"
aria-valuemin="1"
aria-valuenow="16"
class="ant-slider-handle"
role="slider"
style="left:16%;transform:translateX(-50%)"
style="left:15.151515151515152%;transform:translateX(-50%)"
tabindex="0"
/>
</div>
Expand Down
12 changes: 6 additions & 6 deletions components/watermark/__tests__/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ exports[`Watermark Image watermark snapshot 1`] = `
style="position: relative;"
>
<div
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 440px;"
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 470px;"
/>
</div>
</div>
Expand All @@ -20,7 +20,7 @@ exports[`Watermark Interleaved watermark backgroundSize is correct 1`] = `
style="position: relative;"
>
<div
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 600px;"
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 720px;"
/>
</div>
</div>
Expand All @@ -33,7 +33,7 @@ exports[`Watermark Invalid image watermark 1`] = `
style="position: relative;"
>
<div
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 440px;"
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 470px;"
/>
</div>
</div>
Expand All @@ -46,7 +46,7 @@ exports[`Watermark MutationObserver should work properly 1`] = `
style="position: relative;"
>
<div
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 232px;"
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 229px;"
/>
</div>
</div>
Expand All @@ -59,7 +59,7 @@ exports[`Watermark Observe the modification of style 1`] = `
style="position: relative;"
>
<div
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: -250px -250px; background-image: url('data:image/png;base64,00'); background-size: 232px;"
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: -250px -250px; background-image: url('data:image/png;base64,00'); background-size: 229px;"
/>
</div>
</div>
Expand All @@ -85,7 +85,7 @@ exports[`Watermark The watermark should render successfully 1`] = `
style="position: relative;"
>
<div
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 220px;"
style="z-index: 9; position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; background-repeat: repeat; background-position: 0px 0px; background-image: url('data:image/png;base64,00'); background-size: 218px;"
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion components/watermark/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('Watermark', () => {
/>,
);
const target = container.querySelector<HTMLDivElement>('.watermark div');
expect(target?.style.backgroundSize).toBe('600px');
expect(target?.style.backgroundSize).toBe('720px');
expect(container).toMatchSnapshot();
});

Expand Down
2 changes: 1 addition & 1 deletion components/watermark/demo/custom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const App: React.FC = () => {
<ColorPicker />
</Form.Item>
<Form.Item name="fontSize" label="FontSize">
<Slider step={1} min={0} max={100} />
<Slider step={1} min={1} max={100} />
</Form.Item>
<Form.Item name="zIndex" label="zIndex">
<Slider step={1} min={0} max={100} />
Expand Down
145 changes: 42 additions & 103 deletions components/watermark/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import React, { useEffect, useRef } from 'react';

import MutateObserver from '@rc-component/mutate-observer';
import classNames from 'classnames';
import React, { useEffect, useRef } from 'react';
import { getPixelRatio, getStyleStr, reRendering, rotateWatermark } from './utils';
import theme from '../theme';

/**
* Base size of the canvas, 1 for parallel layout and 2 for alternate layout
* Only alternate layout is currently supported
*/
const BaseSize = 2;
const FontGap = 3;
import theme from '../theme';
import useClips, { FontGap } from './useClips';
import { getPixelRatio, getStyleStr, reRendering } from './utils';

export interface WatermarkProps {
zIndex?: number;
Expand Down Expand Up @@ -117,7 +113,7 @@ const Watermark: React.FC<WatermarkProps> = (props) => {
getStyleStr({
...getMarkStyle(),
backgroundImage: `url('${base64Url}')`,
backgroundSize: `${(gapX + markWidth) * BaseSize}px`,
backgroundSize: `${Math.floor(markWidth)}px`,
}),
);
containerRef.current?.append(watermarkRef.current);
Expand All @@ -138,53 +134,20 @@ const Watermark: React.FC<WatermarkProps> = (props) => {
if (!image && ctx.measureText) {
ctx.font = `${Number(fontSize)}px ${fontFamily}`;
const contents = Array.isArray(content) ? content : [content];
const widths = contents.map((item) => ctx.measureText(item!).width);
defaultWidth = Math.ceil(Math.max(...widths));
defaultHeight = Number(fontSize) * contents.length + (contents.length - 1) * FontGap;
const sizes = contents.map((item) => {
const metrics = ctx.measureText(item!);

return [metrics.width, metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent];
});
defaultWidth = Math.ceil(Math.max(...sizes.map((size) => size[0])));
defaultHeight =
Math.ceil(Math.max(...sizes.map((size) => size[1]))) * contents.length +
(contents.length - 1) * FontGap;
}
return [width ?? defaultWidth, height ?? defaultHeight] as const;
};

const fillTexts = (
ctx: CanvasRenderingContext2D,
drawX: number,
drawY: number,
drawWidth: number,
drawHeight: number,
) => {
const ratio = getPixelRatio();
const mergedFontSize = Number(fontSize) * ratio;
ctx.font = `${fontStyle} normal ${fontWeight} ${mergedFontSize}px/${drawHeight}px ${fontFamily}`;
ctx.fillStyle = color;
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.translate(drawWidth / 2, 0);
const contents = Array.isArray(content) ? content : [content];
contents?.forEach((item, index) => {
ctx.fillText(item ?? '', drawX, drawY + index * (mergedFontSize + FontGap * ratio));
});
};

const drawText = (
canvas: HTMLCanvasElement,
ctx: CanvasRenderingContext2D,
drawX: number,
drawY: number,
drawWidth: number,
drawHeight: number,
alternateRotateX: number,
alternateRotateY: number,
alternateDrawX: number,
alternateDrawY: number,
markWidth: number,
) => {
fillTexts(ctx, drawX, drawY, drawWidth, drawHeight);
/** Fill the interleaved text after rotation */
ctx.restore();
rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate);
fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
appendWatermark(canvas.toDataURL(), markWidth);
};
const getClips = useClips();

const renderWatermark = () => {
const canvas = document.createElement('canvas');
Expand All @@ -197,67 +160,43 @@ const Watermark: React.FC<WatermarkProps> = (props) => {

const ratio = getPixelRatio();
const [markWidth, markHeight] = getMarkSize(ctx);
const canvasWidth = (gapX + markWidth) * ratio;
const canvasHeight = (gapY + markHeight) * ratio;
canvas.setAttribute('width', `${canvasWidth * BaseSize}px`);
canvas.setAttribute('height', `${canvasHeight * BaseSize}px`);

const drawX = (gapX * ratio) / 2;
const drawY = (gapY * ratio) / 2;
const drawWidth = markWidth * ratio;
const drawHeight = markHeight * ratio;
const rotateX = (drawWidth + gapX * ratio) / 2;
const rotateY = (drawHeight + gapY * ratio) / 2;
/** Alternate drawing parameters */
const alternateDrawX = drawX + canvasWidth;
const alternateDrawY = drawY + canvasHeight;
const alternateRotateX = rotateX + canvasWidth;
const alternateRotateY = rotateY + canvasHeight;
const drawCanvas = (
drawContent?: NonNullable<WatermarkProps['content']> | HTMLImageElement,
) => {
const [textClips, clipWidth] = getClips(
drawContent || '',
rotate,
ratio,
markWidth,
markHeight,
{
color,
fontSize,
fontStyle,
fontWeight,
fontFamily,
},
gapX,
gapY,
);

ctx.save();
rotateWatermark(ctx, rotateX, rotateY, rotate);
appendWatermark(textClips, clipWidth);
};

if (image) {
const img = new Image();
img.onload = () => {
ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);
/** Draw interleaved pictures after rotation */
ctx.restore();
rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate);
ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
appendWatermark(canvas.toDataURL(), markWidth);
drawCanvas(img);
};
img.onerror = () => {
drawCanvas(content);
};
img.onerror = () =>
drawText(
canvas,
ctx,
drawX,
drawY,
drawWidth,
drawHeight,
alternateRotateX,
alternateRotateY,
alternateDrawX,
alternateDrawY,
markWidth,
);
img.crossOrigin = 'anonymous';
img.referrerPolicy = 'no-referrer';
img.src = image;
} else {
drawText(
canvas,
ctx,
drawX,
drawY,
drawWidth,
drawHeight,
alternateRotateX,
alternateRotateY,
alternateDrawX,
alternateDrawY,
markWidth,
);
drawCanvas(content);
}
}
};
Expand Down
Loading

0 comments on commit b26e3a7

Please sign in to comment.