I have a picture in jpg format(9248 × 6936, 36.6MB). At first I tried to display it completely in webgl.
const VERTEX_SHADER = `
attribute vec2 a_position;
attribute vec2 a_texCoord;
varying vec2 vTexcoord;
void main() {
gl_Position = vec4(a_position * vec2(1.0,-1.0), 0.0, 1.0);
// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
vTexcoord = a_texCoord;
}`
const FRAGMENT_SHADER = `
uniform mediump sampler2D u_sourceTexture;
varying mediump vec2 vTexcoord;
void main() {
gl_FragColor = texture2D(u_sourceTexture, vTexcoord);
}`
And set the width and height of the canvas to be the same as the width and height of the picture(9248 × 6936):
var canvas = document.querySelector("#canvas");
var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});
gl.canvas.width = image.width
gl.canvas.height = image.height
I used that image directly to create the texture:
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.FLOAT, image);
I set the position (-1.0, -1.0) ~ (1.0, 1.0), and texcoord (0.0, 0.0) to (1.0, 1.0)
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0
]), gl.STATIC_DRAW);
var texcoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0,
]), gl.STATIC_DRAW);
If I set the viewport equal to the width and height of the image, only part of the texture will be displayed. So finally set the viewport of webgl equal to drawingBufferWidth and drawingBufferHeight:
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
Everything looks fine, the image fills the canvas, and the canvas has the same width and height as the image. But something went wrong when I was about to save the image. Although the saved image has the same width and height as the original image, the real image only occupies a small part, and the rest are black pixels.
var canvas = document.querySelector("#canvas");
canvas.toBlob((blob) => {
let a = document.createElement('a')
a.download = 'tmp.jpg'
let s = URL.createObjectURL(blob)
a.href = s
a.click()
URL.revokeObjectURL(s)
}, 'image/jpeg', 0.95)
Why does the texture fill up the canvas, but not when it is saved?