You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, filename = 'extracted_audio') {
const container = document.createElement('div');
container.style.display = 'flex';
container.style.flexDirection = 'column';
container.style.alignItems = 'center';
container.style.justifyContent = 'center';
container.style.gap = '15px';
container.style.fontFamily = 'Arial, sans-serif';
container.style.padding = '20px';
container.style.backgroundColor = '#f9f9f9';
container.style.borderRadius = '8px';
container.style.border = '1px solid #ccc';
container.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
container.style.width = '100%';
container.style.maxWidth = '400px';
const titleText = document.createElement('h3');
titleText.innerText = 'Video Audio Extractor Tool';
titleText.style.margin = '0';
titleText.style.color = '#333';
container.appendChild(titleText);
const statusText = document.createElement('div');
statusText.innerText = 'Loading media file, please wait...';
statusText.style.color = '#555';
statusText.style.fontSize = '14px';
statusText.style.textAlign = 'center';
container.appendChild(statusText);
// Run processing asynchronously after returning the container for UI feedback
setTimeout(async () => {
try {
// Fetch raw data from the image's source (works even if the given file was a video object mapped to img.src)
const response = await fetch(originalImg.src);
const arrayBuffer = await response.arrayBuffer();
statusText.innerText = 'Decoding audio data...';
// Allow status text update to render
await new Promise(resolve => setTimeout(resolve, 50));
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const audioBuffer = await new Promise((resolve, reject) => {
audioCtx.decodeAudioData(arrayBuffer, resolve, reject);
});
statusText.innerText = 'Encoding to WAV...';
await new Promise(resolve => setTimeout(resolve, 50));
let numChannels = audioBuffer.numberOfChannels;
let sampleRate = audioBuffer.sampleRate;
let bitDepth = 16;
let channels = [];
for (let i = 0; i < numChannels; i++) {
channels.push(audioBuffer.getChannelData(i));
}
let result;
if (numChannels === 1) {
result = channels[0];
} else {
let length = channels[0].length * numChannels;
result = new Float32Array(length);
let index = 0;
let inputIndex = 0;
while (index < length) {
for (let i = 0; i < numChannels; i++) {
result[index++] = channels[i][inputIndex];
}
inputIndex++;
}
}
let bytesPerSample = bitDepth / 8;
let blockAlign = numChannels * bytesPerSample;
let wavBuffer = new ArrayBuffer(44 + result.length * bytesPerSample);
let view = new DataView(wavBuffer);
const writeString = (view, offset, string) => {
for (let i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
};
// Write WAV Header
writeString(view, 0, 'RIFF');
view.setUint32(4, 36 + result.length * bytesPerSample, true);
writeString(view, 8, 'WAVE');
writeString(view, 12, 'fmt ');
view.setUint32(16, 16, true);
view.setUint16(20, 1, true); // Raw PCM
view.setUint16(22, numChannels, true);
view.setUint32(24, sampleRate, true);
view.setUint32(28, sampleRate * blockAlign, true);
view.setUint16(32, blockAlign, true);
view.setUint16(34, bitDepth, true);
writeString(view, 36, 'data');
view.setUint32(40, result.length * bytesPerSample, true);
// Write PCM Samples
let offset = 44;
for (let i = 0; i < result.length; i++, offset += 2) {
let s = Math.max(-1, Math.min(1, result[i]));
// Optimize using standard 16-bit audio conversion formatting
view.setInt16(offset, s < 0 ? Math.floor(s * 0x8000) : Math.floor(s * 0x7FFF), true);
}
const blob = new Blob([view], { type: 'audio/wav' });
const url = URL.createObjectURL(blob);
const audioEl = document.createElement('audio');
audioEl.controls = true;
audioEl.src = url;
audioEl.style.width = '100%';
audioEl.style.marginTop = '10px';
const downloadLink = document.createElement('a');
downloadLink.href = url;
downloadLink.download = `${filename}.wav`;
downloadLink.innerText = 'Download Extracted Audio (WAV)';
downloadLink.style.padding = '10px 20px';
downloadLink.style.backgroundColor = '#007BFF';
downloadLink.style.color = '#FFF';
downloadLink.style.textDecoration = 'none';
downloadLink.style.borderRadius = '5px';
downloadLink.style.fontWeight = 'bold';
downloadLink.style.textAlign = 'center';
downloadLink.style.width = '100%';
downloadLink.style.boxSizing = 'border-box';
downloadLink.style.transition = 'background-color 0.2s';
downloadLink.onmouseover = () => { downloadLink.style.backgroundColor = '#0056b3'; };
downloadLink.onmouseout = () => { downloadLink.style.backgroundColor = '#007BFF'; };
statusText.innerText = 'Audio extracted successfully!';
statusText.style.color = 'green';
statusText.style.fontWeight = 'bold';
container.appendChild(audioEl);
container.appendChild(downloadLink);
} catch (error) {
statusText.innerText = 'Error extracting audio. Ensure the file contains a recognizable audio track.';
statusText.style.color = 'red';
console.error(error);
}
}, 100);
return container;
}
Apply Changes