how can I calculate the steps in a discrete function of feComponentTransfer in linearRGB color space - svg-filters

I'm trying to make a discrete gradient using the feComponentTransfer functions like this:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg x="0" y="0" width="500px" height="120px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>A discrete gradient</title>
<defs>
<linearGradient id="inputImage" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0" stop-color="black"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<filter id="discrete" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%" color-interpolation-filters="linearRGB">
<feComponentTransfer>
<feFuncR type="discrete" tableValues=".666667 .6 .533333 .466667 .4 .333333 .266667 .2 .133333 .066667"/>
<feFuncG type="discrete" tableValues=".666667 .6 .533333 .466667 .4 .333333 .266667 .2 .133333 .066667"/>
<feFuncB type="discrete" tableValues=".933333 .866667 .8 .733333 .666667 .6 .533333 .466667 .4 .333333"/>
</feComponentTransfer>
</filter>
</defs>
<rect x="10px" y="10px" width="480px" height="100px" fill="url(#inputImage)" filter="url(#discrete)"/>
</svg>
I was expecting to see these colors: #AAAAEE, #9999DD, #8888CC, #7777BB, #6666AA, #555599, #444488, #333377, #222266, #111155 but, instead, Firefox* displayed these: #D5D5F7, #CBCBEF, #C1C1E7, #B6B6DE, #AAAAD5, #9C9CCB, #8D8DC1, #7C7CB6, #6666AA, #49499C respectively, which gave a similar blend but a few tones brighter. I know that this filter's job is to adjust the brightness, the contrast etc. however I don't understand how it works in this case. So, the question here is how should I calculate the steps in the tableValues - inside the linearRGB color space - in order to display exactly the colors I want.
I noticed that most of the component values of the displayed (output) colors are mapped completely out of the given ranges, and I was wondering -please correct me if I'm wrong- how is that agrees with the spec.
Since I don't understand how these functions work in linearRGB color space, I decided to get manually the colors I want. I tried random values and after thousands of attempts, I finally found the steps for the first 6 desired colors (#AAAAEE, #9999DD, #8888CC, #7777BB, #6666AA, #555599) and the ninth one (#222266). For the seventh desired color (#444488, R:68|0.266667, G:68|0.266667, B:136|0.533333) I found easily the feFuncB step but couldn't find a value for red and green functions to output exactly 68|0.266667. So the closest to the desired #444488 gave me the value 0.058823 for red and green, which outputs a near #454588 instead. I faced the same problem also with the desired 8th (#333377) and 10th (#111155) colors for which the closest outputs I could achieved was #353577 and #0D0D55 respectively.
Here are the tableValues written in a way to output (almost) all the colors I wanted in the first place*:
<feFuncR type="discrete" tableValues=".4 .317647 .247058 .184313 .133333 .09 .058823 .0353 .015686 .0039"/>
<feFuncG type="discrete" tableValues=".4 .317647 .247058 .184313 .133333 .09 .058823 .0353 .015686 .0039"/>
<feFuncB type="discrete" tableValues=".8588 .721568 .603921 .498039 .4 .317647 .247 .184313 .13333 .09"/>
Now I repeat the question: Is there an easy way (mathematical type, a multiplier or something) to use in order to have specified colors displayed, without wasting time testing random decimals?
the results are from Firefox 60.0.2 on Ubuntu 16.4 64-bit Gnome, checked with the Gpick tool and, as you already know, differ from other rendering engines on the same or on other OS. At this time I'm only interested in how it works or, better, in how it should work.
Thanks in advance
Spyros Andredakis

Before I answer, you need to be really careful of what your eyedropper is telling you are the color values. If you want to get a specific color in standard sRGB or linearRGB space, make sure that your eyedropper is set to that space.
That said if you're going to do a transform in linearRGB, but you want to get a specific color in sRGB as the result, then you need to specify the equivalent of the target sRGB color in linearRGB terms. You do this by using the gamma correction formula.
For example, if you want the first color in your gradient to be #AAAAEE in sRGB, then you have to do the following correction (in decimal) to your array inputs:
Color in linearRGB = ((Color in sRGB+0.055)/1.055)^2.4
So, for example, the first R/G/B values in your component transfer array should be
R : 0.402 = ((.6667 + 0.055)/1.055)^2.4
G : 0.402 = ((.6667 + 0.055)/1.055)^2.4
B : 0.855 = ((.9333 + 0.055)/1.055)^2.4
This formula is not accurate 100% in general - you need to use a different formula when the sRGB unit value is less than 0.04045 (L=S/12.92). But all your target values are above 0.04 so we don't need to worry.
Full result:
<svg x="0" y="0" width="500px" height="120px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>A discrete gradient</title>
<defs>
<linearGradient id="inputImage" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0" stop-color="black"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<filter id="discrete" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
<feComponentTransfer>
<feFuncR type="discrete" tableValues="0.4020 0.3185 0.2462 0.1845 0.1329 0.0908 0.0578 0.0331 0.0160 0.0056"/>
<feFuncG type="discrete" tableValues="0.4020 0.3185 0.2462 0.1845 0.1329 0.0908 0.0578 0.0331 0.0160 0.0056"/>
<feFuncB type="discrete" tableValues="0.8550 0.7231 0.6038 0.4969 0.4020 0.3185 0.2462 0.1845 0.1329 0.0908"/>
</feComponentTransfer>
</feComponentTransfer>
</filter>
</defs>
<rect x="10px" y="10px" width="480px" height="100px" fill="url(#inputImage)" filter="url(#discrete)"/>
</svg>

Related

Mermaid in tabs

The arrows are not displayed in the second tab. Bug?
It works here https://docusaurus.io/tests/pages/diagrams#mermaid-in-tabs
I have:
a) In "tab-a", the arrows are displayed:
b) But in "tab-b", the arrows are not displayed:
Version of docusaurus: 2.2.0
Type files: .md or .mdx
import Tabs from '#theme/Tabs';
import TabItem from '#theme/TabItem';
<Tabs>
<TabItem value="tab-a">
The following mermaid diagram is shown:
```mermaid
graph LR
a ---> c(10)
b ---> c(10)
```
</TabItem>
<TabItem value="tab-b">
This mermaid diagram is not displayed:
```mermaid
graph LR
d ---> z(42)
e ---> z(42)
```
</TabItem>
</Tabs>
I copy/pasted the code from your docussaurus reference, so I can see the problem.
I believe that is a bug indeed...
This is how I managed to work-around:
import Tabs from '#theme/Tabs';
import TabItem from '#theme/TabItem';
# Mermaid in tabs
<!-- [start] add this to avoid the possible bug. Note: the empty line before [```] is necessary -->
```mermaid
flowchart TD
```
<!-- [end] add this to avoid the possible bug -->
<Tabs>
<TabItem value="tab-a">
```mermaid
graph LR
a ---> c(10)
b ---> c(10)
```
</TabItem>
<TabItem value="tab-b">
```mermaid
graph LR
d ---> z(42)
e ---> z(42)
```
</TabItem>
</Tabs>
NOTES
I downloaded the page that worked, from docusaurus;
I trimmed all code, until it broke;
I tested until I found a way to render the "wanted" result, without any extra "artifacts";
Now we have a working code, but it is a workaround one.

How to pixel perfect align text-element

I want my vue Konva Text element to completely fill the given height, like i expect of a rectangle.
This is issue becomes obvious when pairing with text images, (converting svg text to canvas) that properly match the given dimension
<v-text :config={
x: 50,
y: 50,
width: 1000,
height: 60,
fontSize: 60,
fontStyle: 'bold',
fontFamily 'Campton Book'
text: 'WELT'
}
/>
<v-rect
:config="{ x: 50, y: 50, fill: 'black', height: 60, width: 200 }"
/>
Second Part, is there any way to always pixel perfectly align the left side with the border? the x coordinate matches the border
Is this due to font constraints? What am I missing?
I tried to get the height of the text node to fix this positioning but this is the given height passed down as props
Text is defined as having parts above and below the baseline. Above is termed 'ascenders' amd below is 'descenders', which are required for lower case letters like j y g.
Setting the text fontSize to 60 does not say 'whatever the string, make it fill a space 60px high'. Instead it says 'Make text in a 60px font', which makes space for the descenders because they will generally be required.
If you know for sure that the text will be all caps, then a solution is to measure the height used and increase the font size by a computed factor so that the font fills the line height.
To do this you'll need to get the glyph measurements as follows:
const lineHeight = 60; // following your code
// make your text shape here...left out for brevity
const metrics = ctx.measureText('YOUR CAPS TEXT');
capsHeight = Math.abs(metrics.actualBoundingBoxAscent)
fontSize = lineHeight * lineHeight / capsHeight;
If I got that right, your 60px case should give a value around 75. That's based on the convention that ascenders are 80% of the line height. Now you set the font size of your shape to this new value and you should be filling the entire line height.
Regarding the left-alignment, this relies on what the font gurus call the a-b-c widths. The left gap is the a-space, the b is the character width (where the ink falls) and the c-space is the same as the a-space but on the right hand side.
Sadly unless someone else can tell me I am wrong, you don't get a-b-c widths in the canvas TextMetric. There is a workaround which is rather convoluted but viable. You would draw the text in black on an off-screen canvas filled with a transparent background. Then get the canvas pixel data and walk horizontal lines from the left of the canvas inspecting pixels and looking for the first colored pixel. Once you find it you have the measurement to offset the text shape horizontally.

How to draw Polyline without rendering map using coordinates

I have array of coordinates and I can draw polyline on map using theese coordinates without problem.
Now what I want to do is, only drawing a polyline to screen without rendering the map.
Below is first few items of my coordinates array:
[
[6.56674, 45.39881],
[6.56682, 45.399],
[6.56701, 45.39959],
[6.56727, 45.40006],
[6.56738, 45.4003],
[6.56745, 45.40041],
[6.56757, 45.40053]
]
I want to draw the same polyline to black background without rendering map.
I tried to draw svg polyline using the array of coordinates but I couldn't achieved what I wanted only a dot appeared on the screen. Didn't draw a polyline.
import {Svg, Polyline} from 'react-native-svg';
<Svg height="100" width="100">
<Polyline
points={MY_ARRAY_OF_COORDS.map(item => `${item[0]},${item[1]`).join(" ")}
fill="none"
stroke="blue"
strokeWidth="5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</Svg>
The <polyline> is actually rendered but almost invisible since the coordinates are very close to each other.
So you need to calculate a scale factor.
Js example
const coords= [
[6.56674, 45.39881],
[6.56682, 45.399],
[6.56701, 45.39959],
[6.56727, 45.40006],
[6.56738, 45.4003],
[6.56745, 45.40041],
[6.56757, 45.40053]
];
//calculate coordinate range for a scale factor
let xArr = coords.map((val)=>{return val[0]} );
let xMin = Math.min(...xArr);
let xMax = Math.max(...xArr);
let yArr = coords.map((val)=>{return val[1]} );
let yMin = Math.min(...yArr);
let yMax = Math.max(...yArr);
let xRange = xMax- xMin;
let yRange = yMax- yMin;
let scale = 100/Math.max(...[xRange, yRange]);
//console.log(xRange, yRange, scale)
//scale coordinates
coords.forEach(function(coord){
let [x,y] =[coord[0], coord[1]];
coord[0] = (x-xMin)*scale;
coord[1] = (y-yMin)*scale;
})
//draw polyline
const svg = document.querySelector('svg');
const polyline = svg.querySelector('polyline');
polyline.setAttribute('points', coords.join());
svg{
border: 1px solid #ccc;
overflow:visible
}
<svg height="100" width="100">
<polyline
points=""
fill="none"
stroke="blue"
strokeWidth="10"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
First we need to calculate ranges for x and y values (so the maximum distances between maximum and minimum x).
let xRange = xMax- xMin; //0.000829999999999664
let yRange = yMax- yMin; //0.001720000000005939
If you need a svg bounding box of 100x100 units the scaling factor would be:
let scale = 100/Math.max(...[xRange, yRange]);
Eventually we need to subtract the minimum x and y offsets to align the polyline to the x/y axes origin.

T shaped divider in LaTeX by using multicols

\documentclass[10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{blindtext}
\usepackage{multicol}
\usepackage{geometry}
\geometry{
total={272mm,394mm},
left=20mm,
right=20mm,
top=20mm,
bottom=20mm
}
\setlength{\columnsep}{1cm}
\setlength{\columnseprule}{0.3mm}
\title{Test}
\date{}
\begin{document}
\maketitle
\begin{multicols}{2}
[
\flushleft{\rule{176mm}{0.3mm}}
]
\blindtext[10]
\end{multicols}
\end{document}
I have tried to make a 'T' shaped divider for a document, but it seems like multicols doesn't support a horizontal line above the columns.
I tried to simulate this effect by using
\flushleft{\rule{176mm}{0.3mm}}
but this doesn't help me out.
Is there any way to erase the gap between the two dividers? or is there a different way to make a 'T' shaped divider?
Also, im curious why the the horizontal length of the \rule is 176mm. the width of the paper is 272mm and the margins in the left and right are 20mm each, so why is the length 176mm instead of 232mm?
You could place your horizontal line before the multicols:
\documentclass[10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{blindtext}
\usepackage{multicol}
\usepackage{geometry}
\geometry{
% total={272mm,394mm},
left=20mm,
right=20mm,
top=20mm,
bottom=20mm
}
\setlength{\columnsep}{1cm}
\setlength{\columnseprule}{0.3mm}
\title{Test}
\date{}
\begin{document}
\maketitle
\noindent\rule{\textwidth}{0.3mm}
\vspace*{-0.5cm}
\begin{multicols}{2}
\blindtext[10]
\end{multicols}
\end{document}

kCGImageAlphaPremultipliedFirst and kCGImageAlphaFirst

Can you explain to me difference between kCGImageAlphaPremultipliedFirst and kCGImageAlphaFirst?
What's mean Premultiplied in practice?
In short, premultiplied means that the alpha value will also affect the color component values of the pixels when a pixel which is not opaque is represented.
From the Quartz 2D drawing guide:
For bitmaps that have an alpha component, whether the color components
are already multiplied by the alpha value. Premultiplied alpha
describes a source color whose components are already multiplied by an
alpha value. Premultiplying speeds up the rendering of an image by
eliminating an extra multiplication operation per color component. For
example, in an RGB color space, rendering an image with premultiplied
alpha eliminates three multiplication operations (red times alpha,
green times alpha, and blue times alpha) for each pixel in the image.
BTW, Pre-Multiplied is likely what the APIs will force you to use because that is Quartz's preference. Fortunately, the conversions aren't terrible (lossy OTOH…).
the shortest way to explain this is in float components, using the range [0...1].
If our RGBA input representation is:
typedef struct t_rgba { float r,g,b,a; } t_rgba;
const t_rgba rgba = { 0.5, 0.5, 0.5, 0.5 };
Then to pre-multiply it:
t_rgba rgba_PreMul = rgba;
rgba_PreMul.r *= rgba_PreMul.a;
rgba_PreMul.g *= rgba_PreMul.a;
rgba_PreMul.b *= rgba_PreMul.a;
Then to de-pre-multiply it:
t_rgba rgba_DePreMul = rgba_PreMul;
if (0.0 < rgba_DePreMul.a && 1.0 > rgba_DePreMul.a) {
const float ialpha = 1.0/rgba_DePreMul.a;
rgba_DePreMul.r *= ialpha;
rgba_DePreMul.g *= ialpha;
rgba_DePreMul.b *= ialpha;
}
You might want some saturation in there, too.
Now that's the basic form, which can be repurposed to other numeric representations. Note that these conversions are lossy. As well, be careful not to pass premultiplied bitmaps where regular bitmaps are expected, and vice versa.