diff --git a/.prettierrc b/.prettierrc index 9573023..f98a0aa 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,6 @@ { - "useTabs": true, + "useTabs": false, + "tabWidth": 4, "singleQuote": true, "trailingComma": "none", "printWidth": 100, diff --git a/jsconfig.json b/jsconfig.json index fc93cbd..f28e9d5 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -2,7 +2,7 @@ "extends": "./.svelte-kit/tsconfig.json", "compilerOptions": { "allowJs": true, - "checkJs": true, + "checkJs": false, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, diff --git a/package.json b/package.json index 06b7ded..b3b614a 100644 --- a/package.json +++ b/package.json @@ -28,5 +28,8 @@ "vite": "^5.0.3", "vitest": "^1.2.0" }, - "type": "module" + "type": "module", + "dependencies": { + "localforage": "^1.10.0" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 234364f..0f0e0ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +dependencies: + localforage: + specifier: ^1.10.0 + version: 1.10.0 + devDependencies: '@sveltejs/adapter-auto': specifier: ^3.0.0 @@ -1271,6 +1276,10 @@ packages: engines: {node: '>= 4'} dev: true + /immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + dev: false + /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -1389,6 +1398,12 @@ packages: type-check: 0.4.0 dev: true + /lie@3.1.1: + resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} + dependencies: + immediate: 3.0.6 + dev: false + /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -1402,6 +1417,12 @@ packages: pkg-types: 1.1.0 dev: true + /localforage@1.10.0: + resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} + dependencies: + lie: 3.1.1 + dev: false + /locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} dev: true diff --git a/src/components/background.svelte b/src/components/background.svelte new file mode 100644 index 0000000..9b59aeb --- /dev/null +++ b/src/components/background.svelte @@ -0,0 +1,44 @@ + + +
+ +
+ + diff --git a/src/lib/graphics/index.ts b/src/lib/graphics/index.ts new file mode 100644 index 0000000..148b4df --- /dev/null +++ b/src/lib/graphics/index.ts @@ -0,0 +1,55 @@ +import { gaussianBlurHorizontal, gaussianBlurVertical, applyFilter } from "./utils"; + +export async function processImage(blockSize: number, resolutionFactor:number, radius:number, path: string, canvas: HTMLCanvasElement) { + const ctx = canvas.getContext("2d")!; + + const image = new Image(); + image.src = path; // Replace with your image path + + image.onload = function () { + // Resize image to 1/9 of the original resolution + const resizedWidth = image.width / resolutionFactor; + const resizedHeight = image.height / resolutionFactor; + + const num_blocks_x = Math.floor(resizedWidth / blockSize); + const num_blocks_y = Math.floor(resizedHeight / blockSize); + + canvas.width = resizedWidth; + canvas.height = resizedHeight; + + for (let i = 0; i < num_blocks_y; i++) { + for (let j = 0; j < num_blocks_x; j++) { + const block = document.createElement("canvas"); + block.width = blockSize; + block.height = blockSize; + + const blockCtx = block.getContext("2d")!; + blockCtx.drawImage( + image, + j * blockSize * resolutionFactor, + i * blockSize * resolutionFactor, + blockSize * resolutionFactor, + blockSize * resolutionFactor, + 0, + 0, + blockSize, + blockSize + ); + + applyFilter(block); + + ctx.drawImage(block, j * blockSize, i * blockSize); + } + } + + // Horizontal Gaussian blur + const imageDataHorizontal = ctx.getImageData(0, 0, canvas.width, canvas.height); + const blurredImageDataHorizontal = gaussianBlurHorizontal(imageDataHorizontal, radius); + + // Vertical Gaussian blur + const imageDataVertical = blurredImageDataHorizontal; + const blurredImageData = gaussianBlurVertical(imageDataVertical, radius); + + ctx.putImageData(blurredImageData, 0, 0); + }; +} \ No newline at end of file diff --git a/src/lib/graphics/utils.js b/src/lib/graphics/utils.js new file mode 100644 index 0000000..51d3b64 --- /dev/null +++ b/src/lib/graphics/utils.js @@ -0,0 +1,191 @@ +// Function to apply filter to the block +export function applyFilter(block) { + let imageData = block.getContext("2d").getImageData(0, 0, block.width, block.height); + let data = imageData.data; + + for (let i = 0; i < data.length; i += 4) { + let hsv = rgbToHsv(data[i], data[i + 1], data[i + 2]); + + // Mainly adjust saturation and value channels + hsv[1] = Math.min(hsv[1] * 1.05 + 30 * Math.log(hsv[1] / 100 + 1), 100); + hsv[2] = Math.min(hsv[2] * 1.3 + 40 * Math.log(hsv[2] / 100 + 1), 100); + + let rgb = hsvToRgb(hsv[0], hsv[1], hsv[2]); + + data[i] = rgb[0]; + data[i + 1] = rgb[1]; + data[i + 2] = rgb[2]; + } + + block.getContext("2d").putImageData(imageData, 0, 0); +} + +// Function to perform horizontal Gaussian blur +export function gaussianBlurHorizontal(imageData, radius) { + const width = imageData.width; + const height = imageData.height; + + const newData = new Uint8ClampedArray(imageData.data); + + const kernel = generateGaussianKernel(radius); + + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + let r = 0, + g = 0, + b = 0, + a = 0; + + for (let kx = -radius; kx <= radius; kx++) { + const pixelX = Math.min(width - 1, Math.max(0, x + kx)); + + const kernelValue = kernel[kx + radius]; + + const index = (y * width + pixelX) * 4; + + r += imageData.data[index] * kernelValue; + g += imageData.data[index + 1] * kernelValue; + b += imageData.data[index + 2] * kernelValue; + a += imageData.data[index + 3] * kernelValue; + } + + const dataIndex = (y * width + x) * 4; + newData[dataIndex] = r; + newData[dataIndex + 1] = g; + newData[dataIndex + 2] = b; + newData[dataIndex + 3] = a; + } + } + + return new ImageData(newData, width, height); +} + +// Function to perform vertical Gaussian blur +export function gaussianBlurVertical(imageData, radius) { + const width = imageData.width; + const height = imageData.height; + + const newData = new Uint8ClampedArray(imageData.data); + + const kernel = generateGaussianKernel(radius); + + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + let r = 0, + g = 0, + b = 0, + a = 0; + + for (let ky = -radius; ky <= radius; ky++) { + const pixelY = Math.min(height - 1, Math.max(0, y + ky)); + + const kernelValue = kernel[ky + radius]; + + const index = (pixelY * width + x) * 4; + + r += imageData.data[index] * kernelValue; + g += imageData.data[index + 1] * kernelValue; + b += imageData.data[index + 2] * kernelValue; + a += imageData.data[index + 3] * kernelValue; + } + + const dataIndex = (y * width + x) * 4; + newData[dataIndex] = r; + newData[dataIndex + 1] = g; + newData[dataIndex + 2] = b; + newData[dataIndex + 3] = a; + } + } + + return new ImageData(newData, width, height); +} + +// Function to generate Gaussian kernel +function generateGaussianKernel(radius) { + const size = radius * 2 + 1; + const kernel = []; + + const sigma = 0.4 * ((radius - 1) * 0.5 - 1) + 0.8; + + for (let i = 0; i < size; i++) { + const x = i - radius; + const exponent = Math.exp(-(x * x) / (2 * sigma * sigma)); + kernel[i] = exponent / (Math.sqrt(2 * Math.PI) * sigma); + } + + // Normalize the kernel + const sum = kernel.reduce((a, b) => a + b, 0); + return kernel.map((value) => value / sum); +} + +// Function to convert RGB to HSV +function rgbToHsv(r, g, b) { + (r /= 255), (g /= 255), (b /= 255); + + let max = Math.max(r, g, b), + min = Math.min(r, g, b), + h, + s, + v = max; + + let d = max - min; + s = max === 0 ? 0 : d / max; + + if (max === min) { + h = 0; // achromatic + } else { + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + + return [h * 360, s * 100, v * 100]; +} + +// Function to convert HSV to RGB +function hsvToRgb(h, s, v) { + h /= 360; + s /= 100; + v /= 100; + + let i = Math.floor(h * 6), + f = h * 6 - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + r, + g, + b; + + switch (i % 6) { + case 0: + (r = v), (g = t), (b = p); + break; + case 1: + (r = q), (g = v), (b = p); + break; + case 2: + (r = p), (g = v), (b = t); + break; + case 3: + (r = p), (g = q), (b = v); + break; + case 4: + (r = t), (g = p), (b = v); + break; + case 5: + (r = v), (g = p), (b = q); + break; + } + + return [r * 255, g * 255, b * 255]; +} \ No newline at end of file diff --git a/src/lib/index.js b/src/lib/index.js deleted file mode 100644 index 856f2b6..0000000 --- a/src/lib/index.js +++ /dev/null @@ -1 +0,0 @@ -// place files you want to import through the `$lib` alias in this folder. diff --git a/src/routes/+page.server.js b/src/routes/+page.server.js new file mode 100644 index 0000000..5829b7e --- /dev/null +++ b/src/routes/+page.server.js @@ -0,0 +1 @@ +export const ssr = false; \ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 5982b0a..d846875 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,2 +1,52 @@ -

Welcome to SvelteKit

-

Visit kit.svelte.dev to read the documentation

+ + +

+ Select Audio File: + +

+

+ Select Cover File: + +

+ + + \ No newline at end of file diff --git a/svelte.config.js b/svelte.config.js index 2ca5922..b9a0894 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,4 +1,5 @@ import adapter from '@sveltejs/adapter-auto'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; /** @type {import('@sveltejs/kit').Config} */ const config = { @@ -7,7 +8,8 @@ const config = { // If your environment is not supported, or you settled on a specific environment, switch out the adapter. // See https://kit.svelte.dev/docs/adapters for more information about adapters. adapter: adapter() - } + }, + preprocess: vitePreprocess() }; export default config;