| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- <!--
- Copyright (c) 2006-2023, RT-Thread Development Team
- SPDX-License-Identifier: Apache-2.0
- Change Logs:
- Date Author Notes
- 2023-02-25 GuEe-GUI the first version
- -->
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="shortcut icon" href="https://www.rt-thread.org/favicon.ico" type="image/x-icon">
- <title>Logo PPM Previews</title>
- <style type="text/css">
- body {
- min-width: 860px;
- margin: 0px;
- padding: 0px;
- font-family: Consolas, "Cascadia Code", Monaco;
- background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjxzdmcgd2lkdGg9IjEwIiBoZWlnaHQ9IjEwIiB2aWV3Qm94PSIwIDAgMTAgMTAiIGlkPSJjb2RlLWJhY2tncm91bmQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPg0KICAgIDx0aXRsZT5jb2RlLWJhY2tncm91bmQ8L3RpdGxlPg0KICAgIDxnPg0KICAgICAgICA8bGluZSB5Mj0iMTAiIHgyPSIxMCIgeTE9IjAiIHgxPSIxMCIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiNlNWU1ZTUiLz4NCiAgICAgICAgPGxpbmUgeTI9IjEwIiB4Mj0iMTAiIHkxPSIxMCIgeDE9IjAiIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjZTVlNWU1Ii8+DQogICAgPC9nPg0KPC9zdmc+);
- }
- .main {
- display: flex;
- justify-content: center;
- }
- .controls > div {
- padding: 10px;
- height: 52px;
- line-height: 52px;
- }
- label {
- user-select: none;
- font-size: 24px;
- font-weight: 400;
- color: #494949;
- }
- .res-input, .ppm-input, #background-color {
- cursor: pointer;
- border: 2px solid #494949;
- border-radius: 8px;
- outline: none;
- font-size: 18px;
- background-color: #fff;
- }
- .res-input {
- height: 32px;
- padding: 0 4px;
- line-height: 52px;
- }
- .background-color, .ppm-input {
- display: block;
- text-align: center;
- }
- #background-color {
- width: 20%;
- height: 32px;
- }
- .ppm-input:hover {
- background-color: #eee;
- }
- #ppm-input {
- display: none;
- }
- .canvas {
- justify-content: center;
- display: flex;
- margin-top: 20px;
- }
- </style>
- </head>
- <body>
- <div class="main">
- <div>
- <div class="controls">
- <div style="display: flex; justify-content: center;">
- <div>
- <label class="resolution">Screen Resolution</label>
- <input type="number" class="res-input" id="canvas-width" placeholder="width" min="1" step="1">
- <label class="resolution">×</label>
- <input type="number" class="res-input" id="canvas-height" placeholder="height" min="1" step="1">
- </div>
- </div>
- <div>
- <label class="background-color" for="background-color">
- <span>Background Color</span>
- <input type="color" id="background-color">
- </label>
- </div>
- <div>
- <label class="ppm-input">
- <input type="file" id="ppm-input" accept=".ppm" placeholder="PPM">
- <span>Open PPM File</span>
- </label>
- </div>
- </div>
- <div class="canvas">
- <canvas id="canvas"></canvas>
- </div>
- </div>
- </div>
- </body>
- <script type="text/javascript">
- var Screen = new Object;
- window.onload = function() {
- Screen.canvas = document.getElementById('canvas');
- Screen.ctx = canvas.getContext('2d');
- Screen.ppmWidth = 0;
- Screen.ppmHeight = 0;
- Screen.ppmPixels = [];
- Screen.widthInput = document.getElementById('canvas-width');
- Screen.heightInput = document.getElementById('canvas-height');
- Screen.ColorPicker = document.getElementById('background-color');
- Screen.widthInput.value = 1;
- Screen.heightInput.value = 1;
- Screen.ColorPicker.value = "#000000";
- document.getElementById('canvas-width').addEventListener('input', function(e) {
- applyCanvasSize();
- });
- document.getElementById('canvas-height').addEventListener('input', function(e) {
- applyCanvasSize();
- });
- document.getElementById('background-color').addEventListener('input', function(e) {
- applyBackgroundColor();
- });
- document.getElementById('ppm-input').addEventListener('change', function(e) {
- const file = e.target.files[0];
- if (!file) {
- return;
- }
- const reader = new FileReader();
- reader.onload = function(e) {
- const ppm_data = e.target.result;
- const { width, height, pixels } = parsePPM(ppm_data);
- Screen.ppmWidth = width;
- Screen.ppmHeight = height;
- Screen.ppmPixels = pixels;
- Screen.ctx.reset();
- applyBackgroundColor();
- };
- reader.readAsText(file);
- });
- function parsePPM(data) {
- let cursor = 0;
- const lines = data.split('\n').filter(line => !line.startsWith('#') && line.trim() !== '');
- const magic = lines[cursor++].trim();
- if (!['P1', 'P2', 'P3'].includes(magic)) {
- alert('Unsupported format');
- return;
- }
- let maxVal = 1;
- const [width, height] = lines[cursor++].split(/\s+/).map(Number);
- if (magic !== 'P1') {
- maxVal = parseInt(lines[cursor++]);
- }
- const pixels = [];
- const values = lines.slice(cursor).join(' ').split(/\s+/).filter(v => v !== '');
- if (magic === 'P1' || magic === 'P2') {
- for (var i = 0; i < values.length; ++i) {
- const val = parseInt(values[i]);
- const scaled = magic === 'P1' ? val * 255 : Math.round((val / maxVal) * 255);
- pixels.push([scaled, scaled, scaled]);
- }
- } else if (magic === 'P3') {
- for (var i = 0; i < values.length; i += 3) {
- const r = Math.round((values[i] / maxVal) * 255);
- const g = Math.round((values[i+1] / maxVal) * 255);
- const b = Math.round((values[i+2] / maxVal) * 255);
- pixels.push([r, g, b]);
- }
- }
- return { width, height, pixels };
- }
- function renderPPM() {
- if (Screen.ppmWidth == 0 || Screen.ppmHeight == 0) {
- return;
- }
- const imageData = Screen.ctx.createImageData(Screen.ppmWidth, Screen.ppmHeight);
- for (var i = 0; i < Screen.ppmPixels.length; ++i) {
- const [r, g, b] = Screen.ppmPixels[i];
- const j = i * 4;
- imageData.data[j] = r;
- imageData.data[j + 1] = g;
- imageData.data[j + 2] = b;
- imageData.data[j + 3] = 255;
- }
- const offsetX = (Screen.canvas.width - Screen.ppmWidth) / 2;
- const offsetY = (Screen.canvas.height - Screen.ppmHeight) / 2;
- Screen.ctx.putImageData(imageData, offsetX, offsetY);
- }
- function applyCanvasSize() {
- var canvasWidth = parseInt(Screen.widthInput.value);
- var canvasHeight = parseInt(Screen.heightInput.value);
- if (canvasWidth == 0 || canvasHeight == 0) {
- return;
- }
- Screen.canvas.width = canvasWidth;
- Screen.canvas.height = canvasHeight;
- Screen.canvas.style.boxShadow = "1px 1px 2px rgba(0, 0, 0, 0.2)";
- applyBackgroundColor();
- }
- function applyBackgroundColor() {
- Screen.ctx.fillStyle = Screen.ColorPicker.value;
- Screen.ctx.fillRect(0, 0, Screen.canvas.width, Screen.canvas.height);
- renderPPM();
- }
- }
- </script>
- </html>
|