mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Merge pull request #1 from rain2o/feature/mix-blend-mode
add mix-blend-mode support
This commit is contained in:
commit
fd76b44ef9
@ -46,6 +46,7 @@ Below is a list of all the supported CSS properties and values.
|
||||
- max-width
|
||||
- min-height
|
||||
- min-width
|
||||
- mix-blend-mode (**Limited support**)
|
||||
- opacity
|
||||
- overflow
|
||||
- overflow-wrap
|
||||
@ -79,7 +80,6 @@ These CSS properties are **NOT** currently supported
|
||||
- [box-shadow](https://github.com/niklasvh/html2canvas/pull/1086)
|
||||
- [filter](https://github.com/niklasvh/html2canvas/issues/493)
|
||||
- [font-variant-ligatures](https://github.com/niklasvh/html2canvas/pull/1085)
|
||||
- [mix-blend-mode](https://github.com/niklasvh/html2canvas/issues/580)
|
||||
- [object-fit](https://github.com/niklasvh/html2canvas/issues/1064)
|
||||
- [repeating-linear-gradient()](https://github.com/niklasvh/html2canvas/issues/1162)
|
||||
- [writing-mode](https://github.com/niklasvh/html2canvas/issues/1258)
|
||||
|
@ -41,6 +41,7 @@ import {listStyleImage} from './property-descriptors/list-style-image';
|
||||
import {listStylePosition} from './property-descriptors/list-style-position';
|
||||
import {listStyleType} from './property-descriptors/list-style-type';
|
||||
import {marginBottom, marginLeft, marginRight, marginTop} from './property-descriptors/margin';
|
||||
import {mixBlendMode} from './property-descriptors/mix-blend-mode';
|
||||
import {overflow, OVERFLOW} from './property-descriptors/overflow';
|
||||
import {overflowWrap} from './property-descriptors/overflow-wrap';
|
||||
import {paddingBottom, paddingLeft, paddingRight, paddingTop} from './property-descriptors/padding';
|
||||
@ -126,6 +127,7 @@ export class CSSParsedDeclaration {
|
||||
marginRight: CSSValue;
|
||||
marginBottom: CSSValue;
|
||||
marginLeft: CSSValue;
|
||||
mixBlendMode: ReturnType<typeof mixBlendMode.parse>;
|
||||
opacity: ReturnType<typeof opacity.parse>;
|
||||
overflowX: OVERFLOW;
|
||||
overflowY: OVERFLOW;
|
||||
@ -194,6 +196,7 @@ export class CSSParsedDeclaration {
|
||||
this.marginRight = parse(context, marginRight, declaration.marginRight);
|
||||
this.marginBottom = parse(context, marginBottom, declaration.marginBottom);
|
||||
this.marginLeft = parse(context, marginLeft, declaration.marginLeft);
|
||||
this.mixBlendMode = parse(context, mixBlendMode, declaration.mixBlendMode);
|
||||
this.opacity = parse(context, opacity, declaration.opacity);
|
||||
const overflowTuple = parse(context, overflow, declaration.overflow);
|
||||
this.overflowX = overflowTuple[0];
|
||||
|
77
src/css/property-descriptors/mix-blend-mode.ts
Normal file
77
src/css/property-descriptors/mix-blend-mode.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import {IPropertyIdentValueDescriptor, PropertyDescriptorParsingType} from '../IPropertyDescriptor';
|
||||
import {Context} from '../../core/context';
|
||||
|
||||
export const enum MIX_BLEND_MODE {
|
||||
NORMAL = 'normal',
|
||||
MULTIPLY = 'multiply',
|
||||
SCREEN = 'screen',
|
||||
OVERLAY = 'overlay',
|
||||
DARKEN = 'darken',
|
||||
LIGHTEN = 'lighten',
|
||||
COLOR_DODGE = 'color-dodge',
|
||||
COLOR_BURN = 'color-burn',
|
||||
HARD_LIGHT = 'hard-light',
|
||||
SOFT_LIGHT = 'soft-light',
|
||||
DIFFERENCE = 'difference',
|
||||
EXCLUSION = 'exclusion',
|
||||
HUE = 'hue',
|
||||
SATURATION = 'saturation',
|
||||
COLOR = 'color',
|
||||
LUMINOSITY = 'luminosity',
|
||||
INITIAL = 'initial',
|
||||
INHERIT = 'inherit',
|
||||
REVERT = 'revert',
|
||||
UNSET = 'unset'
|
||||
}
|
||||
|
||||
export const mixBlendMode: IPropertyIdentValueDescriptor<MIX_BLEND_MODE> = {
|
||||
name: 'mix-blend-mode',
|
||||
initialValue: 'normal',
|
||||
prefix: false,
|
||||
type: PropertyDescriptorParsingType.IDENT_VALUE,
|
||||
parse: (_context: Context, mode: string) => {
|
||||
switch (mode) {
|
||||
case 'multiply':
|
||||
return MIX_BLEND_MODE.MULTIPLY;
|
||||
case 'screen':
|
||||
return MIX_BLEND_MODE.SCREEN;
|
||||
case 'overlay':
|
||||
return MIX_BLEND_MODE.OVERLAY;
|
||||
case 'darken':
|
||||
return MIX_BLEND_MODE.DARKEN;
|
||||
case 'lighten':
|
||||
return MIX_BLEND_MODE.LIGHTEN;
|
||||
case 'color-dodge':
|
||||
return MIX_BLEND_MODE.COLOR_DODGE;
|
||||
case 'color-burn':
|
||||
return MIX_BLEND_MODE.COLOR_BURN;
|
||||
case 'hard-light':
|
||||
return MIX_BLEND_MODE.HARD_LIGHT;
|
||||
case 'soft-light':
|
||||
return MIX_BLEND_MODE.SOFT_LIGHT;
|
||||
case 'difference':
|
||||
return MIX_BLEND_MODE.DIFFERENCE;
|
||||
case 'exclusion':
|
||||
return MIX_BLEND_MODE.EXCLUSION;
|
||||
case 'hue':
|
||||
return MIX_BLEND_MODE.HUE;
|
||||
case 'saturation':
|
||||
return MIX_BLEND_MODE.SATURATION;
|
||||
case 'color':
|
||||
return MIX_BLEND_MODE.COLOR;
|
||||
case 'luminosity':
|
||||
return MIX_BLEND_MODE.LUMINOSITY;
|
||||
case 'initial':
|
||||
return MIX_BLEND_MODE.INITIAL;
|
||||
case 'inherit':
|
||||
return MIX_BLEND_MODE.INHERIT;
|
||||
case 'revert':
|
||||
return MIX_BLEND_MODE.REVERT;
|
||||
case 'unset':
|
||||
return MIX_BLEND_MODE.UNSET;
|
||||
case 'normal':
|
||||
default:
|
||||
return MIX_BLEND_MODE.NORMAL;
|
||||
}
|
||||
}
|
||||
};
|
1
src/global.d.ts
vendored
1
src/global.d.ts
vendored
@ -2,6 +2,7 @@ interface CSSStyleDeclaration {
|
||||
textDecorationColor: string;
|
||||
textDecorationLine: string;
|
||||
overflowWrap: string;
|
||||
mixBlendMode: string;
|
||||
}
|
||||
|
||||
interface DocumentType extends Node, ChildNode {
|
||||
|
@ -189,6 +189,7 @@ export class CanvasRenderer extends Renderer {
|
||||
switch (paintOrderLayer) {
|
||||
case PAINT_ORDER_LAYER.FILL:
|
||||
this.ctx.fillStyle = asString(styles.color);
|
||||
this.ctx.globalCompositeOperation = styles.mixBlendMode;
|
||||
this.renderTextWithLetterSpacing(text, styles.letterSpacing, baseline);
|
||||
const textShadows: TextShadow = styles.textShadow;
|
||||
|
||||
@ -276,6 +277,7 @@ export class CanvasRenderer extends Renderer {
|
||||
this.path(path);
|
||||
this.ctx.save();
|
||||
this.ctx.clip();
|
||||
this.ctx.globalCompositeOperation = container.styles.mixBlendMode;
|
||||
this.ctx.drawImage(
|
||||
image,
|
||||
0,
|
||||
@ -714,6 +716,7 @@ export class CanvasRenderer extends Renderer {
|
||||
|
||||
if (!isTransparent(styles.backgroundColor)) {
|
||||
this.ctx.fillStyle = asString(styles.backgroundColor);
|
||||
this.ctx.globalCompositeOperation = styles.mixBlendMode;
|
||||
this.ctx.fill();
|
||||
}
|
||||
|
||||
|
79
tests/reftests/mix-blend-mode.html
Normal file
79
tests/reftests/mix-blend-mode.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mix Blend Mode tests</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<script type="text/javascript" src="../test.js"></script>
|
||||
<style>
|
||||
.circle {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
}
|
||||
.circle-1 {
|
||||
background: red;
|
||||
}
|
||||
.circle-2 {
|
||||
background: green;
|
||||
left: 40px;
|
||||
}
|
||||
.circle-3 {
|
||||
background: skyblue;
|
||||
left: 20px;
|
||||
top: 40px;
|
||||
}
|
||||
.container {
|
||||
position: relative;
|
||||
border: 1px solid purple;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.bg-image {
|
||||
position: relative;
|
||||
background-image: url('../assets/image.jpg');
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<p>Green circle: mix-blend-mode: screen</p>
|
||||
<p>Blue circle: mix-blend-mode: color-burn</p>
|
||||
<div style="height: 120px; position: relative; background-color: gray;">
|
||||
<div class="circle circle-1"></div>
|
||||
<div class="circle circle-2" style="mix-blend-mode: screen"></div>
|
||||
<div class="circle circle-3" style="mix-blend-mode: color-burn"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p>Red background with mix-blend-mode: overlay over a background image</p>
|
||||
<div class="bg-image">
|
||||
<div
|
||||
style="
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: red;
|
||||
mix-blend-mode: overlay;
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container" style="background-color: green">
|
||||
<p>Image with mix-blend-mode: multiply</p>
|
||||
<img src="../assets/image2.jpg" style="mix-blend-mode: multiply" />
|
||||
</div>
|
||||
<div class="container" style="height: 120px; background-color: white;">
|
||||
<div class="circle" style="position: relative; display: inline-block; background-color: red"></div>
|
||||
<div class="circle" style="position: relative; display: inline-block; background-color: blue"></div>
|
||||
<div class="circle" style="position: relative; display: inline-block; background-color: green"></div>
|
||||
<div class="circle" style="position: relative; display: inline-block; background-color: yellow"></div>
|
||||
<div class="circle" style="position: relative; display: inline-block; background-color: darkblue"></div>
|
||||
<div class="circle" style="position: relative; display: inline-block; background-image: url('../assets/image2_1.jpg')"></div>
|
||||
<p style="mix-blend-mode: color; font-weight: 900; font-size: x-large; position: absolute; top: 0;">
|
||||
mix-blend-mode: color; Large text over background colors.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user