xref: /aosp_15_r20/external/deqp/scripts/qpa_image_viewer.html (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker<!--
2*35238bceSAndroid Build Coastguard Worker--------------------------------------
3*35238bceSAndroid Build Coastguard WorkerHTML QPA Image Viewer
4*35238bceSAndroid Build Coastguard Worker--------------------------------------
5*35238bceSAndroid Build Coastguard Worker
6*35238bceSAndroid Build Coastguard WorkerCopyright (c) 2020 The Khronos Group Inc.
7*35238bceSAndroid Build Coastguard WorkerCopyright (c) 2020 Valve Corporation.
8*35238bceSAndroid Build Coastguard Worker
9*35238bceSAndroid Build Coastguard WorkerLicensed under the Apache License, Version 2.0 (the "License");
10*35238bceSAndroid Build Coastguard Workeryou may not use this file except in compliance with the License.
11*35238bceSAndroid Build Coastguard WorkerYou may obtain a copy of the License at
12*35238bceSAndroid Build Coastguard Worker
13*35238bceSAndroid Build Coastguard Workerhttp://www.apache.org/licenses/LICENSE-2.0
14*35238bceSAndroid Build Coastguard Worker
15*35238bceSAndroid Build Coastguard WorkerUnless required by applicable law or agreed to in writing, software
16*35238bceSAndroid Build Coastguard Workerdistributed under the License is distributed on an "AS IS" BASIS,
17*35238bceSAndroid Build Coastguard WorkerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18*35238bceSAndroid Build Coastguard WorkerSee the License for the specific language governing permissions and
19*35238bceSAndroid Build Coastguard Workerlimitations under the License.
20*35238bceSAndroid Build Coastguard Worker-->
21*35238bceSAndroid Build Coastguard Worker<html>
22*35238bceSAndroid Build Coastguard Worker    <head>
23*35238bceSAndroid Build Coastguard Worker        <meta charset="utf-8"/>
24*35238bceSAndroid Build Coastguard Worker        <title>Load PNGs from QPA output</title>
25*35238bceSAndroid Build Coastguard Worker        <style>
26*35238bceSAndroid Build Coastguard Worker            body {
27*35238bceSAndroid Build Coastguard Worker                background: white;
28*35238bceSAndroid Build Coastguard Worker                text-align: left;
29*35238bceSAndroid Build Coastguard Worker                font-family: sans-serif;
30*35238bceSAndroid Build Coastguard Worker            }
31*35238bceSAndroid Build Coastguard Worker            h1 {
32*35238bceSAndroid Build Coastguard Worker                margin-top: 2ex;
33*35238bceSAndroid Build Coastguard Worker            }
34*35238bceSAndroid Build Coastguard Worker            h2 {
35*35238bceSAndroid Build Coastguard Worker                font-size: large;
36*35238bceSAndroid Build Coastguard Worker            }
37*35238bceSAndroid Build Coastguard Worker            figure {
38*35238bceSAndroid Build Coastguard Worker                display: flex;
39*35238bceSAndroid Build Coastguard Worker                flex-direction: column;
40*35238bceSAndroid Build Coastguard Worker            }
41*35238bceSAndroid Build Coastguard Worker            img {
42*35238bceSAndroid Build Coastguard Worker                margin-right: 1ex;
43*35238bceSAndroid Build Coastguard Worker                margin-bottom: 1ex;
44*35238bceSAndroid Build Coastguard Worker                /* Attempt to zoom images using the nearest-neighbor scaling
45*35238bceSAndroid Build Coastguard Worker                algorithm. */
46*35238bceSAndroid Build Coastguard Worker                image-rendering: pixelated;
47*35238bceSAndroid Build Coastguard Worker                image-rendering: crisp-edges;
48*35238bceSAndroid Build Coastguard Worker                /* Use a black background color for images in case some pixels
49*35238bceSAndroid Build Coastguard Worker                are transparent to some degree. In the worst case, the image
50*35238bceSAndroid Build Coastguard Worker                could appear to be missing. */
51*35238bceSAndroid Build Coastguard Worker                background: black;
52*35238bceSAndroid Build Coastguard Worker            }
53*35238bceSAndroid Build Coastguard Worker            button {
54*35238bceSAndroid Build Coastguard Worker                margin: 1ex;
55*35238bceSAndroid Build Coastguard Worker                border: none;
56*35238bceSAndroid Build Coastguard Worker                border-radius: .5ex;
57*35238bceSAndroid Build Coastguard Worker                padding: 1ex;
58*35238bceSAndroid Build Coastguard Worker                background-color: steelblue;
59*35238bceSAndroid Build Coastguard Worker                color: white;
60*35238bceSAndroid Build Coastguard Worker                font-size: large;
61*35238bceSAndroid Build Coastguard Worker            }
62*35238bceSAndroid Build Coastguard Worker            button:hover {
63*35238bceSAndroid Build Coastguard Worker                opacity: .8;
64*35238bceSAndroid Build Coastguard Worker            }
65*35238bceSAndroid Build Coastguard Worker            #clearimagesbutton,#cleartextbutton {
66*35238bceSAndroid Build Coastguard Worker                background-color: seagreen;
67*35238bceSAndroid Build Coastguard Worker            }
68*35238bceSAndroid Build Coastguard Worker            select {
69*35238bceSAndroid Build Coastguard Worker                font-size: large;
70*35238bceSAndroid Build Coastguard Worker                padding: 1ex;
71*35238bceSAndroid Build Coastguard Worker                border-radius: .5ex;
72*35238bceSAndroid Build Coastguard Worker                border: 1px solid darkgrey;
73*35238bceSAndroid Build Coastguard Worker            }
74*35238bceSAndroid Build Coastguard Worker            select:hover {
75*35238bceSAndroid Build Coastguard Worker                opacity: .8;
76*35238bceSAndroid Build Coastguard Worker            }
77*35238bceSAndroid Build Coastguard Worker            .loadoption {
78*35238bceSAndroid Build Coastguard Worker                text-align: center;
79*35238bceSAndroid Build Coastguard Worker                margin: 1ex;
80*35238bceSAndroid Build Coastguard Worker                padding: 2ex;
81*35238bceSAndroid Build Coastguard Worker                border: 1px solid darkgrey;
82*35238bceSAndroid Build Coastguard Worker                border-radius: 1ex;
83*35238bceSAndroid Build Coastguard Worker            }
84*35238bceSAndroid Build Coastguard Worker            #options {
85*35238bceSAndroid Build Coastguard Worker                display: flex;
86*35238bceSAndroid Build Coastguard Worker                flex-wrap: wrap;
87*35238bceSAndroid Build Coastguard Worker            }
88*35238bceSAndroid Build Coastguard Worker            #qpatext {
89*35238bceSAndroid Build Coastguard Worker                display: block;
90*35238bceSAndroid Build Coastguard Worker                min-width: 80ex;
91*35238bceSAndroid Build Coastguard Worker                max-width: 132ex;
92*35238bceSAndroid Build Coastguard Worker                min-height: 25ex;
93*35238bceSAndroid Build Coastguard Worker                max-height: 25ex;
94*35238bceSAndroid Build Coastguard Worker                margin: 1ex auto;
95*35238bceSAndroid Build Coastguard Worker            }
96*35238bceSAndroid Build Coastguard Worker            #fileselector {
97*35238bceSAndroid Build Coastguard Worker                display: none;
98*35238bceSAndroid Build Coastguard Worker            }
99*35238bceSAndroid Build Coastguard Worker            #zoomandclear {
100*35238bceSAndroid Build Coastguard Worker                margin: 2ex;
101*35238bceSAndroid Build Coastguard Worker            }
102*35238bceSAndroid Build Coastguard Worker            #images {
103*35238bceSAndroid Build Coastguard Worker                margin: 2ex;
104*35238bceSAndroid Build Coastguard Worker                display: flex;
105*35238bceSAndroid Build Coastguard Worker                flex-direction: column;
106*35238bceSAndroid Build Coastguard Worker            }
107*35238bceSAndroid Build Coastguard Worker            .imagesblock {
108*35238bceSAndroid Build Coastguard Worker                display: flex;
109*35238bceSAndroid Build Coastguard Worker                flex-wrap: wrap;
110*35238bceSAndroid Build Coastguard Worker            }
111*35238bceSAndroid Build Coastguard Worker        </style>
112*35238bceSAndroid Build Coastguard Worker    </head>
113*35238bceSAndroid Build Coastguard Worker    <body>
114*35238bceSAndroid Build Coastguard Worker        <h1>Load PNGs from QPA output</h1>
115*35238bceSAndroid Build Coastguard Worker
116*35238bceSAndroid Build Coastguard Worker        <div id="options">
117*35238bceSAndroid Build Coastguard Worker            <div class="loadoption">
118*35238bceSAndroid Build Coastguard Worker                <h2>Option 1: Load local QPA files</h2>
119*35238bceSAndroid Build Coastguard Worker                <!-- The file selector text cannot be changed, so we use a hidden selector trick. -->
120*35238bceSAndroid Build Coastguard Worker                <button id="fileselectorbutton">&#x1F4C2; Load files</button>
121*35238bceSAndroid Build Coastguard Worker                <input id="fileselector" type="file" multiple>
122*35238bceSAndroid Build Coastguard Worker            </div>
123*35238bceSAndroid Build Coastguard Worker
124*35238bceSAndroid Build Coastguard Worker            <div class="loadoption">
125*35238bceSAndroid Build Coastguard Worker                <h2>Option 2: Paste QPA text or text extract containing &lt;Image&gt; elements below and click "Load images"</h2>
126*35238bceSAndroid Build Coastguard Worker                <textarea id="qpatext"></textarea>
127*35238bceSAndroid Build Coastguard Worker                <button id="loadimagesbutton">&#x1F4C3; Load images</button>
128*35238bceSAndroid Build Coastguard Worker                <button id="cleartextbutton">&#x267B; Clear text</button>
129*35238bceSAndroid Build Coastguard Worker            </div>
130*35238bceSAndroid Build Coastguard Worker        </div>
131*35238bceSAndroid Build Coastguard Worker
132*35238bceSAndroid Build Coastguard Worker        <div id="zoomandclear">
133*35238bceSAndroid Build Coastguard Worker            &#x1F50E; Image zoom
134*35238bceSAndroid Build Coastguard Worker            <select id="zoomselect">
135*35238bceSAndroid Build Coastguard Worker                <option value="1" selected>1x</option>
136*35238bceSAndroid Build Coastguard Worker                <option value="2">2x</option>
137*35238bceSAndroid Build Coastguard Worker                <option value="4">4x</option>
138*35238bceSAndroid Build Coastguard Worker                <option value="8">8x</option>
139*35238bceSAndroid Build Coastguard Worker                <option value="16">16x</option>
140*35238bceSAndroid Build Coastguard Worker                <option value="32">32x</option>
141*35238bceSAndroid Build Coastguard Worker            </select>
142*35238bceSAndroid Build Coastguard Worker            <button id="clearimagesbutton">&#x267B; Clear images</button>
143*35238bceSAndroid Build Coastguard Worker        </div>
144*35238bceSAndroid Build Coastguard Worker
145*35238bceSAndroid Build Coastguard Worker        <div id="images"></div>
146*35238bceSAndroid Build Coastguard Worker
147*35238bceSAndroid Build Coastguard Worker        <script>
148*35238bceSAndroid Build Coastguard Worker            // Returns zoom factor as a number.
149*35238bceSAndroid Build Coastguard Worker            var getSelectedZoom = function () {
150*35238bceSAndroid Build Coastguard Worker                return new Number(document.getElementById("zoomselect").value);
151*35238bceSAndroid Build Coastguard Worker            }
152*35238bceSAndroid Build Coastguard Worker
153*35238bceSAndroid Build Coastguard Worker            // Scales a given image with the selected zoom factor.
154*35238bceSAndroid Build Coastguard Worker            var scaleSingleImage = function (img) {
155*35238bceSAndroid Build Coastguard Worker                var factor = getSelectedZoom();
156*35238bceSAndroid Build Coastguard Worker                img.style.width = (img.naturalWidth * factor) + "px";
157*35238bceSAndroid Build Coastguard Worker                img.style.height = (img.naturalHeight * factor) + "px";
158*35238bceSAndroid Build Coastguard Worker            }
159*35238bceSAndroid Build Coastguard Worker
160*35238bceSAndroid Build Coastguard Worker            // Rescales all <img> elements in the page. Used after changing the selected zoom.
161*35238bceSAndroid Build Coastguard Worker            var rescaleImages = function () {
162*35238bceSAndroid Build Coastguard Worker                var imageList = document.getElementsByTagName("img");
163*35238bceSAndroid Build Coastguard Worker                for (var i = 0; i < imageList.length; i++) {
164*35238bceSAndroid Build Coastguard Worker                    scaleSingleImage(imageList[i])
165*35238bceSAndroid Build Coastguard Worker                }
166*35238bceSAndroid Build Coastguard Worker            }
167*35238bceSAndroid Build Coastguard Worker
168*35238bceSAndroid Build Coastguard Worker            // Removes everything contained in the images <div>.
169*35238bceSAndroid Build Coastguard Worker            var clearImages = function () {
170*35238bceSAndroid Build Coastguard Worker                var imagesNode = document.getElementById("images");
171*35238bceSAndroid Build Coastguard Worker                while (imagesNode.hasChildNodes()) {
172*35238bceSAndroid Build Coastguard Worker                    imagesNode.removeChild(imagesNode.lastChild);
173*35238bceSAndroid Build Coastguard Worker                }
174*35238bceSAndroid Build Coastguard Worker            }
175*35238bceSAndroid Build Coastguard Worker
176*35238bceSAndroid Build Coastguard Worker            // Clears textarea text.
177*35238bceSAndroid Build Coastguard Worker            var clearText = function() {
178*35238bceSAndroid Build Coastguard Worker                document.getElementById("qpatext").value = "";
179*35238bceSAndroid Build Coastguard Worker            }
180*35238bceSAndroid Build Coastguard Worker
181*35238bceSAndroid Build Coastguard Worker            // Returns a properly sized image with the given base64-encoded PNG data.
182*35238bceSAndroid Build Coastguard Worker            var createImage = function (pngData, imageName) {
183*35238bceSAndroid Build Coastguard Worker                var imageContainer = document.createElement("figure");
184*35238bceSAndroid Build Coastguard Worker                if (imageName.length > 0) {
185*35238bceSAndroid Build Coastguard Worker                    var newFileNameHeader = document.createElement("figcaption");
186*35238bceSAndroid Build Coastguard Worker                    newFileNameHeader.textContent = escape(imageName);
187*35238bceSAndroid Build Coastguard Worker                    imageContainer.appendChild(newFileNameHeader);
188*35238bceSAndroid Build Coastguard Worker                }
189*35238bceSAndroid Build Coastguard Worker                var newImage = document.createElement("img");
190*35238bceSAndroid Build Coastguard Worker                newImage.src = "data:image/png;base64," + pngData;
191*35238bceSAndroid Build Coastguard Worker                newImage.onload = (function () {
192*35238bceSAndroid Build Coastguard Worker                    // Grab the image for the callback. We need to wait until
193*35238bceSAndroid Build Coastguard Worker                    // the image has been properly loaded to access its
194*35238bceSAndroid Build Coastguard Worker                    // naturalWidth and naturalHeight properties, needed for
195*35238bceSAndroid Build Coastguard Worker                    // scaling.
196*35238bceSAndroid Build Coastguard Worker                    var cbImage = newImage;
197*35238bceSAndroid Build Coastguard Worker                    return function () {
198*35238bceSAndroid Build Coastguard Worker                        scaleSingleImage(cbImage);
199*35238bceSAndroid Build Coastguard Worker                    };
200*35238bceSAndroid Build Coastguard Worker                })();
201*35238bceSAndroid Build Coastguard Worker                imageContainer.appendChild(newImage);
202*35238bceSAndroid Build Coastguard Worker                return imageContainer;
203*35238bceSAndroid Build Coastguard Worker            }
204*35238bceSAndroid Build Coastguard Worker
205*35238bceSAndroid Build Coastguard Worker            // Returns a new h3 header with the given file name.
206*35238bceSAndroid Build Coastguard Worker            var createFileNameHeader = function (fileName) {
207*35238bceSAndroid Build Coastguard Worker                var newHeader = document.createElement("h3");
208*35238bceSAndroid Build Coastguard Worker                newHeader.textContent = fileName;
209*35238bceSAndroid Build Coastguard Worker                return newHeader;
210*35238bceSAndroid Build Coastguard Worker            }
211*35238bceSAndroid Build Coastguard Worker
212*35238bceSAndroid Build Coastguard Worker            // Returns a new image block to contain images from a file.
213*35238bceSAndroid Build Coastguard Worker            var createImagesBlock = function () {
214*35238bceSAndroid Build Coastguard Worker                var imagesBlock = document.createElement("div");
215*35238bceSAndroid Build Coastguard Worker                imagesBlock.className = "imagesblock";
216*35238bceSAndroid Build Coastguard Worker                return imagesBlock;
217*35238bceSAndroid Build Coastguard Worker            }
218*35238bceSAndroid Build Coastguard Worker
219*35238bceSAndroid Build Coastguard Worker            // Processes a chunk of QPA text from the given file name. Creates
220*35238bceSAndroid Build Coastguard Worker            // the file name header and a list of images in the images <div>, as
221*35238bceSAndroid Build Coastguard Worker            // found in the text.
222*35238bceSAndroid Build Coastguard Worker            var processText = function(textString, fileName) {
223*35238bceSAndroid Build Coastguard Worker                var imagesNode = document.getElementById("images");
224*35238bceSAndroid Build Coastguard Worker                var newHeader = createFileNameHeader(fileName);
225*35238bceSAndroid Build Coastguard Worker                imagesNode.appendChild(newHeader);
226*35238bceSAndroid Build Coastguard Worker                var imagesBlock = createImagesBlock();
227*35238bceSAndroid Build Coastguard Worker                // [\s\S] is a match-anything regexp like the dot, except it
228*35238bceSAndroid Build Coastguard Worker                // also matches newlines. Ideally, browsers would need to widely
229*35238bceSAndroid Build Coastguard Worker                // support the "dotall" regexp modifier, but that's not the case
230*35238bceSAndroid Build Coastguard Worker                // yet and this does the trick.
231*35238bceSAndroid Build Coastguard Worker                // Group 1 are the image element properties, if any.
232*35238bceSAndroid Build Coastguard Worker                // Group 2 is the base64 PNG data.
233*35238bceSAndroid Build Coastguard Worker                var imageRegexp = /<Image\b(.*?)>([\s\S]*?)<\/Image>/g;
234*35238bceSAndroid Build Coastguard Worker                var imageNameRegexp = /\bName="(.*?)"/;
235*35238bceSAndroid Build Coastguard Worker                var result;
236*35238bceSAndroid Build Coastguard Worker                var innerResult;
237*35238bceSAndroid Build Coastguard Worker                var imageName;
238*35238bceSAndroid Build Coastguard Worker                while ((result = imageRegexp.exec(textString)) !== null) {
239*35238bceSAndroid Build Coastguard Worker                    innerResult = result[1].match(imageNameRegexp);
240*35238bceSAndroid Build Coastguard Worker                    imageName = ((innerResult !== null) ? innerResult[1] : "");
241*35238bceSAndroid Build Coastguard Worker                    // Blanks need to be removed from the base64 string.
242*35238bceSAndroid Build Coastguard Worker                    var pngData = result[2].replace(/\s+/g, "");
243*35238bceSAndroid Build Coastguard Worker                    imagesBlock.appendChild(createImage(pngData, imageName));
244*35238bceSAndroid Build Coastguard Worker                }
245*35238bceSAndroid Build Coastguard Worker                imagesNode.appendChild(imagesBlock);
246*35238bceSAndroid Build Coastguard Worker            }
247*35238bceSAndroid Build Coastguard Worker
248*35238bceSAndroid Build Coastguard Worker            // Loads images from the text in the text area.
249*35238bceSAndroid Build Coastguard Worker            var loadImages = function () {
250*35238bceSAndroid Build Coastguard Worker                processText(document.getElementById("qpatext").value, "<Pasted Text>");
251*35238bceSAndroid Build Coastguard Worker            }
252*35238bceSAndroid Build Coastguard Worker
253*35238bceSAndroid Build Coastguard Worker            // Loads images from the files in the file selector.
254*35238bceSAndroid Build Coastguard Worker            var handleFileSelect = function (evt) {
255*35238bceSAndroid Build Coastguard Worker                var files = evt.target.files;
256*35238bceSAndroid Build Coastguard Worker                for (var i = 0; i < files.length; i++) {
257*35238bceSAndroid Build Coastguard Worker                    // Creates a reader per file.
258*35238bceSAndroid Build Coastguard Worker                    var reader = new FileReader();
259*35238bceSAndroid Build Coastguard Worker                    // Grab the needed objects to use them after the file has
260*35238bceSAndroid Build Coastguard Worker                    // been read, in order to process its contents and add
261*35238bceSAndroid Build Coastguard Worker                    // images, if found, in the images <div>.
262*35238bceSAndroid Build Coastguard Worker                    reader.onload = (function () {
263*35238bceSAndroid Build Coastguard Worker                        var cbFileName = files[i].name;
264*35238bceSAndroid Build Coastguard Worker                        var cbReader = reader;
265*35238bceSAndroid Build Coastguard Worker                        return function () {
266*35238bceSAndroid Build Coastguard Worker                            processText(cbReader.result, cbFileName);
267*35238bceSAndroid Build Coastguard Worker                        };
268*35238bceSAndroid Build Coastguard Worker                    })();
269*35238bceSAndroid Build Coastguard Worker                    // Reads file contents. This will trigger the event above.
270*35238bceSAndroid Build Coastguard Worker                    reader.readAsText(files[i]);
271*35238bceSAndroid Build Coastguard Worker                }
272*35238bceSAndroid Build Coastguard Worker            }
273*35238bceSAndroid Build Coastguard Worker
274*35238bceSAndroid Build Coastguard Worker            // File selector trick: click on the selector when clicking on the
275*35238bceSAndroid Build Coastguard Worker            // custom button.
276*35238bceSAndroid Build Coastguard Worker            var clickFileSelector = function () {
277*35238bceSAndroid Build Coastguard Worker                document.getElementById("fileselector").click();
278*35238bceSAndroid Build Coastguard Worker            }
279*35238bceSAndroid Build Coastguard Worker
280*35238bceSAndroid Build Coastguard Worker            // Clears selected files to be able to select them again if needed.
281*35238bceSAndroid Build Coastguard Worker            var clearSelectedFiles = function() {
282*35238bceSAndroid Build Coastguard Worker                document.getElementById("fileselector").value = "";
283*35238bceSAndroid Build Coastguard Worker            }
284*35238bceSAndroid Build Coastguard Worker
285*35238bceSAndroid Build Coastguard Worker            // Set event handlers for interactive elements in the page.
286*35238bceSAndroid Build Coastguard Worker            document.getElementById("fileselector").onclick = clearSelectedFiles;
287*35238bceSAndroid Build Coastguard Worker            document.getElementById("fileselector").addEventListener("change", handleFileSelect, false);
288*35238bceSAndroid Build Coastguard Worker            document.getElementById("fileselectorbutton").onclick = clickFileSelector;
289*35238bceSAndroid Build Coastguard Worker            document.getElementById("loadimagesbutton").onclick = loadImages;
290*35238bceSAndroid Build Coastguard Worker            document.getElementById("cleartextbutton").onclick = clearText;
291*35238bceSAndroid Build Coastguard Worker            document.getElementById("zoomselect").onchange = rescaleImages;
292*35238bceSAndroid Build Coastguard Worker            document.getElementById("clearimagesbutton").onclick = clearImages;
293*35238bceSAndroid Build Coastguard Worker        </script>
294*35238bceSAndroid Build Coastguard Worker    </body>
295*35238bceSAndroid Build Coastguard Worker</html>
296