Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  color_quads.html   Sprache: HTML

 
 products/Sources/formale Sprachen/C/Firefox/dom/canvas/test/reftest/color_quads.html


<!DOCTYPE html>
<html class="reftest-wait">
  <!--
# color_quads.html

* The default is a 400x400 2d canvas, with 0, 16, 235, and 255 "gray" outer
  quads, and 50%-red, -green, -blue, and -gray inner quads.

* We default to showing the settings pane when loaded without a query string.
  This way, someone naively opens this in a browser, they can immediately see
  all available options.

* The "Publish" button updates the url, and so causes the settings pane to
  hide.

* Clicking on the canvas toggles the settings pane for further editing.
  -->

  <head>
    <meta charset="utf-8">
    <title>color_quads.html (2022-07-15)</title>
  </head>
  <body>
    <div id="e_settings">
      Image override: <input id="e_img" type="text">

      <br>
      <br>Canvas Width: <input id="e_width" type="text" value="400">
      <br>Canvas Height: <input id="e_height" type="text" value="400">
      <br>Canvas Colorspace: <input id="e_cspace" type="text">
      <br>Canvas Context Type: <select id="e_context">
        <option value="2d" selected="selected">Canvas2D</option>
        <option value="webgl">WebGL</option>
      </select>
      <br>Canvas Context Options: <input id="e_options" type="text" value="{}">

      <br>
      <br>OuterTopLeft: <input id="e_color_o1" type="text" value="rgb(0,0,0)">
      <br>OuterTopRight: <input id="e_color_o2" type="text" value="rgb(16,16,16)">
      <br>OuterBottomLeft: <input id="e_color_o3" type="text" value="rgb(235,235,235)">
      <br>OuterBottomRight: <input id="e_color_o4" type="text" value="rgb(255,255,255)">
      <br>
      <br>InnerTopLeft: <input id="e_color_i1" type="text" value="rgb(127,0,0)">
      <br>InnerTopRight: <input id="e_color_i2" type="text" value="rgb(0,127,0)">
      <br>InnerBottomLeft: <input id="e_color_i3" type="text" value="rgb(0,0,127)">
      <br>InnerBottomRight: <input id="e_color_i4" type="text" value="rgb(127,127,127)">
      <br><input id="e_publish" type="button" value="Publish">
      <hr>
    </div>
      <div id="e_canvas_holder">
        <canvas></canvas>
      </div>
    <script>
"use strict";

// document.body.style.backgroundColor = '#fdf';

// -

// Click the canvas to toggle the settings pane.
e_canvas_holder.addEventListener("click", () => {
  // Toggle display:none to hide/unhide.
  e_settings.style.display = e_settings.style.display ? "" : "none";
});

// Hide settings initially if there's a query string in the url.
if (window.location.search.startsWith("?")) {
  e_settings.style.display = "none";
}

// -

function map(obj, fn) {
  fn = fn || (x => x);
  const ret = {};
  for (const [k,v] of Object.entries(obj)) {
    ret[k] = fn(v, k);
  }
  return ret;
}

function map_keys_required(obj, keys, fn) {
  fn = fn || (x => x);

  const ret = {};
  for (const k of keys) {
    const v = obj[k];
    if (v === undefined) throw {k, obj};
    ret[k] = fn(v, k);
  }
  return ret;
}

function set_device_pixel_size(e, device_size) {
  const DPR = window.devicePixelRatio;
  map_keys_required(device_size, ['width''height'], (device, k) => {
    const css = device / DPR;
    e.style[k] = css + 'px';
  });
}

function pad_top_left_to_device_pixels(e) {
  const DPR = window.devicePixelRatio;

  e.style.padding = '';
  let css_rect = e.getBoundingClientRect();
  css_rect = map_keys_required(css_rect, ['left''top']);

  const orig_device_rect = {};
  const snapped_padding = map(css_rect, (css, k) => {
    const device = orig_device_rect[k] = css * DPR;
    const device_snapped = Math.round(device);
    let device_padding = device_snapped - device;
    // Negative padding is treated as 0.
    // We want to pad:
    // * 3.9 -> 4.0
    // * 3.1 -> 4.0
    // * 3.00000001 -> 3.0
    if (device_padding < 0.01) {
      device_padding += 1;
    }
    const css_padding = device_padding / DPR;
    // console.log({css, k, device, device_snapped, device_padding, css_padding});
    return css_padding;
  });

  e.style.paddingLeft = snapped_padding.left + 'px';
  e.style.paddingTop = snapped_padding.top + 'px';
  console.log(`[info] At dpr=${DPR}, padding`, css_rect, '(', orig_device_rect, 'device) by', snapped_padding);
}

// -

const SETTING_NODES = {};
e_settings.childNodes.forEach(n => {
  if (!n.id) return;
  SETTING_NODES[n.id] = n;
  n._default = n.value;
});

const URL_PARAMS = new URLSearchParams(window.location.search);
URL_PARAMS.forEach((v,k) => {
  const n = SETTING_NODES[k];
  if (!n) {
    if (k && !k.startsWith('__')) {
      console.warn(`Unrecognized setting: ${k} = ${v}`);
    }
    return;
  }
  n.value = v;
});

// -

function UNITTEST_STR_EQ(was, expected) {
  function to_result(src) {
    let result = src;
    if (typeof(result) == 'string') {
      result = eval(result);
    }
    let result_str = result.toString();
    if (result instanceof Array) {
      result_str = '[' + result_str + ']';
    }
    return {src, result, result_str};
  }
  was = to_result(was);
  expected = to_result(expected);

  if (false) {
    if (was.result_str != expected.result_str) {
      throw {was, expected};
    }
    console.log(`[unittest] OK `, was.src, ` ->  ${was.result_str}  (`, expected.src, `)`);
  }
  console.assert(was.result_str == expected.result_str,
    was.src, ` ->  ${was.result_str}  (`, expected.src, `)`);
}

// -

/// Non-Premult-Alpha, e.g. [1.0, 1.0, 1.0, 0.5]
function parse_css_color_npa(str) {
  const m = /(rgba?)\((.*)\)/.exec(str);
  if (!m) throw str;

  let vals = m[2];
  vals = vals.split(',').map(s => parseFloat(s));
  if (vals.length == 3) {
    vals.push(1.0);
  }
  for (let i = 0; i < 3; i++) {
    vals[i] /= 255;
  }
  return vals;
}
UNITTEST_STR_EQ(`parse_css_color_npa('rgb(255,255,255)');`, [1,1,1,1]);
UNITTEST_STR_EQ(`parse_css_color_npa('rgba(255,255,255)');`, [1,1,1,1]);
UNITTEST_STR_EQ(`parse_css_color_npa('rgb(20,40,60)');`, '[20/255, 40/255, 60/255, 1]');
UNITTEST_STR_EQ(`parse_css_color_npa('rgb(20,40,60,0.5)');`, '[20/255, 40/255, 60/255, 0.5]');
UNITTEST_STR_EQ(`parse_css_color_npa('rgb(20,40,60,0)');`, '[20/255, 40/255, 60/255, 0]');

// -

let e_canvas;

async function draw() {
  while (e_canvas_holder.firstChild) {
    e_canvas_holder.removeChild(e_canvas_holder.firstChild);
  }

  if (e_img.value) {
    const img = document.createElement("img");
    img.src = e_img.value;
    console.log('img.src ='img.src);
    await img.decode();
    e_canvas_holder.appendChild(img);
    set_device_pixel_size(img, {width: img.naturalWidth, height: img.naturalHeight});
    pad_top_left_to_device_pixels(img);
    return;
  }

  e_canvas = document.createElement("canvas");

  let options = eval(`Object.assign(${e_options.value})`);
  options.colorSpace = e_cspace.value || undefined;

  const context = e_canvas.getContext(e_context.value, options);
  if (context.drawingBufferColorSpace && options.colorSpace) {
    context.drawingBufferColorSpace = options.colorSpace;
  }
  if (context.getContextAttributes) {
    options = context.getContextAttributes();
  }
  console.log({options});

  // -

  const W = parseInt(e_width.value);
  const H = parseInt(e_height.value);
  context.canvas.width = W;
  context.canvas.height = H;
  e_canvas_holder.appendChild(e_canvas);

  // If we don't snap to the device pixel grid, borders between color blocks
  // will be filtered, and this causes a lot of fuzzy() annotations.
  set_device_pixel_size(e_canvas, e_canvas);
  pad_top_left_to_device_pixels(e_canvas);

  // -

  let fillFromElem;
  if (context.fillRect) {
    const c2d = context;
    fillFromElem = (e, left, top, w, h) => {
      if (!e.value) return;
      c2d.fillStyle = e.value;
      c2d.fillRect(left, top, w, h);
    };

  } else if (context.drawArrays) {
    const gl = context;
    gl.enable(gl.SCISSOR_TEST);
    gl.disable(gl.DEPTH_TEST);
    fillFromElem = (e, left, top, w, h) => {
      if (!e.value) return;
      const rgba = parse_css_color_npa(e.value.trim());
      if (false && options.premultipliedAlpha) {
        for (let i = 0; i < 3; i++) {
          rgba[i] *= rgba[3];
        }
      }

      const bottom = top+h; // in y-down c2d coords
      gl.scissor(left, gl.drawingBufferHeight - bottom, w, h);
      gl.clearColor(...rgba);
      gl.clear(gl.COLOR_BUFFER_BIT);
    };
  }

  // -

  const LEFT_HALF = W/2 | 0; // Round
  const TOP_HALF = H/2 | 0;

  fillFromElem(e_color_o1, 0        , 0       ,   LEFT_HALF,   TOP_HALF);
  fillFromElem(e_color_o2, LEFT_HALF, 0       , W-LEFT_HALF,   TOP_HALF);
  fillFromElem(e_color_o3, 0        , TOP_HALF,   LEFT_HALF, H-TOP_HALF);
  fillFromElem(e_color_o4, LEFT_HALF, TOP_HALF, W-LEFT_HALF, H-TOP_HALF);

  // -

  const INNER_SCALE = 1/4;
  const W_INNER = W*INNER_SCALE | 0;
  const H_INNER = H*INNER_SCALE | 0;

  fillFromElem(e_color_i1, LEFT_HALF-W_INNER, TOP_HALF-H_INNER, W_INNER, H_INNER);
  fillFromElem(e_color_i2, LEFT_HALF        , TOP_HALF-H_INNER, W_INNER, H_INNER);
  fillFromElem(e_color_i3, LEFT_HALF-W_INNER, TOP_HALF        , W_INNER, H_INNER);
  fillFromElem(e_color_i4, LEFT_HALF        , TOP_HALF        , W_INNER, H_INNER);
}

(async () => {
  await draw();
  document.documentElement.removeAttribute("class");
})();

// -

Object.values(SETTING_NODES).forEach(x => {
  x.addEventListener("change", draw);
});

e_publish.addEventListener("click", () => {
  let settings = [];
  for (const n of Object.values(SETTING_NODES)) {
    if (n.value == n._default) continue;
    settings.push(`${n.id}=${n.value}`);
  }
  settings = settings.join("&");
  if (!settings) {
    settings = "="; // Empty key-value pair is "publish with default settings"
  }
  window.location.search = "?" + settings;
});
    </script>
  </body>
</html>

Messung V0.5
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge