mirror of https://github.com/SixLabors/ImageSharp
7 changed files with 1568 additions and 23 deletions
@ -0,0 +1,222 @@ |
|||||
|
namespace ImageSharp.Formats.Jpeg.Port.Components |
||||
|
{ |
||||
|
using System; |
||||
|
using ImageSharp.Memory; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Performa the invers
|
||||
|
/// </summary>
|
||||
|
internal static class IDCT |
||||
|
{ |
||||
|
private const int DctCos1 = 4017; // cos(pi/16)
|
||||
|
private const int DctSin1 = 799; // sin(pi/16)
|
||||
|
private const int DctCos3 = 3406; // cos(3*pi/16)
|
||||
|
private const int DctSin3 = 2276; // sin(3*pi/16)
|
||||
|
private const int DctCos6 = 1567; // cos(6*pi/16)
|
||||
|
private const int DctSin6 = 3784; // sin(6*pi/16)
|
||||
|
private const int DctSqrt2 = 5793; // sqrt(2)
|
||||
|
private const int DctSqrt1D2 = 2896; // sqrt(2) / 2
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A port of Poppler's IDCT method which in turn is taken from:
|
||||
|
/// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
|
||||
|
/// 'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
|
||||
|
/// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, 988-991.
|
||||
|
/// </summary>
|
||||
|
/// <param name="quantizationTables">The quantization tables</param>
|
||||
|
/// <param name="component">The fram component</param>
|
||||
|
/// <param name="blockBufferOffset">The block buffer offset</param>
|
||||
|
/// <param name="computationBuffer">The computational buffer for holding temp values</param>
|
||||
|
public static void QuantizeAndInverse(QuantizationTables quantizationTables, ref FrameComponent component, int blockBufferOffset, Buffer<short> computationBuffer) |
||||
|
{ |
||||
|
Span<short> qt = quantizationTables.Tables.GetRowSpan(component.QuantizationIdentifier); |
||||
|
Buffer<short> blockData = component.BlockData; |
||||
|
int v0, v1, v2, v3, v4, v5, v6, v7; |
||||
|
int p0, p1, p2, p3, p4, p5, p6, p7; |
||||
|
int t; |
||||
|
|
||||
|
// inverse DCT on rows
|
||||
|
for (int row = 0; row < 64; row += 8) |
||||
|
{ |
||||
|
// gather block data
|
||||
|
p0 = blockData[blockBufferOffset + row]; |
||||
|
p1 = blockData[blockBufferOffset + row + 1]; |
||||
|
p2 = blockData[blockBufferOffset + row + 2]; |
||||
|
p3 = blockData[blockBufferOffset + row + 3]; |
||||
|
p4 = blockData[blockBufferOffset + row + 4]; |
||||
|
p5 = blockData[blockBufferOffset + row + 5]; |
||||
|
p6 = blockData[blockBufferOffset + row + 6]; |
||||
|
p7 = blockData[blockBufferOffset + row + 7]; |
||||
|
|
||||
|
// dequant p0
|
||||
|
p0 *= qt[row]; |
||||
|
|
||||
|
// check for all-zero AC coefficients
|
||||
|
if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0) |
||||
|
{ |
||||
|
t = ((DctSqrt2 * p0) + 512) >> 10; |
||||
|
short st = (short)t; |
||||
|
computationBuffer[row] = st; |
||||
|
computationBuffer[row + 1] = st; |
||||
|
computationBuffer[row + 2] = st; |
||||
|
computationBuffer[row + 3] = st; |
||||
|
computationBuffer[row + 4] = st; |
||||
|
computationBuffer[row + 5] = st; |
||||
|
computationBuffer[row + 6] = st; |
||||
|
computationBuffer[row + 7] = st; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// dequant p1 ... p7
|
||||
|
p1 *= qt[row + 1]; |
||||
|
p2 *= qt[row + 2]; |
||||
|
p3 *= qt[row + 3]; |
||||
|
p4 *= qt[row + 4]; |
||||
|
p5 *= qt[row + 5]; |
||||
|
p6 *= qt[row + 6]; |
||||
|
p7 *= qt[row + 7]; |
||||
|
|
||||
|
// stage 4
|
||||
|
v0 = ((DctSqrt2 * p0) + 128) >> 8; |
||||
|
v1 = ((DctSqrt2 * p4) + 128) >> 8; |
||||
|
v2 = p2; |
||||
|
v3 = p6; |
||||
|
v4 = ((DctSqrt1D2 * (p1 - p7)) + 128) >> 8; |
||||
|
v7 = ((DctSqrt1D2 * (p1 + p7)) + 128) >> 8; |
||||
|
v5 = p3 << 4; |
||||
|
v6 = p5 << 4; |
||||
|
|
||||
|
// stage 3
|
||||
|
v0 = (v0 + v1 + 1) >> 1; |
||||
|
v1 = v0 - v1; |
||||
|
t = ((v2 * DctSin6) + (v3 * DctCos6) + 128) >> 8; |
||||
|
v2 = ((v2 * DctCos6) - (v3 * DctSin6) + 128) >> 8; |
||||
|
v3 = t; |
||||
|
v4 = (v4 + v6 + 1) >> 1; |
||||
|
v6 = v4 - v6; |
||||
|
v7 = (v7 + v5 + 1) >> 1; |
||||
|
v5 = v7 - v5; |
||||
|
|
||||
|
// stage 2
|
||||
|
v0 = (v0 + v3 + 1) >> 1; |
||||
|
v3 = v0 - v3; |
||||
|
v1 = (v1 + v2 + 1) >> 1; |
||||
|
v2 = v1 - v2; |
||||
|
t = ((v4 * DctSin3) + (v7 * DctCos3) + 2048) >> 12; |
||||
|
v4 = ((v4 * DctCos3) - (v7 * DctSin3) + 2048) >> 12; |
||||
|
v7 = t; |
||||
|
t = ((v5 * DctSin1) + (v6 * DctCos1) + 2048) >> 12; |
||||
|
v5 = ((v5 * DctCos1) - (v6 * DctSin1) + 2048) >> 12; |
||||
|
v6 = t; |
||||
|
|
||||
|
// stage 1
|
||||
|
computationBuffer[row] = (short)(v0 + v7); |
||||
|
computationBuffer[row + 7] = (short)(v0 - v7); |
||||
|
computationBuffer[row + 1] = (short)(v1 + v6); |
||||
|
computationBuffer[row + 6] = (short)(v1 - v6); |
||||
|
computationBuffer[row + 2] = (short)(v2 + v5); |
||||
|
computationBuffer[row + 5] = (short)(v2 - v5); |
||||
|
computationBuffer[row + 3] = (short)(v3 + v4); |
||||
|
computationBuffer[row + 4] = (short)(v3 - v4); |
||||
|
} |
||||
|
|
||||
|
// inverse DCT on columns
|
||||
|
for (int col = 0; col < 8; ++col) |
||||
|
{ |
||||
|
p0 = computationBuffer[col]; |
||||
|
p1 = computationBuffer[col + 8]; |
||||
|
p2 = computationBuffer[col + 16]; |
||||
|
p3 = computationBuffer[col + 24]; |
||||
|
p4 = computationBuffer[col + 32]; |
||||
|
p5 = computationBuffer[col + 40]; |
||||
|
p6 = computationBuffer[col + 48]; |
||||
|
p7 = computationBuffer[col + 56]; |
||||
|
|
||||
|
// check for all-zero AC coefficients
|
||||
|
if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) == 0) |
||||
|
{ |
||||
|
t = ((DctSqrt2 * p0) + 8192) >> 14; |
||||
|
|
||||
|
// convert to 8 bit
|
||||
|
t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4; |
||||
|
short st = (short)t; |
||||
|
|
||||
|
blockData[blockBufferOffset + col] = st; |
||||
|
blockData[blockBufferOffset + col + 8] = st; |
||||
|
blockData[blockBufferOffset + col + 16] = st; |
||||
|
blockData[blockBufferOffset + col + 24] = st; |
||||
|
blockData[blockBufferOffset + col + 32] = st; |
||||
|
blockData[blockBufferOffset + col + 40] = st; |
||||
|
blockData[blockBufferOffset + col + 48] = st; |
||||
|
blockData[blockBufferOffset + col + 56] = st; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// stage 4
|
||||
|
v0 = ((DctSqrt2 * p0) + 2048) >> 12; |
||||
|
v1 = ((DctSqrt2 * p4) + 2048) >> 12; |
||||
|
v2 = p2; |
||||
|
v3 = p6; |
||||
|
v4 = ((DctSqrt1D2 * (p1 - p7)) + 2048) >> 12; |
||||
|
v7 = ((DctSqrt1D2 * (p1 + p7)) + 2048) >> 12; |
||||
|
v5 = p3; |
||||
|
v6 = p5; |
||||
|
|
||||
|
// stage 3
|
||||
|
// Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
|
||||
|
// converting to UInt8 range later.
|
||||
|
v0 = ((v0 + v1 + 1) >> 1) + 4112; |
||||
|
v1 = v0 - v1; |
||||
|
t = ((v2 * DctSin6) + (v3 * DctCos6) + 2048) >> 12; |
||||
|
v2 = ((v2 * DctCos6) - (v3 * DctSin6) + 2048) >> 12; |
||||
|
v3 = t; |
||||
|
v4 = (v4 + v6 + 1) >> 1; |
||||
|
v6 = v4 - v6; |
||||
|
v7 = (v7 + v5 + 1) >> 1; |
||||
|
v5 = v7 - v5; |
||||
|
|
||||
|
// stage 2
|
||||
|
v0 = (v0 + v3 + 1) >> 1; |
||||
|
v3 = v0 - v3; |
||||
|
v1 = (v1 + v2 + 1) >> 1; |
||||
|
v2 = v1 - v2; |
||||
|
t = ((v4 * DctSin3) + (v7 * DctCos3) + 2048) >> 12; |
||||
|
v4 = ((v4 * DctCos3) - (v7 * DctSin3) + 2048) >> 12; |
||||
|
v7 = t; |
||||
|
t = ((v5 * DctSin1) + (v6 * DctCos1) + 2048) >> 12; |
||||
|
v5 = ((v5 * DctCos1) - (v6 * DctSin1) + 2048) >> 12; |
||||
|
v6 = t; |
||||
|
|
||||
|
// stage 1
|
||||
|
p0 = v0 + v7; |
||||
|
p7 = v0 - v7; |
||||
|
p1 = v1 + v6; |
||||
|
p6 = v1 - v6; |
||||
|
p2 = v2 + v5; |
||||
|
p5 = v2 - v5; |
||||
|
p3 = v3 + v4; |
||||
|
p4 = v3 - v4; |
||||
|
|
||||
|
// convert to 8-bit integers
|
||||
|
p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4; |
||||
|
p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4; |
||||
|
p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4; |
||||
|
p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4; |
||||
|
p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4; |
||||
|
p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4; |
||||
|
p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4; |
||||
|
p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4; |
||||
|
|
||||
|
// store block data
|
||||
|
blockData[blockBufferOffset + col] = (short)p0; |
||||
|
blockData[blockBufferOffset + col + 8] = (short)p1; |
||||
|
blockData[blockBufferOffset + col + 16] = (short)p2; |
||||
|
blockData[blockBufferOffset + col + 24] = (short)p3; |
||||
|
blockData[blockBufferOffset + col + 32] = (short)p4; |
||||
|
blockData[blockBufferOffset + col + 40] = (short)p5; |
||||
|
blockData[blockBufferOffset + col + 48] = (short)p6; |
||||
|
blockData[blockBufferOffset + col + 56] = (short)p7; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
|
||||
|
<head> |
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<input type="file" id="files" /> |
||||
|
<div id="output"></div> |
||||
|
<script src="jpg.js"></script> |
||||
|
<script> |
||||
|
(function (document) { |
||||
|
var input = document.getElementById("files"), |
||||
|
output = document.getElementById('output'), |
||||
|
fileData; // We need fileData to be visible to getBuffer. |
||||
|
|
||||
|
// Eventhandler for file input. |
||||
|
function openfile(evt) { |
||||
|
var files = input.files; |
||||
|
// Pass the file to the blob, not the input[0]. |
||||
|
fileData = new Blob([files[0]]); |
||||
|
// Pass getBuffer to promise. |
||||
|
var promise = new Promise(getBuffer); |
||||
|
// Wait for promise to be resolved, or log error. |
||||
|
promise.then(function (data) { |
||||
|
// Here you can pass the bytes to another function. |
||||
|
// output.innerHTML = data.toString(); |
||||
|
// console.log(data); |
||||
|
console.log(new Date()); |
||||
|
var jpeg = new JpegImage(); |
||||
|
jpeg.parse(data); |
||||
|
var d = jpeg.getData(804, 1198, true); |
||||
|
// output.innerHTML = d.toString(); |
||||
|
console.log(new Date()); |
||||
|
console.log(d); |
||||
|
|
||||
|
}).catch(function (err) { |
||||
|
console.log('Error: ', err); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
Create a function which will be passed to the promise |
||||
|
and resolve it when FileReader has finished loading the file. |
||||
|
*/ |
||||
|
function getBuffer(resolve) { |
||||
|
var reader = new FileReader(); |
||||
|
reader.readAsArrayBuffer(fileData); |
||||
|
reader.onload = function () { |
||||
|
var arrayBuffer = reader.result |
||||
|
var bytes = new Uint8Array(arrayBuffer); |
||||
|
resolve(bytes); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Eventlistener for file input. |
||||
|
input.addEventListener('change', openfile, false); |
||||
|
}(document)); |
||||
|
</script> |
||||
|
|
||||
|
</body> |
||||
|
|
||||
|
</html> |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue