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:
@@ -46,6 +46,7 @@ Below is a list of all the supported CSS properties and values.
|
|||||||
- max-width
|
- max-width
|
||||||
- min-height
|
- min-height
|
||||||
- min-width
|
- min-width
|
||||||
|
- mix-blend-mode (**Limited support**)
|
||||||
- opacity
|
- opacity
|
||||||
- overflow
|
- overflow
|
||||||
- overflow-wrap
|
- overflow-wrap
|
||||||
@@ -79,7 +80,6 @@ These CSS properties are **NOT** currently supported
|
|||||||
- [box-shadow](https://github.com/niklasvh/html2canvas/pull/1086)
|
- [box-shadow](https://github.com/niklasvh/html2canvas/pull/1086)
|
||||||
- [filter](https://github.com/niklasvh/html2canvas/issues/493)
|
- [filter](https://github.com/niklasvh/html2canvas/issues/493)
|
||||||
- [font-variant-ligatures](https://github.com/niklasvh/html2canvas/pull/1085)
|
- [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)
|
- [object-fit](https://github.com/niklasvh/html2canvas/issues/1064)
|
||||||
- [repeating-linear-gradient()](https://github.com/niklasvh/html2canvas/issues/1162)
|
- [repeating-linear-gradient()](https://github.com/niklasvh/html2canvas/issues/1162)
|
||||||
- [writing-mode](https://github.com/niklasvh/html2canvas/issues/1258)
|
- [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 {listStylePosition} from './property-descriptors/list-style-position';
|
||||||
import {listStyleType} from './property-descriptors/list-style-type';
|
import {listStyleType} from './property-descriptors/list-style-type';
|
||||||
import {marginBottom, marginLeft, marginRight, marginTop} from './property-descriptors/margin';
|
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 {overflow, OVERFLOW} from './property-descriptors/overflow';
|
||||||
import {overflowWrap} from './property-descriptors/overflow-wrap';
|
import {overflowWrap} from './property-descriptors/overflow-wrap';
|
||||||
import {paddingBottom, paddingLeft, paddingRight, paddingTop} from './property-descriptors/padding';
|
import {paddingBottom, paddingLeft, paddingRight, paddingTop} from './property-descriptors/padding';
|
||||||
@@ -126,6 +127,7 @@ export class CSSParsedDeclaration {
|
|||||||
marginRight: CSSValue;
|
marginRight: CSSValue;
|
||||||
marginBottom: CSSValue;
|
marginBottom: CSSValue;
|
||||||
marginLeft: CSSValue;
|
marginLeft: CSSValue;
|
||||||
|
mixBlendMode: ReturnType<typeof mixBlendMode.parse>;
|
||||||
opacity: ReturnType<typeof opacity.parse>;
|
opacity: ReturnType<typeof opacity.parse>;
|
||||||
overflowX: OVERFLOW;
|
overflowX: OVERFLOW;
|
||||||
overflowY: OVERFLOW;
|
overflowY: OVERFLOW;
|
||||||
@@ -194,6 +196,7 @@ export class CSSParsedDeclaration {
|
|||||||
this.marginRight = parse(context, marginRight, declaration.marginRight);
|
this.marginRight = parse(context, marginRight, declaration.marginRight);
|
||||||
this.marginBottom = parse(context, marginBottom, declaration.marginBottom);
|
this.marginBottom = parse(context, marginBottom, declaration.marginBottom);
|
||||||
this.marginLeft = parse(context, marginLeft, declaration.marginLeft);
|
this.marginLeft = parse(context, marginLeft, declaration.marginLeft);
|
||||||
|
this.mixBlendMode = parse(context, mixBlendMode, declaration.mixBlendMode);
|
||||||
this.opacity = parse(context, opacity, declaration.opacity);
|
this.opacity = parse(context, opacity, declaration.opacity);
|
||||||
const overflowTuple = parse(context, overflow, declaration.overflow);
|
const overflowTuple = parse(context, overflow, declaration.overflow);
|
||||||
this.overflowX = overflowTuple[0];
|
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;
|
textDecorationColor: string;
|
||||||
textDecorationLine: string;
|
textDecorationLine: string;
|
||||||
overflowWrap: string;
|
overflowWrap: string;
|
||||||
|
mixBlendMode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DocumentType extends Node, ChildNode {
|
interface DocumentType extends Node, ChildNode {
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ export class CanvasRenderer extends Renderer {
|
|||||||
switch (paintOrderLayer) {
|
switch (paintOrderLayer) {
|
||||||
case PAINT_ORDER_LAYER.FILL:
|
case PAINT_ORDER_LAYER.FILL:
|
||||||
this.ctx.fillStyle = asString(styles.color);
|
this.ctx.fillStyle = asString(styles.color);
|
||||||
|
this.ctx.globalCompositeOperation = styles.mixBlendMode;
|
||||||
this.renderTextWithLetterSpacing(text, styles.letterSpacing, baseline);
|
this.renderTextWithLetterSpacing(text, styles.letterSpacing, baseline);
|
||||||
const textShadows: TextShadow = styles.textShadow;
|
const textShadows: TextShadow = styles.textShadow;
|
||||||
|
|
||||||
@@ -276,6 +277,7 @@ export class CanvasRenderer extends Renderer {
|
|||||||
this.path(path);
|
this.path(path);
|
||||||
this.ctx.save();
|
this.ctx.save();
|
||||||
this.ctx.clip();
|
this.ctx.clip();
|
||||||
|
this.ctx.globalCompositeOperation = container.styles.mixBlendMode;
|
||||||
this.ctx.drawImage(
|
this.ctx.drawImage(
|
||||||
image,
|
image,
|
||||||
0,
|
0,
|
||||||
@@ -714,6 +716,7 @@ export class CanvasRenderer extends Renderer {
|
|||||||
|
|
||||||
if (!isTransparent(styles.backgroundColor)) {
|
if (!isTransparent(styles.backgroundColor)) {
|
||||||
this.ctx.fillStyle = asString(styles.backgroundColor);
|
this.ctx.fillStyle = asString(styles.backgroundColor);
|
||||||
|
this.ctx.globalCompositeOperation = styles.mixBlendMode;
|
||||||
this.ctx.fill();
|
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>
|
||||||
Reference in New Issue
Block a user