Sharp put images side by side with a linear gradient transition between images - sharp

I'm trying to use the sharp library to put images side by side but can't get a linear transition between the images to work, what's the correct way to do that?
This is a sample output without the linear gradient:
I tried multiple blend modes but they all don't yield the result I'd like to have, perhaps do I need an SVG linear gradient between the images?
const overlayPixels = 50;
const buffer = await sharp({
create: {
width: 2048,
height: 512,
channels: 4,
background: { r: 255, g: 255, b: 255, alpha: 0 },
},
})
.composite([
{ input: "./images/1.png", left: 0, top: 0 },
{
input: Buffer.from([0, 0, 0, 255]),
raw: {
width: 1,
height: 1,
channels: 4,
},
blend: "multiply",
},
{
input: "./images/2.png",
left: 512 - overlayPixels,
top: 0,
},
{
input: "./images/3.png",
left: 1024 - overlayPixels,
top: 0,
},
{
input: "./images/4.png",
left: 1536 - overlayPixels,
top: 0,
},
])
.toFormat("jpeg")
.toBuffer();
fs.writeFileSync(`./output.jpg`, buffer);

Related

How do I convert an array of two-dimensional Cartesian coordinates to an OpenCV input array?

Initially, I tried implementing the OpenCV Basic Drawing example with rust using Rust OpenCV bindings (Crate opencv 0.48.0).
However, I was stuck.
I want to draw a closed polygon with opencv::imgproc::polylines.
The vertices of the polygon are given by an array of two-dimensional Cartesian coordinates.
I need to pass these points to the 2nd argument of the function which is of type &dyn opencv::core::ToInputArray.
This is where I struggle. How do I convert the array of vertices to an argument of type opencv::core::ToInputArray?
let pts = [[100, 50], [50, 150], [150, 150]];
imgproc::polylines(
&mut image,
???, <-- "pts" have to go here
true,
core::Scalar::from([0.0, 0.0, 255.0, 255.0]),
1, 8, 0).unwrap();
Minimal example
use opencv::{core, imgproc, highgui};
fn main() {
let mut image : core::Mat = core::Mat::new_rows_cols_with_default(
200, 200, core::CV_8UC4, core::Scalar::from([0.0, 0.0, 0.0, 0.0])).unwrap();
// draw yellow quad
imgproc::rectangle(
&mut image, core::Rect {x: 50, y: 50, width: 100, height: 100},
core::Scalar::from([0.0, 255.0, 255.0, 255.0]), -1, 8, 0).unwrap();
// should draw red triangle -> causes error (of course)
/*
let pts = [[100, 50], [50, 150], [150, 150]];
imgproc::polylines(
&mut image,
&pts,
true,
core::Scalar::from([0.0, 0.0, 255.0, 255.0]),
1, 8, 0).unwrap();
*/
highgui::imshow("", &image).unwrap();
highgui::wait_key(0).unwrap();
}
[dependencies]
opencv = {version = "0.48.0", features = ["buildtime-bindgen"]}
I found the solution with the help of the comment from #kmdreko.
I can define the vertices with an opencv::types::VectorOfPoint, that implements an opencv::core::ToInputArray trait:
let pts = types::VectorOfPoint::from(vec![
core::Point{x: 100, y: 50},
core::Point{x: 50, y: 150},
core::Point{x: 150, y: 150}]
);
Complete example:
use opencv::{core, types, imgproc, highgui};
fn main() {
let mut image : core::Mat = core::Mat::new_rows_cols_with_default(
200, 200, core::CV_8UC4, core::Scalar::from([0.0, 0.0, 0.0, 0.0])).unwrap();
let pts = types::VectorOfPoint::from(vec![
core::Point{x: 100, y: 50},
core::Point{x: 50, y: 150},
core::Point{x: 150, y: 150}]
);
imgproc::polylines(
&mut image,
&pts,
true,
core::Scalar::from([0.0, 0.0, 255.0, 255.0]),
1, 8, 0).unwrap();
highgui::imshow("", &image).unwrap();
highgui::wait_key(0).unwrap();
}

bezier line in konvajs is not the normal bezier

I want change normal line to bezier curve with this:
var grayBezierLine = new Konva.Line({
points: [50, 50, 100, 100, 150, 50, 200, 100, 250, 50, 300, 100, 350, 50],
stroke: 'gray',
strokeWidth: 15,
lineCap: 'round',
lineJoin: 'round',
bezier: true,
});
but the display is weird, after check the sourcecode, found this:
if (bezier) {
// no tension but bezier
n = 2;
while (n < length) {
context.bezierCurveTo(
points[n++],
points[n++],
points[n++],
points[n++],
points[n++],
points[n++]
);
}
}
At first I thought except the first(50, 50) point and last point(350, 50), all intermediate points are control points, but it's not, every three points forms a curve.
this is a reproduce demo.
My question is this a deliberate design or a bug?

Konvajs layer positions not being set as expected

I have an app where I am panning and zooming multiple layers.
However, when I set the position of the layers they are being updated to the wrong values.
For instance, after calling:
layer.position({
x: 12,
y: 233,
});
I would expect
layer.getClientRect();
to return
{
x: 12,
y: 233,
}
Instead it returns
{
x: -22,
y: 220,
}
Is there any known reason this is happening?
I realised I wasn't taking into account all the offsets. The x position of a circle is set from the centre while getClientRect() returns the width and height including negatives. So getClientRect() on a circle with a radius of 50 and x of 0 will actually return {x: -25, y: -25, width: 50, height: 50}.
Seems to work for me as advertised in this cut down test. Did you move the stage or something ?
In the snippet below I draw a layer with 4 'corner' rects, display its value from grtClientRect() in 'Layer pos #1' which gives (0, 0), then move the stage to 12, 233 and display its value from grtClientRect() in 'Layer pos #2' which shows (12, 233). I move the layer back up to (12, 23) just for fun thereafter.
var stage = new Konva.Stage({
container: 'container',
width: 1600,
height: 400
});
// add a layer
var layer = new Konva.Layer();
stage.add(layer);
// add 4 corner rects - code I happened to have to hand
var rectCorner = [];
for (i=0;i<4;i=i+1){
rectCorner[i] = new Konva.Rect({
x: 0,
y: 0,
width: 50,
height: 50,
fill: 'red',
opacity: 0.5,
strokeWidth: 0})
layer.add(rectCorner[i]);
}
// put the rects in the corners to give a known layer space
rectCorner[1].position({x:500, y: 0});
rectCorner[2].position({x:500, y: 150});
rectCorner[3].position({x:0, y: 150});
layer.draw();
// get the client rect now
var p = layer.getClientRect();
$('#info1').html('Layer pos #1=' + p.x + ', ' + p.y);
// move the layer...
layer.position({
x: 12,
y: 233,
});
// get the client rect now
var p = layer.getClientRect();
$('#info2').html('Layer pos #2=' + p.x + ', ' + p.y);
// move the layer back to the top...
layer.position({
x: 12,
y: 23,
});
stage.draw();
p
{
padding: 4px;
}
#container
{
background-color: silver;
overflow: hidden;
}
<div id='info1'></div>
<div id='info2'></div>
<div id="container"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.7.6/konva.min.js"></script>
<script type="text/javascript" src="test.js"></script>

Highcharts Multiseries Gauge with DataLabels at Ends

How would you achieve this (jsFiddle link)
dynamically for the Highcharts "Activity Gauge", so obviously it works there but I had to manually determine the correct x & y coordinates for the labels.
This result is similar to using the "inside" property for column charts, but seems nothing is built-in like that for this chart type (that I've run across at least). One could come close by passing in the same y values as for each series as tick marks on the y-axis (see snippet below) and getting rid of all markings except the number, but then I can't stagger those to be positioned correctly within each series, and for the dataLabel x & y approach I don't know the equation to be able to position the labels based on the series y values dynamically with a callback.
yAxis: {
labels: {
enabled: true,
x: 10, y: -15,
format: '{value} %',
style: {
fontSize: 16,
color: 'black'
}
},
min: 0,
max: 100,
gridLineColor: 'transparent',
lineColor: 'transparent',
minorTickLength: 0,
//tickInterval: 67,
tickPositions: [50, 65, 80], //TRIED TO USE Y-AXIS LABELS BUT COULDN'T STAGGER THEM
tickColor: '#000000',
tickPosition: 'inside',
//tickLength: 50,
tickWidth: 0
},
Any help would be much appreciated, thanks in advance.
Solved via Highcharts support forum:
fiddle
, just call the following function on chart load and redraw events:
function redrawConnectors() {
var chart = this,
cX, cY,
shapeArgs, ang, posX, posY, bBox;
Highcharts.each(chart.series, function(series, j) {
Highcharts.each(series.points, function(point, i) {
if (point.dataLabel) {
bBox = point.dataLabel.getBBox();
shapeArgs = point.shapeArgs;
cX = shapeArgs.x,
cY = shapeArgs.y,
ang = shapeArgs.end;
posX = cX + shapeArgs.r * Math.cos(ang);
posY = cY + shapeArgs.r * Math.sin(ang);
point.dataLabel.attr({
x: posX - bBox.width / 2,
y: posY - bBox.height / 2
});
}
});
});
}

"Stops" in Highcharts polar chart column?

We want to achieve the same as "stops" (like in solid gauge), where we can define values from 0-5 is red, 6 and 7 is yellow, and 8 is green for each column in a Highcharts polar chart.
But stops, that we have tried, is displaying a gradient for the whole column independent of value.. not able to define colours for each column based on specific value.
Only option I see so far is to set colour based on data directly. Example here: http://jsfiddle.net/buzLywrx/3/
That is:
data: [{ y: 8, color: 'green'}, { y: 7, color: 'green'}, { y: 6, color: 'yellow'}, { y: 5, color: 'yellow'}, { y: 4, color: 'red'}, { y: 3, color: 'green'}, { y: 2, color: 'red'}, { y: 1, color: 'red'}],
We are displaying a mean, so the data can actually be any number (with two decimals) between 0-100.
What is the best option to achieve column colour based on a value range?
You can iterate on each point in the serie and update color by condition.
var color;
$.each(chart.series[0].data, function(i, data){
if(data.y<4) {
color = 'red';
} else if((data.y>4) && (data.y <6)) {
color = 'yellow';
} else if(data.y > 6) {
color = 'orange';
}
data.update({
color: color
});
});
Example: http://jsfiddle.net/buzLywrx/4/

Resources