1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
// From: http://stackoverflow.com/a/18320662
const resample = (canvas, width, height, resize_canvas) => {
let width_source = canvas.width;
let height_source = canvas.height;
width = Math.round(width);
height = Math.round(height);
let ratio_w = width_source / width;
let ratio_h = height_source / height;
let ratio_w_half = Math.ceil(ratio_w / 2);
let ratio_h_half = Math.ceil(ratio_h / 2);
let ctx = canvas.getContext("2d");
let img = ctx.getImageData(0, 0, width_source, height_source);
let img2 = ctx.createImageData(width, height);
let data = img.data;
let data2 = img2.data;
for (let j = 0; j < height; j++) {
for (let i = 0; i < width; i++) {
let x2 = (i + j * width) * 4;
let weight = 0;
let weights = 0;
let weights_alpha = 0;
let gx_r = 0;
let gx_g = 0;
let gx_b = 0;
let gx_a = 0;
let center_y = (j + 0.5) * ratio_h;
let yy_start = Math.floor(j * ratio_h);
let yy_stop = Math.ceil((j + 1) * ratio_h);
for (let yy = yy_start; yy < yy_stop; yy++) {
let dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
let center_x = (i + 0.5) * ratio_w;
let w0 = dy * dy; //pre-calc part of w
let xx_start = Math.floor(i * ratio_w);
let xx_stop = Math.ceil((i + 1) * ratio_w);
for (let xx = xx_start; xx < xx_stop; xx++) {
let dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
let w = Math.sqrt(w0 + dx * dx);
if (w >= 1) {
// pixel too far
continue;
}
// hermite filter
weight = 2 * w * w * w - 3 * w * w + 1;
let pos_x = 4 * (xx + yy * width_source);
// alpha
gx_a += weight * data[pos_x + 3];
weights_alpha += weight;
// colors
if (data[pos_x + 3] < 255)
weight = weight * data[pos_x + 3] / 250;
gx_r += weight * data[pos_x];
gx_g += weight * data[pos_x + 1];
gx_b += weight * data[pos_x + 2];
weights += weight;
}
}
data2[x2] = gx_r / weights;
data2[x2 + 1] = gx_g / weights;
data2[x2 + 2] = gx_b / weights;
data2[x2 + 3] = gx_a / weights_alpha;
}
}
// clear and resize canvas
if (resize_canvas === true) {
canvas.width = width;
canvas.height = height;
} else {
ctx.clearRect(0, 0, width_source, height_source);
}
// draw
ctx.putImageData(img2, 0, 0);
};
const Avatar = React.createClass({
propTypes: {
src: React.PropTypes.string.isRequired,
size: React.PropTypes.number.isRequired,
style: React.PropTypes.object,
animated: React.PropTypes.bool
},
getDefaultProps () {
return {
animated: true
};
},
getInitialState () {
return {
hovering: false
};
},
mixins: [PureRenderMixin],
handleMouseEnter () {
this.setState({ hovering: true });
},
handleMouseLeave () {
this.setState({ hovering: false });
},
handleLoad () {
this.canvas.width = this.image.naturalWidth;
this.canvas.height = this.image.naturalHeight;
this.canvas.getContext('2d').drawImage(this.image, 0, 0);
resample(this.canvas, this.props.size * window.devicePixelRatio, this.props.size * window.devicePixelRatio, true);
},
setImageRef (c) {
this.image = c;
},
setCanvasRef (c) {
this.canvas = c;
},
render () {
const { hovering } = this.state;
if (this.props.animated) {
return (
<div style={{ ...this.props.style, width: `${this.props.size}px`, height: `${this.props.size}px` }}>
<img src={this.props.src} width={this.props.size} height={this.props.size} alt='' style={{ borderRadius: '4px' }} />
</div>
);
}
return (
<div onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} style={{ ...this.props.style, width: `${this.props.size}px`, height: `${this.props.size}px`, position: 'relative' }}>
<img ref={this.setImageRef} onLoad={this.handleLoad} src={this.props.src} width={this.props.size} height={this.props.size} alt='' style={{ position: 'absolute', top: '0', left: '0', opacity: hovering ? '1' : '0', borderRadius: '4px' }} />
<canvas ref={this.setCanvasRef} style={{ borderRadius: '4px', width: this.props.size, height: this.props.size, opacity: hovering ? '0' : '1' }} />
</div>
);
}
});
export default Avatar;
|