I'm wondering if it's possible to extract the metrics for the baseline of the mrow elements in a rendered mathjax equation, specificically using the SVG Output Jax.
For example, the mml-sample page (raw version here ) has a block element with 3 mrow elements, and I'm wondering if it's possible to extract the position (preferably, the x and y positions of endpoints) of the baselines of these elements.
Here's the short answer: Fork a copy of Mathjax and then set the removable flag on the 'g' elements to false, to prevent the <g> elements that represent the nesting in the original MML from being removed -- an by doing this the origin of the baseline can be read from the transform="translate(...)" and transform="scale(...)" attributes
Next, export any other metrics, such as:
svg.H: Height above the baseline of the entire (sub) expression (un-scaled)
svg.D: Depth below the baseline of the entire (sub) expression (un-scaled)
svg.w: Width of the rendered expression (un-scaled)
svg.r: right margin (un-scaled)
svg.l: left margin (un-scaled)
svg.scale: Scaling factor
here and here with something like:
svg.element.setAttribute("fm",
"{D:" + SVG.Fixed(svg.D,2) +
",H:" + SVG.Fixed(svg.H,2) +
",r:" + SVG.Fixed(svg.r,2) +
",l:" + SVG.Fixed(svg.l,2) +
",w:" + SVG.Fixed(svg.w,2) +
",s:" + SVG.Fixed(svg.scale,5) +
"}");
Optionally, to reduce the extent of unnecessary nesting, change svg.removeable to (svg.removeable || svg.element.nodeName === "g") in this if statement
Related
I need to calculate the height and width of a svg text element. Is there a way to do so without actually adding it to the DOM of my page? I need only the measures not the actual element.
I am using neither d3 nor Raphael, but only plain JavaScript. (Maybe I should use one of the former for my calculations?)
What I am after is just a function like imagettfbbox in PHP, but in plain JavaScript. Is there such a thing? Or is it easy to write?
Since I am not actually using the text elements it seems strange to me to add them and hide them (I also have read somewhere that Firefox has problems with calculating the bbox of hidden elements, Calculating vertical height of a SVG text). But maybe this is the only way to go? Will I have to work with opacity in that case? Do I destroy the element somehow afterwards?
Maybe there is no good way to achieve exactly what I was after. However, giving up the "without actually adding it to the DOM of my page" part, the following function seems to achieve my goal.
function bboxText( svgDocument, string ) {
var data = svgDocument.createTextNode( string );
var svgElement = svgDocument.createElementNS( svgns, "text" );
svgElement.appendChild(data);
svgDocument.documentElement.appendChild( svgElement );
var bbox = svgElement.getBBox();
svgElement.parentNode.removeChild(svgElement);
return bbox;
}
Edit:
A note on the calculation of the height: the height of the bbox returned, i.e. bbox.height, is always the full height of the glyph, i.e. a will have the same height as A. And I could not find a way to calculate them more exactly.
However, one can calculate the height of uppercase accented characters, e.g. Ä. This will be just the negative of the y coordinate of the bbox, i.e. -bbox.y.
Using this one can calculate, for example, some coordinates for vertical alignment. For example to emulate the dominantBaseline attribute set to text-before-edge, text-after-edge, and central.
text-before-edge: dy = -bbox.y
text-after-edge: dy = -bbox.height -bbox.y
central: dy = -bbox.y -bbox.height/2
Where dy is the vertical translation. This can be used to get around limitations of some applications that do not support these alignments set by attributes.
I have encountered a similar problem in VB.Net !
I written a VB.Net program that generate a SVG file and that needs to compute width of text to compute next vertical bar position as you can see in following image
The B line vertical bar is positionned in computing max text width of A line elements.
To do that in Console VB.Net application, I execute following lines of code
Private Sub WriteTextInfo(sInfo As String)
If sInfo <> "" Then
'display Text in SVG file
sw.WriteLine("<text x ='" & (xPos + 10) & "' y='" & yPos & "' fill='black' font-family='Arial' font-size='20'>" & sInfo & "</text>")
'Create Font object as defined in <text> SVG tag
Dim font As New Font("Arial", 20.0F)
'Compute width of text in pixels
Dim xSize = TextRenderer.MeasureText(sInfo, font)
'Divide pixels witdh by a factor 1.4 to obtain SVG width !
Dim iWidth As Decimal = Math.Truncate(CDec(xSize.Width) / 1.4)
'If new vertical position is greater than old vertical position
If xPos + iWidth > xPosMax Then
xPosMax = xPos + iWidth
End If
End If
End Sub
In resume, I compute text's width in pixels using TextRenderer.MeasureText() function and I divide this number by 1.4 to obtain SVG width.
1.4 value is obtained by experiment relatively to my case !
To use TextRendered and Font objects, I have added reference to
System.Drawing
System.Windows.Forms
As you can see, I don't use any DOM method to compute text's width because I compute it in VB.Net program.
I'm trying to zoomable/draggle rectangle from going outside of the svg bounds when panning and zooming. I've tried to implement it based off of this example, but i cant seem to get it to work. I've created this jsfiddle with just the rectangle that is zoomable and draggable. Again, im trying to make it so that you can not drag the rectangle outside of the svg box i put the border on. I know i need to update the move function. the code below is from the first link example but it does not seem to work well so i commented part of it out.
function move() {
var t = d3.event.translate,
s = d3.event.scale;
//t[0] = Math.min(width / 2 * (s - 1), Math.max(width / 2 * (1 - s), t[0]));
//t[1] = Math.min(height / 2 * (s - 1) + 230 * s, Math.max(height / 2 * (1 - s) - 230 * s, t[1]));
//zoom.translate(t);
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
Edit: So additionally i need to be able to drag the rectangle when you are zoomed in all the way and its bigger than the svg. In the image below, the blue rectangle is the svg and green would be the rectangle and you are zoomed in all the way so that the green rectangle takes up the much more than the SVG. This is similar to the map in the constrained zoom example. You can zoom into the states and drag across the country, navigating to states outside the current svg size
You can do this by constraining the translation coordinates you set to the size of the box:
var t = d3.event.translate,
s = d3.event.scale;
t[0] = Math.max(0, Math.min(t[0], width - s*50));
t[1] = Math.max(0, Math.min(t[1], height - s*50));
svg.attr("transform", "translate(" + t + ")scale(" + d3.event.scale + ")");
This is constraining the x coordinate to be between 0 and the width minus however much space is required to show the box completely -- this depends on the zoom level and the term therefore contains s. For the y coordinate, it is exactly the same.
This is much easier if you don't use both a translation and explicit coordinate settings through x and y for the box -- to offset from the top left corner, simply set an initial translation.
Complete example here.
please , see following image, here you can see blue rectangle is custom shape bounds and custom shape is shoe , i want to find area of a portion written in image and i want that area in form of rectangle
do is there any path iterator concept ?
Note
custom shape i derived from image of the same size.
I would do it like this:
1.create table for all bounding box-rect perimeter lines
each value in it will represent the empty space length form border line to shape
something like this:
the values are found by simple image scanning until first non space color found
2.now bruteforce find the biggest rectangle area
x,y = top left corner
for xs = 1 to bounding box width
now scan the max valid height of rectangle from x to x + xs (x grows to the right)
// it should be the min y0[x..x+xs]
remember the biggest valid area/size combination
do this for all 4 combinations (star from the other corners)
I now Brute-force is slow but
you can divide perimeter lines not by pixels but with some step instead
also I am sure this can be optimized somehow
for example by derivation of perimeter find the extremes and check from them backwards
when the size will start shrinking then stop ...
of course take in mind that on complicated shapes this optimization will not work ...
I have a system that requires moving an image on the screen. I am currently using a png and just placing it at the desired screen coordinates.
Because of a combination of the screen resolution and the required frame rate, some frames are identical because the image has not yet moved a full pixel. Unfortunately, the resolution of the screen is not negotiable.
I have a general understanding of how sub-pixel rendering works to smooth out edges but I have been unable to find a resource (if it exists) as to how I can use shading to translate an image by less than a single pixel.
Ideally, this would be usable with any image but if it was only possible with a simple shape like a circle or a ring, that would also be acceptable.
Sub-pixel interpolation is relatively simple. Typically you apply what amounts to an all-pass filter with a constant phase shift, where the phase shift corresponds to the required sub-pixel image shift. Depending on the required image quality you might use e.g. a 5 point Lanczos or other windowed sinc function and then apply this in one or both axes depending on whether you want an X shift or a Y shift or both.
E.g. for a 0.5 pixel shift the coefficients might be [ 0.06645, 0.18965, 0.27713, 0.27713, 0.18965 ]. (Note that the coefficients are normalised, i.e. their sum is equal to 1.0.)
To generate a horizontal shift you would convolve these coefficients with the pixels from x - 2 to x + 2, e.g.
const float kCoeffs[5] = { 0.06645f, 0.18965f, 0.27713f, 0.27713f, 0.18965f };
for (y = 0; y < height; ++y) // for each row
for (x = 2; x < width - 2; ++x) // for each col (apart from 2 pixel border)
{
float p = 0.0f; // convolve pixel with Lanczos coeffs
for (dx = -2; dx <= 2; ++dx)
p += in[y][x + dx] * kCoeffs[dx + 2];
out[y][x] = p; // store interpolated pixel
}
Conceptually, the operation is very simple. First you scale up the image (using any method of interpolation, as you like), then you translate the result, and finally you subsample down to the original image size.
The scale factor depends on the precision of sub-pixel translation you want to do. If you want to translate by 0.5 degrees, you need scale up the original image by a factor of 2 then you translate the resulting image by 1 pixel; if you want to translate by 0.25 degrees, you need to scale up by a factor of 4, and so on.
Note that this implementation is not efficient because when you scale up you end up calculating pixel values that you won't actually use because they're just dropped when you subsample back to the original image size. The implementation in Paul's answer is more efficient.
I'm trying to implement image convolution with a 3x3 matrix, where my colour components (each ranging from 0 to 255) are stored using pre-multiplied alpha. All the tutorials (e.g. http://www.codeproject.com/KB/GDI-plus/csharpfilters.aspx) I can find only describe performing the convolution calculations on the RGB components and nothing is mentioned about the alpha component.
My current code leaves the alpha component as it is. The filters I have tried look fine when working on images where every pixel already has full alpha set. When I have partially transparent pixels e.g. a boxblur filter looks strange because pixel colors do not propagate into transparent areas when blurring happens.
What calculations do I perform on the alpha component when running the convolution algorithm and how do I deal with pre-multiplied alphas when setting the final pixel value? Also, do I add the filter offset to the alpha component?
I've tried calculating my new alpha component the same way I calculate the RGB components (i.e. adding up the surrounding alpha values for that pixel according to the filter matrix) but I get colored fringes appearing on the edge of transparent areas and semi-transparent pixels start to darken too much. I think I need to change the new RGB components to take into account the new alpha value but I'm not sure what to do.
Thanks.
I think that the correct way is to first compute just the alpha of the convolution using the standard formulas
alpha = a1*m1 + a2*m2 + a3*m3 +
a4*m4 + a5*m5 + a6*m6 +
a7*m7 + a8*m8 + a9*m9;
then you must compute the convolution of the original (non-premultiplied) r/g/b and post-multiply by alpha
red = (r1/a1*m1 + r2/a2*m2 + r3/a3*m3 +
r4/a4*m4 + r5/a5*m5 + r6/a6*m6 +
r7/a7*m7 + r8/a8*m8 + r9/a9*m9) * alpha;
with a similar formula for green and blue.
A more efficient way would be first removing premultiplication (i.e. replacing r with r/a, g with g/a and b with b/a) doing the convolution of all components using standard formulas and then re-premultiply (replacing r with r*a, g with g*a and b with b*a).