mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
⚡ Add shear option, resize with alpha color and fix bug
This commit is contained in:
parent
2cc6f6c218
commit
9fee42b2a8
|
@ -82,8 +82,8 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|
||||||
<div v-else-if="parameter.type === 'color'" ref="inputField" class="color-input">
|
<div v-else-if="parameter.type === 'color'" ref="inputField" class="color-input">
|
||||||
<el-color-picker :value="displayValue" :disabled="isReadOnly" @change="valueChanged" size="small" class="color-picker" @focus="setFocus" :title="displayTitle" ></el-color-picker>
|
<el-color-picker :value="displayValue" :disabled="isReadOnly" @change="valueChanged" size="small" class="color-picker" @focus="setFocus" :title="displayTitle" :show-alpha="getArgument('showAlpha')"></el-color-picker>
|
||||||
<el-input v-model="tempValue" size="small" type="text" :value="displayValue" :disabled="isReadOnly" @change="valueChanged" @keydown.stop @focus="setFocus" :title="displayTitle" ></el-input>
|
<el-input v-model="tempValue" size="small" type="text" :value="tempValue" :disabled="isReadOnly" @change="valueChanged" @keydown.stop @focus="setFocus" :title="displayTitle" ></el-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="parameter.type === 'boolean'">
|
<div v-else-if="parameter.type === 'boolean'">
|
||||||
|
@ -213,6 +213,10 @@ export default mixins(
|
||||||
this.loadRemoteParameterOptions();
|
this.loadRemoteParameterOptions();
|
||||||
},
|
},
|
||||||
value () {
|
value () {
|
||||||
|
if (this.parameter.type === 'color' && this.getArgument('showAlpha') === true) {
|
||||||
|
// Do not set for color with alpha else wrong value gets displayed in field
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.tempValue = this.displayValue as string;
|
this.tempValue = this.displayValue as string;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -274,6 +278,18 @@ export default mixins(
|
||||||
returnValue = this.expressionValueComputed;
|
returnValue = this.expressionValueComputed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.parameter.type === 'color' && this.getArgument('showAlpha') === true && returnValue.charAt(0) === '#') {
|
||||||
|
// Convert the value to rgba that el-color-picker can display it correctly
|
||||||
|
const bigint = parseInt(returnValue.slice(1), 16);
|
||||||
|
const h = [];
|
||||||
|
h.push((bigint >> 24) & 255);
|
||||||
|
h.push((bigint >> 16) & 255);
|
||||||
|
h.push((bigint >> 8) & 255);
|
||||||
|
h.push((255 - bigint & 255) / 255);
|
||||||
|
|
||||||
|
returnValue = 'rgba('+h.join()+')';
|
||||||
|
}
|
||||||
|
|
||||||
if (returnValue !== undefined && returnValue !== null && this.parameter.type === 'string') {
|
if (returnValue !== undefined && returnValue !== null && this.parameter.type === 'string') {
|
||||||
const rows = this.getArgument('rows');
|
const rows = this.getArgument('rows');
|
||||||
if (rows === undefined || rows === 1) {
|
if (rows === undefined || rows === 1) {
|
||||||
|
@ -537,14 +553,35 @@ export default mixins(
|
||||||
// Set focus on field
|
// Set focus on field
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
(this.$refs.inputField.$el.querySelector('input') as HTMLInputElement).focus();
|
if (this.$refs.inputField.$el) {
|
||||||
|
// @ts-ignore
|
||||||
|
(this.$refs.inputField.$el.querySelector('input') as HTMLInputElement).focus();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
rgbaToHex (value: string): string | null {
|
||||||
|
// Convert rgba to hex from: https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
|
||||||
|
const valueMatch = (value as string).match(/^rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)$/);
|
||||||
|
if (valueMatch === null) {
|
||||||
|
// TODO: Display something if value is not valid
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const [r, g, b, a] = valueMatch.splice(1, 4).map(v => Number(v));
|
||||||
|
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1) + ((1 << 8) + Math.floor((1-a)*255)).toString(16).slice(1);
|
||||||
|
},
|
||||||
valueChanged (value: string | number | boolean | Date | null) {
|
valueChanged (value: string | number | boolean | Date | null) {
|
||||||
if (value instanceof Date) {
|
if (value instanceof Date) {
|
||||||
value = value.toISOString();
|
value = value.toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.parameter.type === 'color' && this.getArgument('showAlpha') === true && value !== null && value.toString().charAt(0) !== '#') {
|
||||||
|
const newValue = this.rgbaToHex(value as string);
|
||||||
|
if (newValue !== null) {
|
||||||
|
this.tempValue = newValue;
|
||||||
|
value = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const parameterData = {
|
const parameterData = {
|
||||||
node: this.node !== null ? this.node.name : this.nodeName,
|
node: this.node !== null ? this.node.name : this.nodeName,
|
||||||
name: this.path,
|
name: this.path,
|
||||||
|
@ -570,6 +607,13 @@ export default mixins(
|
||||||
this.nodeName = this.node.name;
|
this.nodeName = this.node.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.parameter.type === 'color' && this.getArgument('showAlpha') === true && this.displayValue !== null && this.displayValue.toString().charAt(0) !== '#') {
|
||||||
|
const newValue = this.rgbaToHex(this.displayValue as string);
|
||||||
|
if (newValue !== null) {
|
||||||
|
this.tempValue = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.remoteMethod !== undefined && this.node !== null) {
|
if (this.remoteMethod !== undefined && this.node !== null) {
|
||||||
// Make sure to load the parameter options
|
// Make sure to load the parameter options
|
||||||
// directly and whenever the credentials change
|
// directly and whenever the credentials change
|
||||||
|
|
|
@ -9,6 +9,12 @@ import {
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import * as gm from 'gm';
|
import * as gm from 'gm';
|
||||||
|
import { file } from 'tmp-promise';
|
||||||
|
import {
|
||||||
|
writeFile as fsWriteFile,
|
||||||
|
} from 'fs';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
const fsWriteFileAsync = promisify(fsWriteFile);
|
||||||
|
|
||||||
|
|
||||||
export class EditImage implements INodeType {
|
export class EditImage implements INodeType {
|
||||||
|
@ -61,6 +67,11 @@ export class EditImage implements INodeType {
|
||||||
value: 'resize',
|
value: 'resize',
|
||||||
description: 'Change the size of image',
|
description: 'Change the size of image',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Shear',
|
||||||
|
value: 'shear',
|
||||||
|
description: 'Shear image along the X or Y axis',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Text',
|
name: 'Text',
|
||||||
value: 'text',
|
value: 'text',
|
||||||
|
@ -385,6 +396,11 @@ export class EditImage implements INodeType {
|
||||||
value: 'onlyIfSmaller',
|
value: 'onlyIfSmaller',
|
||||||
description: 'Resize only if image is smaller than width or height',
|
description: 'Resize only if image is smaller than width or height',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Percent',
|
||||||
|
value: 'percent',
|
||||||
|
description: 'Width and height are specified in percents.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
default: 'maximumArea',
|
default: 'maximumArea',
|
||||||
displayOptions: {
|
displayOptions: {
|
||||||
|
@ -422,7 +438,10 @@ export class EditImage implements INodeType {
|
||||||
displayName: 'Background Color',
|
displayName: 'Background Color',
|
||||||
name: 'backgroundColor',
|
name: 'backgroundColor',
|
||||||
type: 'color',
|
type: 'color',
|
||||||
default: '#ffffff',
|
default: '#ffffffff',
|
||||||
|
typeOptions: {
|
||||||
|
showAlpha: true,
|
||||||
|
},
|
||||||
displayOptions: {
|
displayOptions: {
|
||||||
show: {
|
show: {
|
||||||
operation: [
|
operation: [
|
||||||
|
@ -433,6 +452,39 @@ export class EditImage implements INodeType {
|
||||||
description: 'The color to use for the background when image gets rotated by anything which is not a multiple of 90..',
|
description: 'The color to use for the background when image gets rotated by anything which is not a multiple of 90..',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// shear
|
||||||
|
// ----------------------------------
|
||||||
|
{
|
||||||
|
displayName: 'Degrees X',
|
||||||
|
name: 'degreesX',
|
||||||
|
type: 'number',
|
||||||
|
default: 0,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'shear',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'X (horizontal) shear degrees.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Degrees Y',
|
||||||
|
name: 'degreesY',
|
||||||
|
type: 'number',
|
||||||
|
default: 0,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'shear',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Y (vertical) shear degrees.',
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
displayName: 'Options',
|
displayName: 'Options',
|
||||||
name: 'options',
|
name: 'options',
|
||||||
|
@ -503,7 +555,6 @@ export class EditImage implements INodeType {
|
||||||
},
|
},
|
||||||
description: 'Sets the jpeg|png|tiff compression level from 0 to 100 (best).',
|
description: 'Sets the jpeg|png|tiff compression level from 0 to 100 (best).',
|
||||||
},
|
},
|
||||||
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -529,6 +580,8 @@ export class EditImage implements INodeType {
|
||||||
|
|
||||||
let gmInstance = gm(Buffer.from(item.binary![dataPropertyName as string].data, BINARY_ENCODING));
|
let gmInstance = gm(Buffer.from(item.binary![dataPropertyName as string].data, BINARY_ENCODING));
|
||||||
|
|
||||||
|
gmInstance = gmInstance.background('transparent');
|
||||||
|
|
||||||
if (operation === 'blur') {
|
if (operation === 'blur') {
|
||||||
const blur = this.getNodeParameter('blur') as number;
|
const blur = this.getNodeParameter('blur') as number;
|
||||||
const sigma = this.getNodeParameter('sigma') as number;
|
const sigma = this.getNodeParameter('sigma') as number;
|
||||||
|
@ -574,6 +627,8 @@ export class EditImage implements INodeType {
|
||||||
option = '<';
|
option = '<';
|
||||||
} else if (resizeOption === 'onlyIfLarger') {
|
} else if (resizeOption === 'onlyIfLarger') {
|
||||||
option = '>';
|
option = '>';
|
||||||
|
} else if (resizeOption === 'percent') {
|
||||||
|
option = '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
gmInstance = gmInstance.resize(width, height, option);
|
gmInstance = gmInstance.resize(width, height, option);
|
||||||
|
@ -581,6 +636,10 @@ export class EditImage implements INodeType {
|
||||||
const rotate = this.getNodeParameter('rotate') as number;
|
const rotate = this.getNodeParameter('rotate') as number;
|
||||||
const backgroundColor = this.getNodeParameter('backgroundColor') as string;
|
const backgroundColor = this.getNodeParameter('backgroundColor') as string;
|
||||||
gmInstance = gmInstance.rotate(backgroundColor, rotate);
|
gmInstance = gmInstance.rotate(backgroundColor, rotate);
|
||||||
|
} else if (operation === 'shear') {
|
||||||
|
const xDegrees = this.getNodeParameter('degreesX') as number;
|
||||||
|
const yDegress = this.getNodeParameter('degreesY') as number;
|
||||||
|
gmInstance = gmInstance.shear(xDegrees, yDegress);
|
||||||
} else if (operation === 'text') {
|
} else if (operation === 'text') {
|
||||||
const fontColor = this.getNodeParameter('fontColor') as string;
|
const fontColor = this.getNodeParameter('fontColor') as string;
|
||||||
const fontSize = this.getNodeParameter('fontSize') as number;
|
const fontSize = this.getNodeParameter('fontSize') as number;
|
||||||
|
@ -624,6 +683,8 @@ export class EditImage implements INodeType {
|
||||||
// data references which do not get changed still stay behind
|
// data references which do not get changed still stay behind
|
||||||
// but the incoming data does not get changed.
|
// but the incoming data does not get changed.
|
||||||
Object.assign(newItem.binary, item.binary);
|
Object.assign(newItem.binary, item.binary);
|
||||||
|
// Make a deep copy of the binary data we change
|
||||||
|
newItem.binary![dataPropertyName as string] = JSON.parse(JSON.stringify(newItem.binary![dataPropertyName as string]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.quality !== undefined) {
|
if (options.quality !== undefined) {
|
||||||
|
|
|
@ -408,6 +408,7 @@ export interface INodePropertyTypeOptions {
|
||||||
numberStepSize?: number; // Supported by: number
|
numberStepSize?: number; // Supported by: number
|
||||||
password?: boolean; // Supported by: string
|
password?: boolean; // Supported by: string
|
||||||
rows?: number; // Supported by: string
|
rows?: number; // Supported by: string
|
||||||
|
showAlpha?: boolean; // Supported by: color
|
||||||
[key: string]: boolean | number | string | EditorTypes | undefined | string[];
|
[key: string]: boolean | number | string | EditorTypes | undefined | string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue