Support Svg images as background for WinUI3 renderer (#8911)
* Initial commit for supporting svg background images * Fixes for svg images as url and data * Add Rasterize size of svg image on background thread * Call TileControl::LoadImageBrush once svg size is calculated on background thread * Addressed comments * Support for svg xml in the data scheme for background images * Addressed comments * Handle base64 svg data scheme for background image and add sample payload * Updated IsSvgImage check and addressed comments * Clean up code * Updated IsSvgImage check
This commit is contained in:
Родитель
31bbb89420
Коммит
cb729fce1d
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.6",
|
||||
"backgroundImage": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MDAiICBoZWlnaHQ9IjI5NC40IiB2aWV3Qm94PSIwIDAgNzAwLjAwMDAxIDI5NC40MjI1OCI+IAo8c3R5bGU+CiAgCiAgLnRlc3QgewogICAgYW5pbWF0aW9uOiBmYWRlIDNzIGluZmluaXRlIGFsdGVybmF0ZTsgCiAgICAKICB9CiAgCiAgQGtleWZyYW1lcyBmYWRlIHsKICAgIAogICAgZnJvbSB7CiAgICAgIG9wYWNpdHk6IDAKICAgIH0KICAgIAogICAgdG8gewogICAgICAKICAgICAgb3BhY2l0eToxCiAgICB9CiAgICAKICB9CiAgCiAgPC9zdHlsZT4KICAKICA8cGF0aCBjbGFzcz0idGVzdCIgZD0iTTYwMi4yIDEyOC42Yy0xMS43IDIuNy00Mi42IDQuMi00Mi42IDQuMmwtMy44IDEyLjJzMTUuMy0xLjMgMjYuNS0uMmMwIDAgMy42LS4zIDQgNCAuMiA0LjQtLjMgOS0uMyA5cy0uMyAyLjctNCAzLjRjLTQuMy43LTMzLjMgMi0zMy4zIDJMNTQ0IDE3OXMtMS43IDMuNiAyLjIgMi42YzMuNi0xIDM0LTYuOCAzOC02IDQuMiAxIDkgNi44IDcuNiAxMi0xLjYgNi4zLTMyIDI1LjctNTAuNCAyNC40IDAgMC05LjcuNi0xNy44LTEyLjUtNy44LTEyLjUgMi43LTM2IDIuNy0zNnMtNC43LTExLTEuMi0xNWMwIDAgMi0xLjcgOC0yLjJsNy41LTE1LjRzLTguNS41LTEzLjUtNS43Yy00LjYtNi01LTguNi0xLjQtMTAuMiAzLjgtMiAzOS04LjMgNjMuMi03LjUgMCAwIDguNS0xIDE2IDEzLjcgMCAwIDMuNCA2LTIuNiA3LjRNNTExIDE4Ny44Yy0zIDcuMy0xMS4zIDE1LTIxLjMgMTAuMy0xMC4yLTQuOC0yNi4zLTM3LjYtMjYuMy0zNy42cy02LTEyLjItNy4yLTExLjhjMCAwLTEuMy0yLjQtMiAxMS0xIDEzLjMuMiAzOS4yLTUuMyA0My4zLTUgNC0xMSAyLjMtMTQuNC0yLjQtMi44LTQuNy00LTE2LTIuNC0zNS43IDEuOC0xOS43IDYuMy00MC43IDEyLTQ3LjIgNi02LjYgMTAuOC0xLjggMTIuNiAwIDAgMCA3LjcgNyAyMC43IDI3LjdsMi4yIDMuOHMxMS44IDE5LjcgMTMgMTkuNmMwIDAgMSAxIDEuOC4yIDEuMi0uMy44LTYuNy44LTYuN1M0OTMgMTQxIDQ4MiAxMDVjMCAwLTEuNi00LjYtLjUtOSAxLTQgNS4zLTIgNS4zLTJzMTYuNiA4IDI0LjcgMzVjOCAyNyAyLjYgNTEuNS0uNCA1OC44TTQyOS42IDExOC41Yy0xLjYgMi44LTIuMyA2LjctOS4yIDcuOCAwIDAtNjcgNC43LTcwLjMgOS40IDAgMC0yLjIgMi44IDEuNCAzLjUgMy44LjggMTkgMi44IDI2LjIgMy4yIDcuOCAwIDM0IC4yIDQzLjYgMTIgMCAwIDUuNSA1LjYgNS4zIDE4LjMtLjIgMTMtMi41IDE3LjYtNy42IDIyLjMtNS4zIDQuNC01MC43IDI0LjgtODAtNi40IDAgMC0xMy40LTE1IDQuNy0yNi40IDAgMCAxMy04IDQ2LjMgMS4zIDAgMCAxMCAzLjYgOS42IDcuMy0uNiA0LTguMyA4LTE5LjUgNy44LTEwLjgtLjMtMTguOC01LjUtMTcuMi00LjYgMS41LjUtMTEuNy02LjQtMTUuOC0xLjctNCA0LjQtMyA3IDEgOS43IDEwIDUuOCA0OS4zIDMuNyA2MS05LjQgMCAwIDQuNy01LjMtMi40LTkuNi03LTQtMjcuNC02LjUtMzUuMy02LjgtNy41LS40LTM1LjYgMC0zOS44LTcuMyAwIDAtNC01LjIuNC0xOS40IDQuNi0xNSAzNy4zLTIwLjggNTEuNS0yMiAwIDAgMzktMS42IDQ2LjMgNi40IDAgMCAxIDEuOC0uMiA0LjVNMzE5IDIwNi40Yy00LjcgMy41LTE0LjcgMi0xNy42LTItMi44LTMuNS0zLjgtMTcuMy0zLjMtMzkgLjctMjIuMiAxLTQ5LjQgNi01My44IDUtNC4zIDgtLjUgMTAgMi40IDIgMyA0LjYgNi4zIDUgMTMuMi42IDcgMi4zIDQzIDIuMyA0M3MyLjIgMzIuOC0yLjMgMzYuMk0zMjkgODkuNGMtMTMuOCA0LjctMjMuMiAzLjItMzEuMi0uMy0zLjUgNi4zLTUuNiA4LjItOC4yIDguNi00IC40LTcuNS02LTgtOC0uOC0xLjUtMi43LTQuMi0uNC0xMC4zLTcuOC03LTguNC0xNi40LTctMjIuNyAxLjgtNy40IDE1LTM1LjIgNTUtMzguNSAwIDAgMTkuNi0xLjQgMjMgOWguNnMxOSAwIDE4LjYgMTdjMCAxNy0yMSAzOC4yLTQyLjQgNDUuNW0xNy44LTQ4LjdjLTEyLjYgMi0zMiAxOC44LTQxLjMgMzIuNyAxNC4zIDIuNiAzOS4zIDEuNiA1MC41LTIxIDAgMCA1LjMtMTQuMi05LjItMTEuN20tNTUuMyAxMWMtNCA2LjUtNC4yIDEwLjQtMi4zIDEzIDQuNy03IDEzLTE4IDI1LjUtMjYuNi05LjYgMS0xNy43IDUtMjMuMiAxMy42TTYzMi4yIDIwNS43Yy05LjIgMjIuNi0xNyA0NS41LTIxLjUgNzkuOCAwIDAtMSA2LjctNi41IDQuNS01LjUtMi0xNC41LTExLTE2LjUtMjMuNy0yLTE2LjYgNS40LTQ0LjYgMjAuNS03Ni44LTQuNC03LTcuNS0xNy40LTUtMzIgMCAwIDQtMjcgMzEtNTEuNCAwIDAgMy4yLTIuNyA1LTEuOCAyLjIgMSAxLjMgOS42LS41IDE0LTEuNiA0LjItMTMuNiAyNS0xMy42IDI1cy03LjUgMTQuMi01LjQgMjUuM2MxNC4yLTIxLjggNDYuNS02NiA2Ni41LTUyIDEyLjcgOSAxMi43IDM4IDMuMiA1NC44LTcuNSAxMy4zLTI4LjcgNDAuOC01NyAzNC40bTQxLjYtNjhjLTcuNCA4LTIwLjYgMjMuMi0zMSA0My44IDExLTEuMiAyMS43LTcuMyAyNS0xMC40IDUuMy00LjcgMTcuNS0xNy40IDE1LjYtMzQuMiAwIDAtMS4yLTguOC05LjYuOE0yMjYgMjE3LjVjLTM1LjQgMTAuOC02OC44IDUuOC04NyAxLS41IDcuNC0xLjMgMTAuNS0yLjUgMTEuNy0xLjQgMS42LTEzIDguMi0xOS40LTEuMi0yLjgtNC41LTQuMi0xMi42LTUtMjAtNDEtMTguNi02MC00Ni02MC42LTQ3LTEtMS0xMC4zLTEwLjctMS0yMi43IDguNy0xMC44IDM3LjUtMjEuNyA2My4zLTI2IDEtMjIgMy40LTM5IDYuNS00Ni41IDMuNy05IDguNC0xIDEyLjYgNSAzLjQgNC41IDUuNSAyMy44IDUuNyAzOS4yIDE2LjgtLjggMjcgLjQgNDUuNyA0IDI0LjYgNC4yIDQxIDE2LjggMzkuNyAzMS0xLjIgMTQtMTQgMTkuOC0xOSAyMC4yLTUgLjQtMTMtMy4zLTEzLTMuMy01LjYtMi42LS41LTUgNi03LjggNy4yLTMuNSA1LjYtNyA1LjYtNy0yLjYtOC0zNC41LTEzLjMtNjYuMi0xMy4zIDAgMTcuNS43IDQ2LjUgMS4yIDYzLjQgMjIuMiA0LjIgMzguOCAzLjMgMzguOCAzLjNzODEtMi4zIDgzLjMtNTRjMi41LTUxLjgtODEtMTAxLjQtMTQyLjUtMTE3QzU2LjggMTQuNCAyMiAyNS44IDE5IDI3LjNjLTMuMyAxLjYtLjMgMi4yLS4zIDIuMlMyMiAzMCAyOCAzMmM2IDIgMS4yIDUgMS4yIDVDMTguNyA0MC42IDcgMzguNSA0LjcgMzMuN2MtMi4zLTQuNyAxLjUtOSA2LTE1LjMgNC4yLTYuNSA5LTYuMyA5LTYuMyA3Ni0yNi41IDE2OC44IDIxIDE2OC44IDIxIDg2LjggNDMuOCAxMDEuNiA5NS4zIDEwMCAxMTUuMy0xLjQgMTkuNy05IDUzLTYyLjUgNjkuMk01OSAxNDZjLTguNiA0LTIuNiAxMC40LTIuNiAxMC40IDE2LjIgMTcuMyAzNiAyOC4yIDU1IDM1IDIuMi0zMCAyLTQwLjcgMi01NS44Qzg0IDEzNy42IDY3IDE0Mi40IDU5IDE0NiIvPiA8L3N2Zz4=",
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "This card must have a background image parsed from a dataUri",
|
||||
"wrap": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.6",
|
||||
"backgroundImage": {
|
||||
"url": "https://adaptivecards.io/content/adaptive-card.svg",
|
||||
"verticalAlignment": "center",
|
||||
"horizontalAlignment": "center"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in body"
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 1 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 2 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 3 in Container"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.6",
|
||||
"backgroundImage": {
|
||||
"url": "https://adaptivecards.io/content/adaptive-card.svg",
|
||||
"fillMode": "repeat"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in body"
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 1 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 2 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 3 in Container"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.6",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "repeatHorizontally",
|
||||
"verticalAlignment": "center"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in body"
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 1 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 2 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 3 in Container"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.6",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "repeatVertically",
|
||||
"horizontalAlignment": "center"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in body"
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 1 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 2 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 3 in Container"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.6",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "repeat"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in body"
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 1 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 2 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 3 in Container"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.6",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "repeatHorizontally",
|
||||
"verticalAlignment": "center"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in body"
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"width": "auto",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text in Column 2"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 1 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 2 in Container"
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Text 3 in Container"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
{
|
||||
"type": "AdaptiveCard",
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"version": "1.6",
|
||||
"body": [
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"width": "auto"
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"verticalAlignment": "Center"
|
||||
},
|
||||
"width": "stretch"
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"width": "auto"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "You can even repeat the background image..."
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "Repeat"
|
||||
},
|
||||
"width": "stretch"
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"horizontalAlignment": "Center",
|
||||
"verticalContentAlignment": "Center",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"horizontalAlignment": "Center",
|
||||
"text": "Those are some neat arrows",
|
||||
"wrap": true
|
||||
}
|
||||
],
|
||||
"width": "stretch"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Horizontal repeat..."
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatHorizontally"
|
||||
},
|
||||
"width": "stretch"
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatHorizontally",
|
||||
"verticalAlignment": "Center"
|
||||
},
|
||||
"width": "stretch"
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatHorizontally",
|
||||
"verticalAlignment": "Bottom"
|
||||
},
|
||||
"width": "stretch"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "Vertical repeat..."
|
||||
},
|
||||
{
|
||||
"type": "ColumnSet",
|
||||
"columns": [
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatVertically"
|
||||
},
|
||||
"width": "stretch"
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatVertically",
|
||||
"horizontalAlignment": "Center"
|
||||
},
|
||||
"width": "stretch"
|
||||
},
|
||||
{
|
||||
"type": "Column",
|
||||
"minHeight": "50px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatVertically",
|
||||
"horizontalAlignment": "Right"
|
||||
},
|
||||
"width": "stretch"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"type": "AdaptiveCard",
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"version": "1.6",
|
||||
"body": [
|
||||
{
|
||||
"type": "Container",
|
||||
"minHeight": "150px",
|
||||
"backgroundImage": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"items": [
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "What a beautiful background"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "TextBlock",
|
||||
"text": "They can even repeat a bunch of different ways..."
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"minHeight": "100px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "Repeat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatHorizontally",
|
||||
"verticalAlignment": "Center"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Container",
|
||||
"minHeight": "100px",
|
||||
"backgroundImage": {
|
||||
"url": "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg",
|
||||
"fillMode": "RepeatVertically",
|
||||
"horizontalAlignment": "Center"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -36,15 +36,6 @@ namespace winrt::AdaptiveCards::Rendering::Xaml_Rendering::implementation
|
|||
|
||||
namespace AdaptiveCards::Rendering::Xaml_Rendering
|
||||
{
|
||||
auto inline GetDispatcher(winrt::ImageSource const &imageSource)
|
||||
{
|
||||
#ifdef USE_WINUI3
|
||||
return imageSource.DispatcherQueue();
|
||||
#else
|
||||
return imageSource.Dispatcher();
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT! Methods below here are actually XamlBuilder methods. They're defined here because they're only used
|
||||
|
@ -71,7 +62,7 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto isImageSvg = IsSvgImage(HStringToUTF8(url));
|
||||
auto isImageSvg = IsSvgImage(imageUrl);
|
||||
|
||||
uint32_t pixelWidth = adaptiveImage.PixelWidth();
|
||||
uint32_t pixelHeight = adaptiveImage.PixelHeight();
|
||||
|
@ -289,57 +280,6 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering
|
|||
adaptiveCardElement, selectAction, renderContext, frameworkElement, XamlHelpers::SupportsInteractivity(hostConfig), true);
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromXmlString(winrt::hstring const& content)
|
||||
{
|
||||
// Parse the size from the XamlDocument as XML
|
||||
winrt::XmlDocument xmlDoc;
|
||||
|
||||
xmlDoc.LoadXml(content);
|
||||
|
||||
if (xmlDoc)
|
||||
{
|
||||
auto rootElement = xmlDoc.DocumentElement();
|
||||
|
||||
// Root element must be an SVG
|
||||
if (rootElement.NodeName() == L"svg")
|
||||
{
|
||||
auto heightAttribute = rootElement.GetAttribute(L"height");
|
||||
auto widthAttribute = rootElement.GetAttribute(L"width");
|
||||
|
||||
double height{0.0};
|
||||
double width{0.0};
|
||||
|
||||
if (!heightAttribute.empty())
|
||||
{
|
||||
height = TryHStringToDouble(heightAttribute).value_or(0.0);
|
||||
}
|
||||
|
||||
if (!widthAttribute.empty())
|
||||
{
|
||||
width = TryHStringToDouble(widthAttribute).value_or(0.0);
|
||||
}
|
||||
|
||||
return {static_cast<float>(width), static_cast<float>(height)};
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
winrt::IAsyncOperation<winrt::Windows::Foundation::Size> XamlBuilder::ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream)
|
||||
{
|
||||
auto inputStream = stream.GetInputStreamAt(0);
|
||||
auto dataReader = winrt::DataReader(inputStream);
|
||||
|
||||
// Load the data from the stream
|
||||
uint32_t numBytesLoaded = co_await dataReader.LoadAsync(static_cast<uint32_t>(stream.Size()));
|
||||
|
||||
// Read the data as a string
|
||||
winrt::hstring svgString = dataReader.ReadString(numBytesLoaded);
|
||||
|
||||
co_return ParseSizeOfSVGImageFromXmlString(svgString);
|
||||
}
|
||||
|
||||
winrt::IAsyncOperation<winrt::IRandomAccessStream> XamlBuilder::ResolveToStreamAsync(winrt::Uri const imageUrl,
|
||||
winrt::AdaptiveCardResourceResolvers const resolvers, bool const isImageSvg)
|
||||
{
|
||||
|
@ -689,13 +629,6 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering
|
|||
}
|
||||
}
|
||||
|
||||
boolean XamlBuilder::IsSvgImage(std::string url)
|
||||
{
|
||||
// Question: is this check sufficient?
|
||||
auto foundSvg = url.find("svg");
|
||||
return !(foundSvg == std::string::npos);
|
||||
}
|
||||
|
||||
void XamlBuilder::SetRasterizedPixelHeight(winrt::ImageSource const& imageSource, double const& imageSize) {
|
||||
if (auto image = imageSource.try_as<winrt::SvgImageSource>())
|
||||
{
|
||||
|
|
|
@ -32,6 +32,25 @@ namespace winrt::AdaptiveCards::Rendering::Xaml_Rendering::implementation
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileControl::SvgImageOpened(const IInspectable& /* sender */, const winrt::SvgImageSourceOpenedEventArgs& /* args */)
|
||||
{
|
||||
auto uiElement = m_resolvedImage;
|
||||
|
||||
// Do we need to throw/log if we fail here?
|
||||
if (const auto image = m_resolvedImage.try_as<winrt::Image>())
|
||||
{
|
||||
if (const auto imageSource = image.Source())
|
||||
{
|
||||
if (const auto svgImageSource = imageSource.try_as<winrt::SvgImageSource>())
|
||||
{
|
||||
m_imageSize = {(float)svgImageSource.RasterizePixelWidth(), (float)svgImageSource.RasterizePixelHeight()};
|
||||
RefreshContainerTile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileControl::LoadImageBrush(winrt::UIElement const& uielement)
|
||||
{
|
||||
m_resolvedImage = uielement;
|
||||
|
@ -46,6 +65,12 @@ namespace winrt::AdaptiveCards::Rendering::Xaml_Rendering::implementation
|
|||
m_imageOpenedRevoker = bitmapImage.ImageOpened(winrt::auto_revoke, {this, &TileControl::ImageOpened});
|
||||
m_brushXaml.ImageSource(imageSource);
|
||||
}
|
||||
else if (const auto svgImageSource = imageSource.try_as<winrt::SvgImageSource>())
|
||||
{
|
||||
m_svgImageOpenedRevoker.revoke();
|
||||
m_svgImageOpenedRevoker = svgImageSource.Opened(winrt::auto_revoke, {this, &TileControl::SvgImageOpened});
|
||||
m_brushXaml.ImageSource(imageSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace winrt::AdaptiveCards::Rendering::Xaml_Rendering::implementation
|
|||
private:
|
||||
void RefreshContainerTile();
|
||||
void ImageOpened(const IInspectable& sender, const winrt::RoutedEventArgs& args);
|
||||
void SvgImageOpened(const IInspectable& sender, const winrt::SvgImageSourceOpenedEventArgs& args);
|
||||
|
||||
// Fields
|
||||
/* winrt::FrameworkElement m_rootElement;*/
|
||||
|
@ -48,6 +49,7 @@ namespace winrt::AdaptiveCards::Rendering::Xaml_Rendering::implementation
|
|||
|
||||
// Revokers
|
||||
winrt::BitmapImage::ImageOpened_revoker m_imageOpenedRevoker;
|
||||
winrt::SvgImageSource::Opened_revoker m_svgImageOpenedRevoker;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -657,3 +657,71 @@ std::string ExtractSvgDataFromUri(winrt::Windows::Foundation::Uri const& imageUr
|
|||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
winrt::Windows::Foundation::Size ParseSizeOfSVGImageFromXmlString(winrt::hstring const& content)
|
||||
{
|
||||
// Parse the size from the XamlDocument as XML
|
||||
winrt::XmlDocument xmlDoc;
|
||||
|
||||
xmlDoc.LoadXml(content);
|
||||
|
||||
if (xmlDoc)
|
||||
{
|
||||
auto rootElement = xmlDoc.DocumentElement();
|
||||
|
||||
// Root element must be an SVG
|
||||
if (rootElement.NodeName() == L"svg")
|
||||
{
|
||||
auto heightAttribute = rootElement.GetAttribute(L"height");
|
||||
auto widthAttribute = rootElement.GetAttribute(L"width");
|
||||
|
||||
double height{0.0};
|
||||
double width{0.0};
|
||||
|
||||
if (!heightAttribute.empty())
|
||||
{
|
||||
height = TryHStringToDouble(heightAttribute).value_or(0.0);
|
||||
}
|
||||
|
||||
if (!widthAttribute.empty())
|
||||
{
|
||||
width = TryHStringToDouble(widthAttribute).value_or(0.0);
|
||||
}
|
||||
|
||||
return {static_cast<float>(width), static_cast<float>(height)};
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
winrt::IAsyncOperation<winrt::Windows::Foundation::Size> ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream)
|
||||
{
|
||||
auto inputStream = stream.GetInputStreamAt(0);
|
||||
auto dataReader = winrt::DataReader(inputStream);
|
||||
|
||||
// Load the data from the stream
|
||||
uint32_t numBytesLoaded = co_await dataReader.LoadAsync(static_cast<uint32_t>(stream.Size()));
|
||||
|
||||
// Read the data as a string
|
||||
winrt::hstring svgString = dataReader.ReadString(numBytesLoaded);
|
||||
|
||||
co_return ParseSizeOfSVGImageFromXmlString(svgString);
|
||||
}
|
||||
|
||||
bool IsSvgImage(winrt::Windows::Foundation::Uri const& imageUrl)
|
||||
{
|
||||
auto imagePath = HStringToUTF8(imageUrl.Path());
|
||||
|
||||
if (imageUrl.SchemeName() == L"data")
|
||||
{
|
||||
// Find the position of the first semicolon
|
||||
size_t semicolonPos = imagePath.find(';');
|
||||
|
||||
// Check if "svg" is present in the substring from the start to the semicolon
|
||||
return imagePath.substr(0, semicolonPos).find("svg") != std::string::npos;
|
||||
}
|
||||
|
||||
// Check if the file extension is ".svg"
|
||||
return imagePath.substr(imagePath.find_last_of('.') + 1) == "svg";
|
||||
}
|
||||
|
|
|
@ -225,3 +225,18 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering
|
|||
}
|
||||
|
||||
std::string ExtractSvgDataFromUri(winrt::Windows::Foundation::Uri const& imageUrl);
|
||||
|
||||
winrt::Windows::Foundation::Size ParseSizeOfSVGImageFromXmlString(winrt::hstring const& content);
|
||||
|
||||
winrt::IAsyncOperation<winrt::Windows::Foundation::Size> ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream);
|
||||
|
||||
bool IsSvgImage(winrt::Windows::Foundation::Uri const& imageUrl);
|
||||
|
||||
auto inline GetDispatcher(winrt::ImageSource const& imageSource)
|
||||
{
|
||||
#ifdef USE_WINUI3
|
||||
return imageSource.DispatcherQueue();
|
||||
#else
|
||||
return imageSource.Dispatcher();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -97,10 +97,6 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering
|
|||
|
||||
winrt::ImageSource CreateImageSource(bool isImageSvg);
|
||||
|
||||
winrt::Windows::Foundation::Size XamlBuilder::ParseSizeOfSVGImageFromXmlString(winrt::hstring const& content);
|
||||
|
||||
winrt::IAsyncOperation<winrt::Windows::Foundation::Size> XamlBuilder::ParseSizeOfSVGImageFromStreamAsync(winrt::IRandomAccessStream const stream);
|
||||
|
||||
winrt::IAsyncOperation<winrt::IRandomAccessStream> XamlBuilder::ResolveToStreamAsync(
|
||||
winrt::Uri const uri, winrt::AdaptiveCardResourceResolvers const resolvers, bool const isImageSvg);
|
||||
|
||||
|
@ -116,8 +112,6 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering
|
|||
winrt::ImageSource imageSource,
|
||||
ImageProperties<TElement> const properties);
|
||||
|
||||
boolean IsSvgImage(std::string url);
|
||||
|
||||
void FireAllImagesLoaded();
|
||||
void FireImagesLoadingHadError();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "TileControl.h"
|
||||
#include "AdaptiveBase64Util.h"
|
||||
#include "WholeItemsPanel.h"
|
||||
#include "Util.h"
|
||||
|
||||
namespace AdaptiveCards::Rendering::Xaml_Rendering::XamlHelpers
|
||||
{
|
||||
|
@ -242,17 +243,32 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering::XamlHelpers
|
|||
return content;
|
||||
}
|
||||
|
||||
winrt::Image CreateBackgroundImage(winrt::AdaptiveRenderContext const& renderContext, winrt::hstring const& url)
|
||||
winrt::Image CreateBackgroundImage(winrt::AdaptiveRenderContext const& renderContext,
|
||||
winrt::TileControl const& tileControl,
|
||||
bool IsSvg,
|
||||
winrt::Uri imageUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto imageUrl = GetUrlFromString(renderContext.HostConfig(), url);
|
||||
if (IsSvg)
|
||||
{
|
||||
winrt::SvgImageSource svgImageSource{};
|
||||
|
||||
ConfigureSvgImageSourceAsync(imageUrl, svgImageSource, tileControl);
|
||||
|
||||
winrt::Image backgroundImage;
|
||||
backgroundImage.Source(svgImageSource);
|
||||
|
||||
return backgroundImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (imageUrl.SchemeName() == L"data")
|
||||
{
|
||||
return RenderImageFromDataUri(imageUrl);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
winrt::BitmapImage bitmapImage{};
|
||||
bitmapImage.UriSource(imageUrl);
|
||||
|
||||
|
@ -261,6 +277,8 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering::XamlHelpers
|
|||
|
||||
return backgroundImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (winrt::hresult_error const& ex)
|
||||
{
|
||||
renderContext.AddWarning(winrt::WarningStatusCode::CustomWarning, ex.message() + L" Skipping rendering of background image.");
|
||||
|
@ -268,21 +286,93 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering::XamlHelpers
|
|||
}
|
||||
}
|
||||
|
||||
winrt::fire_and_forget ConfigureSvgImageSourceAsync(winrt::Uri imageUrl,
|
||||
winrt::SvgImageSource svgImageSource,
|
||||
winrt::TileControl tileControl)
|
||||
{
|
||||
auto weakImageSource{winrt::make_weak(svgImageSource)};
|
||||
auto weakTileControl{winrt::make_weak(tileControl)};
|
||||
|
||||
if (imageUrl.SchemeName() == L"data")
|
||||
{
|
||||
auto imagePath = HStringToUTF8(imageUrl.Path());
|
||||
auto foundBase64 = imagePath.find("base64");
|
||||
winrt::DataWriter dataWriter{winrt::InMemoryRandomAccessStream{}};
|
||||
|
||||
if (foundBase64 != std::string::npos)
|
||||
{
|
||||
// Decode base 64 string
|
||||
std::string data = AdaptiveBase64Util::ExtractDataFromUri(imagePath);
|
||||
std::vector<char> decodedData = AdaptiveBase64Util::Decode(data);
|
||||
dataWriter.WriteBytes(std::vector<byte>{decodedData.begin(), decodedData.end()});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string data = ExtractSvgDataFromUri(imageUrl);
|
||||
dataWriter.WriteBytes(std::vector<byte>{data.begin(), data.end()});
|
||||
}
|
||||
|
||||
co_await dataWriter.StoreAsync();
|
||||
if (auto strongImageSource = weakImageSource.get())
|
||||
{
|
||||
auto stream = dataWriter.DetachStream().try_as<winrt::InMemoryRandomAccessStream>();
|
||||
stream.Seek(0);
|
||||
auto sizeParseOp{ParseSizeOfSVGImageFromStreamAsync(stream)};
|
||||
co_await wil::resume_foreground(GetDispatcher(strongImageSource));
|
||||
auto size = co_await sizeParseOp;
|
||||
strongImageSource.RasterizePixelHeight(size.Height);
|
||||
strongImageSource.RasterizePixelWidth(size.Width);
|
||||
co_await strongImageSource.SetSourceAsync(stream);
|
||||
winrt::Image image;
|
||||
image.Source(strongImageSource);
|
||||
if (auto strongTileControl = weakTileControl.get())
|
||||
{
|
||||
strongTileControl.LoadImageBrush(image);
|
||||
}
|
||||
}
|
||||
co_return;
|
||||
}
|
||||
|
||||
winrt::HttpClient httpClient;
|
||||
auto getOperation = co_await httpClient.GetAsync(imageUrl);
|
||||
auto readOperation = co_await getOperation.Content().ReadAsStringAsync();
|
||||
auto size{ParseSizeOfSVGImageFromXmlString(readOperation)};
|
||||
|
||||
if (auto strongImageSource = weakImageSource.get())
|
||||
{
|
||||
co_await wil::resume_foreground(GetDispatcher(strongImageSource));
|
||||
strongImageSource.RasterizePixelHeight(size.Height);
|
||||
strongImageSource.RasterizePixelWidth(size.Width);
|
||||
winrt::Image image;
|
||||
image.Source(strongImageSource);
|
||||
strongImageSource.UriSource(imageUrl);
|
||||
if (auto strongTileControl = weakTileControl.get())
|
||||
{
|
||||
strongTileControl.LoadImageBrush(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyBackgroundToRoot(winrt::Panel const& rootPanel,
|
||||
winrt::AdaptiveBackgroundImage const& adaptiveBackgroundImage,
|
||||
winrt::AdaptiveRenderContext const& renderContext)
|
||||
{
|
||||
// In order to reuse the image creation code paths, we simply create an adaptive card
|
||||
// image element and then build that into xaml and apply to the root.
|
||||
if (const auto backgroundImage = CreateBackgroundImage(renderContext, adaptiveBackgroundImage.Url()))
|
||||
{
|
||||
// Creates the background image for all fill modes
|
||||
auto tileControl = winrt::make<winrt::implementation::TileControl>();
|
||||
auto imageUrl = GetUrlFromString(renderContext.HostConfig(), adaptiveBackgroundImage.Url());
|
||||
bool IsSvg = IsSvgImage(imageUrl);
|
||||
|
||||
// In order to reuse the image creation code paths, we simply create an adaptive card
|
||||
// image element and then build that into xaml and apply to the root.
|
||||
if (const auto backgroundImage = CreateBackgroundImage(renderContext, tileControl, IsSvg, imageUrl))
|
||||
{
|
||||
// Set IsEnabled to false to avoid generating a tab stop for the background image tile control
|
||||
tileControl.IsEnabled(false);
|
||||
tileControl.BackgroundImage(adaptiveBackgroundImage);
|
||||
if (!IsSvg)
|
||||
{
|
||||
tileControl.LoadImageBrush(backgroundImage);
|
||||
}
|
||||
|
||||
XamlHelpers::AppendXamlElementToPanel(tileControl, rootPanel);
|
||||
|
||||
|
|
|
@ -197,4 +197,8 @@ namespace AdaptiveCards::Rendering::Xaml_Rendering::XamlHelpers
|
|||
SeparatorParemeters GetSeparatorParameters(winrt::IAdaptiveCardElement const& element, winrt::AdaptiveHostConfig const& hostConfig);
|
||||
|
||||
winrt::Image RenderImageFromDataUri(winrt::Uri const& imageUrl);
|
||||
|
||||
winrt::fire_and_forget ConfigureSvgImageSourceAsync(winrt::Uri imageUrl,
|
||||
winrt::SvgImageSource svgImageSource,
|
||||
winrt::TileControl tileControl);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче