Closed ngaurav closed 1 year ago
If you'd like you can submit a PR and @erickok will review it, since you already have created a solution. It definitely seems like a great feature! :)
To support vertical-align styling beyond just the use case here, maybe we could use transform? I'd have to read up on what this css property does exactly on the web.
Transform works, but the issue is that when you shift the image by some pixels, the line height of the widget does not change. This leads to overlap of two lines as shown below
Oh yeah that's an issue then. Okay we have to take a good look. I saw your commits and they look promising, but I hope to find something beyond just support for this css property for just inline svg images.
I understand that it seems like a corner use-case. But, we can look at it like a general support for vertical-align inline style. It will work on all kinds of images (SVG, PNG) and also can be helpful when mixing fonts. Some people mix symbols with text on the same line, and they expect it to be aligned. https://stackoverflow.com/questions/62371976/align-text-baseline-with-text-inside-a-column-using-flutter https://stackoverflow.com/questions/56592377/align-icon-by-baseline-in-stack
And, some people just want to shift the text alignment. https://stackoverflow.com/questions/56170779/base-align-text-and-dashed-line-in-flutter https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align
If image alignment is implemented, then whatever people can convert every complex html attribute into SVG and use it with this library.
@ngaurav I tried to replicate your setup but its not working for me, the image still renders in the middle of the text. Any ideas?
@tneotia , For me it is working with BaselineBox class Refer to https://gitlab.com/nishant.gaurav/flutter_html/-/tree/dev. This is a hack, where I am adding a depth attribute to SVGContentElement. But the text is getting rendered properly. Here is a sample Html
"<p>What is the remainder when <img class='latex-inline math' style='vertical-align:-0.105206pt' alt='' id='c3130ab88ff1525' src='data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48IS0tIFRoaXMgZmlsZSB3YXMgZ2VuZXJhdGVkIGJ5IGR2aXN2Z20gMi44LjEgLS0+PHN2ZyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZycgeG1sbnM6eGxpbms9J2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsnIHdpZHRoPScxNi43NjM3MThwdCcgaGVpZ2h0PScxMy42NjIyNjZwdCcgdmlld0JveD0nMCAtMTMuNTU3NDUzIDE2Ljc2MzcxOCAxMy42NjIyNjYnPjxkZWZzPjxwYXRoIGlkPSdnMi01MCcgZD0nTS42NzE3NTctLjM3NjM3NUMxLjcyNDY1NC0xLjIxNDg4IDIuMzAxMTI2LTEuNzUzMjM5IDIuMzAxMTI2LTIuMzUzNTMzQzIuMzAxMTI2LTIuODkxODkyIDEuOTI0NzUyLTMuMjUzOTc0IDEuMzEwMTY1LTMuMjUzOTc0Qy43MTk0LTMuMjUzOTc0IC4zMDAxNDctMi45MTU3MTMgLjMwMDE0Ny0yLjU4MjIxNkMuMzAwMTQ3LTIuNDIwMjMyIC40MDAxOTYtMi4zMTU0MTkgLjU2Njk0NC0yLjMxNTQxOUMuNjQzMTcyLTIuMzE1NDE5IC43MTQ2MzUtMi4zMzkyNCAuNzgxMzM1LTIuMzg2ODgzVi0yLjg5NjY1NkMuOTI0MjYyLTIuOTc3NjQ4IDEuMDYyNDI1LTMuMDEwOTk4IDEuMjA1MzUyLTMuMDEwOTk4QzEuNjAwNzg0LTMuMDEwOTk4IDEuODM4OTk1LTIuNzQ0MiAxLjgzODk5NS0yLjI5MTU5OEMxLjgzODk5NS0xLjY2NzQ4MyAxLjI0MzQ2Ni0xLjE0ODE4MSAuMjAwMDk4LS4zMDAxNDdWMEgyLjQwNTk0Vi0uNzgxMzM1SDIuMTkxNTQ5TDIuMTA1NzkzLS4zNzYzNzVILjY3MTc1N1onLz48cGF0aCBpZD0nZzItNTEnIGQ9J00xLjUxMDI2My0xLjY4MTc3NkMxLjk3NzE1OC0xLjgxNTE3NCAyLjIyMDEzNC0yLjA4NjczNiAyLjIyMDEzNC0yLjQ1MzU4MkMyLjIyMDEzNC0yLjkzNDc3IDEuODUzMjg4LTMuMjUzOTc0IDEuMjgxNTgtMy4yNTM5NzRDLjY4NjA1LTMuMjUzOTc0IC4yNzYzMjYtMi45MzQ3NyAuMjc2MzI2LTIuNjIwMzNDLjI3NjMyNi0yLjQ2Nzg3NSAuMzgxMTM5LTIuMzYzMDYxIC41MzM1OTUtMi4zNjMwNjFDLjYwOTgyMi0yLjM2MzA2MSAuNjcxNzU3LTIuMzgyMTE4IC43Mjg5MjgtMi40MjQ5OTZWLTIuODcyODM1Qy44NjcwOTEtMi45NjgxMTkgMS4wMTQ3ODItMy4wMTA5OTggMS4xODE1MzEtMy4wMTA5OThDMS41NDgzNzctMy4wMTA5OTggMS43ODY1ODktMi43NjgwMjEgMS43ODY1ODktMi4zOTE2NDdDMS43ODY1ODktMi4wMDU3NDQgMS41MjkzMi0xLjc3NzA2IDEuMDQ4MTMyLTEuNzc3MDZDMS4wMTQ3ODItMS43NzcwNiAuOTgxNDMzLTEuNzgxODI1IC45NDgwODMtMS43ODE4MjVWLTEuNTAwNzM1QzEuMDM4NjA0LTEuNTE1MDI3IDEuMTI0MzYtMS41MTk3OTEgMS4yMDA1ODgtMS41MTk3OTFDMS42NTc5NTQtMS41MTk3OTEgMS45MDU2OTUtMS4zMDA2MzcgMS45MDU2OTUtLjkyNDI2MkMxLjkwNTY5NS0uNTAwMjQ1IDEuNTkxMjU1LS4xNzE1MTMgMS4xNTc3MS0uMTcxNTEzQzEuMDE0NzgyLS4xNzE1MTMgLjg4MTM4NC0uMjA5NjI2IC43NTI3NDktLjI4NTg1NEwuNjA1MDU4LS42OTA4MTRDLjU1MjY1MS0uNzA5ODcxIC41MDUwMDktLjcxNDYzNSAuNDYyMTMxLS43MTQ2MzVDLjMwOTY3NS0uNzE0NjM1IC4xOTUzMzQtLjYwOTgyMiAuMTk1MzM0LS40NzE2NTlDLjE5NTMzNC0uMjI4NjgzIC41NzE3MDggLjA1MjQwNyAxLjEzODY1MyAuMDUyNDA3QzEuODcyMzQ1IC4wNTI0MDcgMi4zNDQwMDQtLjM4MTEzOSAyLjM0NDAwNC0uOTE0NzMzQzIuMzQ0MDA0LTEuMzQ4Mjc5IDIuMDM5MDkzLTEuNjQzNjYyIDEuNTEwMjYzLTEuNjgxNzc2WicvPjx1c2UgaWQ9J2c1LTUwJyB4bGluazpocmVmPScjZzItNTAnIHRyYW5zZm9ybT0nc2NhbGUoMS40KScvPjx1c2UgaWQ9J2c4LTUxJyB4bGluazpocmVmPScjZzItNTEnIHRyYW5zZm9ybT0nc2NhbGUoMiknLz48L2RlZnM+PGcgaWQ9J3BhZ2UxJz48dXNlIHg9JzAnIHk9JzAnIHhsaW5rOmhyZWY9JyNnOC01MScvPjx1c2UgeD0nNS4zMTc2OTYnIHk9Jy0zLjgxNjEwMycgeGxpbms6aHJlZj0nI2c1LTUwJy8+PHVzZSB4PSc5LjA0MDA4MycgeT0nLTYuNDg3Mzc2JyB4bGluazpocmVmPScjZzItNTAnLz48dXNlIHg9JzExLjY5ODkzJyB5PSctOC4zOTU0MjgnIHhsaW5rOmhyZWY9JyNnMi01MCcvPjx1c2UgeD0nMTQuMzU3Nzc4JyB5PSctMTAuMzAzNDc5JyB4bGluazpocmVmPScjZzItNTAnLz48L2c+PC9zdmc+'> is divided by 10?</p>"
@ngaurav I tried your branch (I had to update the dependencies bc of conflicts) and the SVG does not show up, is there code I am missing?
@tneotia Actually the SVG is showing up. I had used a color filter which was making SVGs white for dark backgrounds. I have updated the branch now. It should be visible.
Yes it works now and I identified why my implementation wasn't working. Something interesting:
Using alignment: PlaceholderAlignment.aboveBaseline,
aligns your SVG perfectly without needing any vertical align, but then manually setting the baseline appears to do nothing.
Only when using alignment: PlaceholderAlignment.baseline,
, setting vertical-align will actually do something - but vertical-align 0 appears to align the top of the element with the baseline, rather than the bottom.
Now this brings up a dilemma - I can try and use alignment: PlaceholderAlignment.baseline,
, but for that we would have to compensate for the height of the element so that the bottom of the element is aligned with the baseline.
Edit: Also intrinsics aren't available for PlaceholderAlignment.baseline, PlaceholderAlignment.aboveBaseline, or PlaceholderAlignment.belowBaseline
, so this breaks any HTML with tables in it.
@tneotia alignment: PlaceholderAlignment.aboveBaseline
will always align the entire widget above baseline. In the example given by me, the ideal rendering should paint everything above baseline. Therefore, it was appearing perfect. If you have fraction term to render, where the denominator is usually rendered below the baseline, then alignment: PlaceholderAlignment.aboveBaseline
will not help.
And I understand the dilemma, that flutter asks us to specify the baseline from the top, and therefore we must know the intrinsic height. I do not have a good understanding of intrinsics. But I found this link which uses intrinsics – https://github.com/flutter/flutter/issues/65895. Their code is very similar to the BaselineBox class in my branch of flutter_svg.
Another idea could be to try getting the baseline from child and then shifting it in BaselineBox Class:
double computeDistanceToActualBaseline(TextBaseline baselineType) {
return _baseline + child!.computeDistanceToActualBaseline(baselineType)! ;
}
EDIT: This allow _baseline to just have the vertical-align, while in previous case _baseline will be sum of height and vertical-align.
Closing as duplicate of #481. Follow that issue for updates.
I am storing text with some latex code for math part. Using python markdown extensions that text can be converted into html, which is mostly text but the latex is rendered as SVG in tag. To match the baseline of image with the text, there is a vertical-align attribute. Flutter_html currently ignores inline vertical-align attributes for img tag. To suit my requirements, I have created a hacky fork of flutter_html = which uses a class called BaselineBox to define a baseline for its child (SvgContentElement class). If this sounds like a worthy feature for flutter_html, then please implement it. Here is a sample html node, which can be used as a test case.
<p>If <img class="latex-inline math" style="vertical-align:-0.353876pt" alt="" id="4b09cb9bb985eb9" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48IS0tIFRoaXMgZmlsZSB3YXMgZ2VuZXJhdGVkIGJ5IGR2aXN2Z20gMi44LjEgLS0+PHN2ZyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZycgeG1sbnM6eGxpbms9J2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsnIHdpZHRoPScyMC4wODkxNTVwdCcgaGVpZ2h0PScxMS4yOTIwODNwdCcgdmlld0JveD0nMCAtMTAuOTM5NTMgMjAuMDg5MTU1IDExLjI5MjA4Myc+PGRlZnM+PHBhdGggaWQ9J2cyLTQ2JyBkPSdNLjY2MjIyOS0uNTYyMThDLjQ5NTQ4MS0uNTYyMTggLjM1NzMxOC0uNDI4NzgxIC4zNTczMTgtLjI1NzI2OVMuNDk1NDgxIC4wNDI4NzggLjY2MjIyOSAuMDQyODc4Uy45NjIzNzYtLjA5MDUyIC45NjIzNzYtLjI1NzI2OUMuOTYyMzc2LS40Mjg3ODEgLjgyODk3Ny0uNTYyMTggLjY2MjIyOS0uNTYyMThaJy8+PHBhdGggaWQ9J2cyLTU1JyBkPSdNLjMzODI2MS0zLjE5NjgwM1YtMi40MDExNzVILjU2MjE4TC42Mzg0MDgtMi44MzQ3MjFIMi4xMDU3OTNMLjU1MjY1MSAuMTc2Mjc3SC45NDgwODNWLjA3MTQ2NEwyLjUyOTgxLTMuMDA2MjMzVi0zLjE5NjgwM0guMzM4MjYxWicvPjxwYXRoIGlkPSdnMS00OScgZD0nTTMuMTY4MjE3LTEuNjQ4NDI2QzIuNzU4NDkzLTIuMTE1MzIxIDIuMjgyMDY5LTIuNTQ0MTAyIDEuNjY3NDgzLTIuNTQ0MTAyQy45MDk5NjktMi41NDQxMDIgLjUzMzU5NS0xLjk1ODEwMSAuNTMzNTk1LTEuMzcyMVMuOTA5OTY5LS4yMDQ4NjIgMS42Njc0ODMtLjIwNDg2MkMyLjI1ODI0OC0uMjA0ODYyIDIuNzEwODUxLS42MjQxMTUgMy4wOTE5OS0xLjA5NTc3NEMzLjUwNjQ3OC0uNjI4ODc5IDMuOTgyOTAyLS4yMDQ4NjIgNC41OTI3MjQtLjIwNDg2MkM1LjM1MDIzOC0uMjA0ODYyIDUuNzMxMzc3LS43ODYwOTkgNS43MzEzNzctMS4zNzIxUzUuMzUwMjM4LTIuNTQ0MTAyIDQuNTkyNzI0LTIuNTQ0MTAyQzQuMDAxOTU5LTIuNTQ0MTAyIDMuNTQ5MzU2LTIuMTIwMDg1IDMuMTY4MjE3LTEuNjQ4NDI2Wk0zLjM1ODc4Ny0xLjQzNDAzNUMzLjY4NzUxOS0xLjg1MzI4OCA0LjA2ODY1OC0yLjI1ODI0OCA0LjU5MjcyNC0yLjI1ODI0OEM1LjA1MDA5MS0yLjI1ODI0OCA1LjQxMjE3My0xLjg4NjYzOCA1LjQxMjE3My0xLjQzODc5OUM1LjQxMjE3My0xLjQxOTc0MyA1LjQxMjE3My0xLjM5NTkyMSA1LjQwNzQwOS0xLjM3MjFDNS4zNzQwNTktLjk1Mjg0NyA1LjAxNjc0MS0uNjMzNjQzIDQuNTkyNzI0LS42MzM2NDNDNC4wNzgxODctLjYzMzY0MyAzLjY5NzA0OC0xLjAzMzgzOSAzLjM1ODc4Ny0xLjQzNDAzNVpNMi45MDYxODQtMS4zMTAxNjVDMi41NzI2ODgtLjg5MDkxMiAyLjE5MTU0OS0uNDkwNzE2IDEuNjY3NDgzLS40OTA3MTZDMS4yMTQ4OC0uNDkwNzE2IC44NDgwMzQtLjg1NzU2MyAuODQ4MDM0LTEuMzA1NDAxQy44NDgwMzQtMS4zMjQ0NTggLjg1Mjc5OC0xLjM0ODI3OSAuODUyNzk4LTEuMzcyMUMuODg2MTQ4LTEuNzkxMzUzIDEuMjQzNDY2LTIuMTE1MzIxIDEuNjY3NDgzLTIuMTE1MzIxQzIuMTg2Nzg1LTIuMTE1MzIxIDIuNTY3OTI0LTEuNzEwMzYxIDIuOTA2MTg0LTEuMzEwMTY1WicvPjx1c2UgaWQ9J2c2LTQ2JyB4bGluazpocmVmPScjZzItNDYnLz48dXNlIGlkPSdnOS01NScgeGxpbms6aHJlZj0nI2cyLTU1Jy8+PHVzZSBpZD0nZzEyLTU1JyB4bGluazpocmVmPScjZzItNTUnIHRyYW5zZm9ybT0nc2NhbGUoMS40KScvPjx1c2UgaWQ9J2cxNS01NScgeGxpbms6aHJlZj0nI2cyLTU1JyB0cmFuc2Zvcm09J3NjYWxlKDIpJy8+PC9kZWZzPjxnIGlkPSdwYWdlMSc+PHVzZSB4PScwJyB5PScwJyB4bGluazpocmVmPScjZzE1LTU1Jy8+PHVzZSB4PSc1LjMxNzY5NicgeT0nLTMuODE2MTAzJyB4bGluazpocmVmPScjZzEyLTU1Jy8+PHVzZSB4PSc5LjA0MDA4MycgeT0nLTYuNDg3Mzc2JyB4bGluazpocmVmPScjZzktNTUnLz48dXNlIHg9JzExLjY5ODkzJyB5PSctOC4zOTU0MjgnIHhsaW5rOmhyZWY9JyNnNi00NicvPjx1c2UgeD0nMTMuMDI4MzU0JyB5PSctOC4zOTU0MjgnIHhsaW5rOmhyZWY9JyNnNi00NicvPjx1c2UgeD0nMTQuMzU3Nzc4JyB5PSctOC4zOTU0MjgnIHhsaW5rOmhyZWY9JyNnMS00OScvPjwvZz48L3N2Zz4="> is divided by 5 what will be the remainder?</p>