fixed several issues with waveforms...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-12-27 02:24:15 +03:00
parent acebbf51ff
commit d5689162ff

View File

@ -18,17 +18,17 @@ var object = require('lib/object')
var Filters = var Filters =
module.Filters = { module.Filters = {
makeCanvas: function(w, h){ makeCanvas: function(w, h, canvas){
var c = document.createElement('canvas') var c = canvas || document.createElement('canvas')
c.width = w c.width = w
c.height = h c.height = h
return c }, return c },
// as input takes an HTML Image object... // as input takes an HTML Image object...
getPixels: function(img, w, h){ getPixels: function(img, tmp_canvas, w, h){
var w = w || img.width var w = w || img.naturalWidth
var h = h || img.height var h = h || img.naturalHeight
var c = this.makeCanvas(w, h) var c = this.makeCanvas(w, h, tmp_canvas)
var context = c.getContext('2d') var context = c.getContext('2d')
if(img == null){ if(img == null){
context.rect(0, 0, w, h) context.rect(0, 0, w, h)
@ -46,8 +46,13 @@ module.Filters = {
// get image pixels normalized to a square of size s, rotated and flipped... // get image pixels normalized to a square of size s, rotated and flipped...
// //
// NOTE: flip is applied to the image before it is rotated... (XXX ???) // NOTE: flip is applied to the image before it is rotated... (XXX ???)
getNormalizedPixels: function(img, s, rotate, flip){ // XXX BUG: this is still wrong for images with exif orientation...
s = s || Math.max(img.width, img.height) // to reproduce:
// loadImages: "L:/tmp/test/export-test/index-with-exif-rotation"
// focusImage: 2
// showMetadata
getNormalizedPixels: function(img, tmp_canvas, s, rotate, flip){
s = s || Math.max(img.naturalWidth, img.naturalHeight)
rotate = rotate || 0 rotate = rotate || 0
;(rotate == 90 || rotate == 270) ;(rotate == 90 || rotate == 270)
@ -64,7 +69,7 @@ module.Filters = {
[1, -1] [1, -1]
: [1, 1] : [1, 1]
var c = this.makeCanvas(s, s) var c = this.makeCanvas(s, s, tmp_canvas)
var context = c.getContext('2d') var context = c.getContext('2d')
context.rect(0, 0, s, s) context.rect(0, 0, s, s)
context.fillStyle = 'black' context.fillStyle = 'black'
@ -104,7 +109,7 @@ module.Filters = {
var h = size var h = size
// output buffer... // output buffer...
var out = this.getPixels(null, w, h) var out = this.getPixels(null, null, w, h)
// pixel hit buffer... // pixel hit buffer...
var count = [] var count = []
@ -158,21 +163,23 @@ module.Filters = {
color = color || 'normalized' color = color || 'normalized'
var w = pixels.width var w = pixels.width
var h = pixels.height
// normalize pixel ratio... // normalize pixel ratio...
var m = (1/pixels.height)*255 var m = (1/h)*255
var offsetTop = 0 var offsetTop = 0
var offsetBottom = 0 var offsetBottom = 0
// output buffer... // output buffer...
var out = this.getPixels(null, var out = this.getPixels(null, null,
w, w,
offsetTop + 255 + offsetBottom) offsetTop + 255 + offsetBottom)
// pixel hit buffer... // pixel hit buffer...
// XXX make this an ArrayBuffer(..) // XXX revise size -- do we need the alpha component??
var count = [] var count = new Int8Array(new ArrayBuffer(w * h * 4))
//var count = []
var od = out.data var od = out.data
var d = pixels.data var d = pixels.data
@ -182,15 +189,15 @@ module.Filters = {
// horizontal position offset... // horizontal position offset...
var _hp = w*4 var _hp = w*4
// top margin... // top margin...
var _tm = offsetTop*_tm var _tm = offsetTop*_hp
var pos = function(i, value){ var pos = function(i, value){
return (_tm, return (_tm
// horixontal position... // horizontal position...
+ i%(_hp) + i%(_hp)
// value vertical offset... // value vertical offset...
+ (255-Math.round(value))*_hp) } + (255-Math.round(value))*_hp) }
var gain = 100 var gain = 100 * m
// CIE luminance for RGB // CIE luminance for RGB
var Rl = 0.2126 var Rl = 0.2126
@ -205,42 +212,42 @@ module.Filters = {
var c, j, f, x, y var c, j, f, x, y
if(mode == 'luminance'){ if(mode === 'luminance'){
var v = Rl*r + Gl*g + Bl*b var v = Rl*r + Gl*g + Bl*b
c = count[j = pos(i, v)] = (count[j] || 0) + m c = count[j = pos(i, v)] = (count[j] || 0) + 1
od[j] = od[j+1] = od[j+2] = c * gain od[j] = od[j+1] = od[j+2] = c * gain
} else { } else {
if(mode == 'color' || mode == 'R'){ if(mode === 'color' || mode === 'R'){
f = Rl f = Rl
x = 1 x = 1
y = 2 y = 2
j = pos(i, r) j = pos(i, r)
c = count[j] = (count[j] || 0) + m c = count[j] = (count[j] || 0) + 1
od[j] = c * gain } od[j] = c * gain }
if(mode == 'color' || mode == 'G'){ if(mode === 'color' || mode === 'G'){
f = Gl f = Gl
x = -1 x = -1
y = 1 y = 1
j = pos(i, g) + 1 j = pos(i, g) + 1
c = count[j] = (count[j] || 0) + m c = count[j] = (count[j] || 0) + 1
od[j] = c * gain } od[j] = c * gain }
if(mode == 'color' || mode == 'B'){ if(mode === 'color' || mode === 'B'){
f = Bl f = Bl
x = -2 x = -2
y = -1 y = -1
j = pos(i, b) + 2 j = pos(i, b) + 2
c = count[j] = (count[j] || 0) + m c = count[j] = (count[j] || 0) + 1
od[j] = c * gain } od[j] = c * gain }
// normalize... // normalize...
mode != 'color' mode !== 'color'
&& (color == 'white' ? && (color === 'white' ?
(od[j+x] = od[j+y] = c * gain) (od[j+x] = od[j+y] = c * gain)
: color == 'normalized' ? : color === 'normalized' ?
(od[j+x] = od[j+y] = c * gain/2 * (1-f)) (od[j+x] = od[j+y] = c * gain/2 * (1-f))
: null) } } : null) } }
return out }, return out },
@ -256,8 +263,8 @@ module.WAVEFORM_SIZE = 1000
var waveform = var waveform =
module.waveform = module.waveform =
function(img, canvas, mode, color, rotate, flip){ function(img, canvas, tmp_canvas, mode, color, rotate, flip){
var d = Filters.getNormalizedPixels(img, WAVEFORM_SIZE, rotate, flip) var d = Filters.getNormalizedPixels(img, tmp_canvas, WAVEFORM_SIZE, rotate, flip)
var w = Filters.waveform(d, mode, color) var w = Filters.waveform(d, mode, color)
Filters.setPixels(canvas, w) } Filters.setPixels(canvas, w) }
@ -267,8 +274,8 @@ module.HISTOGRAM_SIZE = 1000
var histogram = var histogram =
module.histogram = module.histogram =
function(img, canvas, mode, color){ function(img, canvas, tmp_canvas, mode, color){
var d = Filters.getPixels(img) var d = Filters.getPixels(img, tmp_canvas)
var w = Filters.histogram(d, mode, color) var w = Filters.histogram(d, mode, color)
Filters.setPixels(canvas, w) } Filters.setPixels(canvas, w) }
@ -325,9 +332,19 @@ var igImageGraph_template = `
:host .controls button:hover:not([disabled]) { :host .controls button:hover:not([disabled]) {
opacity: 1; opacity: 1;
} }
:host .hidden {
position: absolute;
width: 0;
height: 0;
opacity: 0;
image-orientation: none;
}
</style> </style>
<canvas class="graph"></canvas> <canvas class="graph"></canvas>
<div class="controls"></div> <div class="controls"></div>
<img class="hidden"/>
<canvas class="hidden"></canvas>
` `
@ -356,7 +373,8 @@ object.Constructor('igImageGraph', HTMLElement, {
shadow.appendChild(tpl.content.cloneNode(true)) }, shadow.appendChild(tpl.content.cloneNode(true)) },
connectedCallback: function(){ connectedCallback: function(){
this.update_controls() this.update_controls()
this.update() }, this.image
|| this.update() },
// attributes... // attributes...
get observedAttributes(){ get observedAttributes(){
@ -393,7 +411,9 @@ object.Constructor('igImageGraph', HTMLElement, {
// get/create image... // get/create image...
var img = this.image = var img = this.image =
url ? url ?
(this.image || document.createElement('img')) //(this.image || document.createElement('img'))
// XXX HACK: image-orientation only works if element is attached to DOM...
(this.image || this.__shadow.querySelector('img'))
: value : value
img.removeEventListener('load', this.__update_handler) img.removeEventListener('load', this.__update_handler)
img.addEventListener('load', this.__update_handler) img.addEventListener('load', this.__update_handler)
@ -559,19 +579,18 @@ object.Constructor('igImageGraph', HTMLElement, {
button button
&& button.classList.add('current') } && button.classList.add('current') }
// XXX configurable...
var type = this.graph
var graph = this.graphs[type]
var canvas = this.__shadow.querySelector('canvas')
if(this.image){ if(this.image){
var orientation = this.orientation var orientation = this.orientation
orientation = parseFloat( orientation = parseFloat(
{top: 180, left: 90, bottom: 0, right: 270}[orientation] {top: 180, left: 90, bottom: 0, right: 270}[orientation]
|| orientation) || orientation)
graph(this.image, canvas, var canvas = this.__shadow.querySelector('canvas.graph')
var tmp_canvas = this.__shadow.querySelector('canvas.hidden')
// XXX configurable...
this.graphs[this.graph](this.image,
canvas, tmp_canvas,
this.mode, this.mode,
this.color, this.color,
Math.round(orientation), Math.round(orientation),