0% found this document useful (0 votes)
8 views

htmlviewer.html (2)

The document outlines the structure and design of a web-based image compression tool called 'Image Compressor Pro'. It allows users to upload images, adjust compression quality, and preview the results without uploading files to a server, ensuring privacy and speed. The tool features a user-friendly interface with sections for uploading images, displaying previews, and providing information about the compression process.

Uploaded by

usastoryshorts
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

htmlviewer.html (2)

The document outlines the structure and design of a web-based image compression tool called 'Image Compressor Pro'. It allows users to upload images, adjust compression quality, and preview the results without uploading files to a server, ensuring privacy and speed. The tool features a user-friendly interface with sections for uploading images, displaying previews, and providing information about the compression process.

Uploaded by

usastoryshorts
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 14

<!

DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-
scale=1.0, user-scalable=no">
<title>Image Compressor Pro | Free Online Tool</title>
<meta name="description" content="Free online tool to compress and resize images
without losing quality. Works completely in your browser - no server upload
needed.">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-
awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: #4f46e5;
--primary-light: #6366f1;
--dark: #1e293b;
--light: #f8fafc;
--gray: #94a3b8;
--border-radius: 12px;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0,
0.06);
--transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

* {
margin: 0;
padding: 0;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}

html, body {
touch-action: manipulation;
overflow-x: hidden;
}

body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background-color: #f1f5f9;
color: var(--dark);
line-height: 1.5;
min-height: 100vh;
display: flex;
flex-direction: column;
}

/* Header/Navigation */
header {
background-color: white;
box-shadow: var(--shadow);
position: sticky;
top: 0;
z-index: 100;
}

nav {
max-width: 1200px;
margin: 0 auto;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
}

.logo {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary);
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
}

.logo i {
font-size: 1.8rem;
}

/* Hero Section */
.hero {
text-align: center;
padding: 4rem 2rem;
background: linear-gradient(135deg, #f5f7ff 0%, #e2e8ff 100%);
}

.hero h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
color: var(--primary);
}

.hero p {
font-size: 1.2rem;
color: var(--dark);
max-width: 700px;
margin: 0 auto 2rem;
}

/* Main App Container */


.container {
max-width: 800px;
margin: 2rem auto;
padding: 0 2rem;
flex: 1;
}

.card {
background: white;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
padding: 2rem;
margin-bottom: 2rem;
}

/* Upload Area */
.upload-area {
border: 2px dashed #cbd5e1;
border-radius: var(--border-radius);
padding: 2.5rem 1rem;
text-align: center;
cursor: pointer;
transition: var(--transition);
margin-bottom: 1.5rem;
position: relative;
}

.upload-area:hover {
border-color: var(--primary-light);
background-color: rgba(99, 102, 241, 0.03);
}

.upload-area.highlight {
border-color: var(--primary);
background-color: rgba(79, 70, 229, 0.05);
}

.upload-icon {
font-size: 2.5rem;
color: var(--primary-light);
margin-bottom: 1rem;
}

.upload-text {
font-weight: 600;
margin-bottom: 0.5rem;
}

.upload-hint {
color: var(--gray);
font-size: 0.875rem;
}

#fileInput {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0;
cursor: pointer;
}

/* Controls */
.controls {
display: none;
animation: fadeIn 0.4s ease-out;
}

.control-group {
margin-bottom: 1.5rem;
}

.slider-container {
margin-top: 0.5rem;
}
.slider-header {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}

.slider-label {
font-weight: 500;
font-size: 0.9375rem;
}

.slider-value {
font-weight: 600;
color: var(--primary);
}

.range-slider {
width: 100%;
height: 6px;
-webkit-appearance: none;
appearance: none;
background: #e2e8f0;
border-radius: 3px;
outline: none;
touch-action: none;
}

.range-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
background: var(--primary);
border-radius: 50%;
cursor: pointer;
transition: var(--transition);
}

.range-slider::-webkit-slider-thumb:hover {
transform: scale(1.15);
background: var(--primary-light);
}

/* Preview Section */
.preview-container {
display: none;
margin-top: 1.5rem;
animation: fadeIn 0.4s ease-out;
}

.preview-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}

.preview-title {
font-weight: 600;
font-size: 1.125rem;
}

.preview-frame {
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: var(--shadow);
margin-bottom: 1.5rem;
background: #f8fafc;
display: flex;
justify-content: center;
align-items: center;
height: 300px; /* Fixed height for preview */
border: 1px solid #e2e8f0;
position: relative;
}

#previewCanvas {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
display: block;
object-fit: contain;
}

.file-info {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}

.info-card {
background: #f8fafc;
border-radius: 8px;
padding: 1rem;
text-align: center;
border: 1px solid #e2e8f0;
}

.info-label {
font-size: 0.8125rem;
color: var(--gray);
margin-bottom: 0.25rem;
}

.info-value {
font-weight: 600;
color: var(--dark);
font-size: 0.9375rem;
}

/* Buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--primary);
color: white;
padding: 0.75rem 1.25rem;
border-radius: 8px;
text-decoration: none;
font-weight: 500;
border: none;
cursor: pointer;
transition: var(--transition);
width: 100%;
font-size: 1rem;
}

.btn:hover {
background: var(--primary-light);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.2);
}

.btn i {
margin-right: 8px;
}

#downloadBtn {
display: none;
}

/* Spinner */
.spinner {
display: none;
width: 2.5rem;
height: 2.5rem;
margin: 1rem auto;
border: 3px solid rgba(79, 70, 229, 0.1);
border-radius: 50%;
border-top-color: var(--primary);
animation: spin 1s linear infinite;
}

/* Features Section */
.features {
max-width: 1200px;
margin: 4rem auto;
padding: 0 2rem;
}

.features h2 {
text-align: center;
font-size: 2rem;
margin-bottom: 2rem;
color: var(--primary);
}

.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}

.feature-card {
background: white;
border-radius: var(--border-radius);
padding: 2rem;
box-shadow: var(--shadow);
text-align: center;
}

.feature-icon {
font-size: 2.5rem;
color: var(--primary);
margin-bottom: 1rem;
}

.feature-card h3 {
margin-bottom: 1rem;
color: var(--dark);
}

/* Footer */
footer {
background: var(--dark);
color: white;
text-align: center;
padding: 2rem;
margin-top: auto;
}

.footer-content {
max-width: 1200px;
margin: 0 auto;
}

.footer-links {
display: flex;
justify-content: center;
gap: 2rem;
margin: 1rem 0;
}

.footer-links a {
color: white;
text-decoration: none;
transition: var(--transition);
}

.footer-links a:hover {
color: var(--primary-light);
}

.copyright {
color: var(--gray);
font-size: 0.875rem;
}

/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes spin {
to { transform: rotate(360deg); }
}

/* Responsive adjustments */
@media (max-width: 768px) {
.hero h1 {
font-size: 2rem;
}

.hero p {
font-size: 1rem;
}

.card {
padding: 1.5rem;
}

.features-grid {
grid-template-columns: 1fr;
}

.preview-frame {
height: 250px; /* Slightly smaller on mobile */
}
}

@media (max-width: 480px) {


nav {
padding: 1rem;
}

.hero {
padding: 3rem 1rem;
}

.container {
padding: 0 1rem;
}

.upload-area {
padding: 2rem 1rem;
}

.file-info {
grid-template-columns: 1fr;
}

.footer-links {
flex-direction: column;
gap: 1rem;
}

.preview-frame {
height: 200px; /* Even smaller on very small devices */
}
}
</style>
</head>
<body>
<!-- Header with Navigation -->
<header>
<nav>
<a href="#" class="logo">
<i class="fas fa-compress-alt"></i>
<span>ImageCompressor Pro</span>
</a>
</nav>
</header>

<!-- Hero Section -->


<section class="hero">
<h1>Free Online Image Compressor</h1>
<p>Reduce image file size without losing quality. Works completely in your
browser - no server upload needed.</p>
</section>

<!-- Main App Container -->


<main class="container">
<div class="card">
<div class="upload-area" id="uploadArea">
<div class="upload-icon">
<i class="fas fa-cloud-upload-alt"></i>
</div>
<h3 class="upload-text">Upload your image</h3>
<p class="upload-hint">Drag & drop or click to browse (JPEG, PNG, WEBP)</p>
<input type="file" id="fileInput" accept="image/*">
</div>

<div class="spinner" id="spinner"></div>

<div class="controls" id="controls">


<div class="control-group">
<div class="slider-header">
<span class="slider-label">Compression Quality</span>
<span class="slider-value" id="qualityValue">100%</span>
</div>
<div class="slider-container">
<input type="range" class="range-slider" id="qualitySlider" min="20"
max="100" value="100" step="1">
</div>
</div>
</div>

<div class="preview-container" id="previewContainer">


<div class="preview-header">
<h3 class="preview-title">Preview</h3>
<div class="file-size">
<span id="fileSizeValue">-</span>
</div>
</div>

<div class="preview-frame">
<canvas id="previewCanvas"></canvas>
</div>

<div class="file-info">
<div class="info-card">
<div class="info-label">Original Dimensions</div>
<div class="info-value" id="originalDimensions">-</div>
</div>
<div class="info-card">
<div class="info-label">New Dimensions</div>
<div class="info-value" id="newDimensions">-</div>
</div>
<div class="info-card">
<div class="info-label">Size Reduction</div>
<div class="info-value" id="reductionValue">-</div>
</div>
</div>
</div>

<button class="btn" id="downloadBtn">


<i class="fas fa-download"></i> Download Compressed Image
</button>
</div>
</main>

<!-- Features Section -->


<section class="features">
<h2>Why Use Our Image Compressor?</h2>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">
<i class="fas fa-shield-alt"></i>
</div>
<h3>Privacy Focused</h3>
<p>All processing happens in your browser. Your images never leave your
device.</p>
</div>
<div class="feature-card">
<div class="feature-icon">
<i class="fas fa-bolt"></i>
</div>
<h3>Lightning Fast</h3>
<p>Compress images in seconds with our optimized processing engine.</p>
</div>
<div class="feature-card">
<div class="feature-icon">
<i class="fas fa-chart-line"></i>
</div>
<h3>Quality Control</h3>
<p>Adjust compression level to find the perfect balance between size and
quality.</p>
</div>
</div>
</section>

<!-- Footer -->


<footer>
<div class="footer-content">
<div class="footer-links">
<a href="#">Home</a>
<a href="#">Privacy Policy</a>
<a href="#">Terms of Service</a>
<a href="#">Contact</a>
</div>
<p class="copyright">© 2023 ImageCompressor Pro. All rights reserved.</p>
</div>
</footer>

<script>
// DOM Elements
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const spinner = document.getElementById('spinner');
const controls = document.getElementById('controls');
const previewContainer = document.getElementById('previewContainer');
const previewCanvas = document.getElementById('previewCanvas');
const previewCtx = previewCanvas.getContext('2d');
const qualitySlider = document.getElementById('qualitySlider');
const qualityValue = document.getElementById('qualityValue');
const originalDimensions = document.getElementById('originalDimensions');
const newDimensions = document.getElementById('newDimensions');
const reductionValue = document.getElementById('reductionValue');
const fileSizeValue = document.getElementById('fileSizeValue');
const downloadBtn = document.getElementById('downloadBtn');

// Variables
let originalImage = new Image();
let originalWidth = 0;
let originalHeight = 0;
let originalSize = 0;
let processing = false;

// Disable zooming via touch gestures


document.addEventListener('gesturestart', function(e) {
e.preventDefault();
});

// Initialize
initEventListeners();

function initEventListeners() {
// File input handling
fileInput.addEventListener('change', handleFileSelect);

// Quality slider - use both input and change events


qualitySlider.addEventListener('input', handleSliderInput);
qualitySlider.addEventListener('change', handleSliderChange);

// Download button
downloadBtn.addEventListener('click', downloadImage);

// Drag and drop


uploadArea.addEventListener('dragover', handleDragOver);
uploadArea.addEventListener('dragleave', handleDragLeave);
uploadArea.addEventListener('drop', handleDrop);
}

function handleFileSelect(event) {
const file = event.target.files[0];
if (!file || !file.type.match('image.*')) return;

startProcessing();
originalSize = file.size;
const reader = new FileReader();

reader.onload = function(e) {
originalImage.onload = function() {
originalWidth = originalImage.naturalWidth;
originalHeight = originalImage.naturalHeight;

// Show original dimensions immediately


originalDimensions.textContent = `${originalWidth} × ${originalHeight}`;

// Process initial image


processImage(true);
finishProcessing();
};
originalImage.src = e.target.result;
};

reader.readAsDataURL(file);
}

function processImage(updateDownload = false) {


const quality = parseInt(qualitySlider.value) / 100;
const newWidth = Math.round(originalWidth * quality);
const newHeight = Math.round(originalHeight * quality);

// Update dimensions display


newDimensions.textContent = `${newWidth} × ${newHeight}`;

// Calculate dimensions to fit in our fixed preview area


const previewWidth = previewCanvas.parentElement.clientWidth - 40;
const previewHeight = previewCanvas.parentElement.clientHeight - 40;
let displayWidth = newWidth;
let displayHeight = newHeight;

// Scale down if needed to fit preview area


if (displayWidth > previewWidth || displayHeight > previewHeight) {
const ratio = Math.min(previewWidth / displayWidth, previewHeight /
displayHeight);
displayWidth = displayWidth * ratio;
displayHeight = displayHeight * ratio;
}

// Set canvas dimensions (actual processing uses full size)


previewCanvas.width = displayWidth;
previewCanvas.height = displayHeight;

// Draw scaled image for preview


previewCtx.clearRect(0, 0, displayWidth, displayHeight);
previewCtx.drawImage(originalImage, 0, 0, newWidth, newHeight, 0, 0,
displayWidth, displayHeight);

// Only update download URL on final processing (not during live updates)
if (updateDownload) {
// Create a temporary canvas for the actual download
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = newWidth;
tempCanvas.height = newHeight;
tempCtx.drawImage(originalImage, 0, 0, newWidth, newHeight);

const dataUrl = tempCanvas.toDataURL('image/jpeg', 0.85);


downloadBtn.setAttribute('data-url', dataUrl);

// Calculate file size


const base64Length = dataUrl.length - 'data:image/jpeg;base64,'.length;
const sizeInKB = (base64Length * 3 / 4) / 1024;

// Update UI
fileSizeValue.textContent = `${sizeInKB.toFixed(1)} KB`;
const reduction = ((originalSize / 1024 - sizeInKB) / (originalSize / 1024)
* 100).toFixed(1);
reductionValue.textContent = `${reduction}%`;
}
}

function handleSliderInput() {
const quality = qualitySlider.value;
qualityValue.textContent = `${quality}%`;

// Update preview in real-time without updating download URL


if (!processing) {
processImage(false);
}
}

function handleSliderChange() {
if (!processing) {
processing = true;
setTimeout(() => {
// Final processing with download URL update
processImage(true);
processing = false;
}, 100);
}
}

function downloadImage() {
const dataUrl = downloadBtn.getAttribute('data-url');
if (!dataUrl) return;

const link = document.createElement('a');


link.href = dataUrl;
link.download = `compressed-image-${qualitySlider.value}q.jpg`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}

// Drag and drop handlers


function handleDragOver(e) {
e.preventDefault();
uploadArea.classList.add('highlight');
}

function handleDragLeave() {
uploadArea.classList.remove('highlight');
}

function handleDrop(e) {
e.preventDefault();
uploadArea.classList.remove('highlight');

if (e.dataTransfer.files.length) {
fileInput.files = e.dataTransfer.files;
handleFileSelect({ target: fileInput });
}
}

// Processing state handlers


function startProcessing() {
processing = true;
spinner.style.display = 'block';
controls.style.display = 'none';
previewContainer.style.display = 'none';
downloadBtn.style.display = 'none';
}

function finishProcessing() {
processing = false;
spinner.style.display = 'none';
controls.style.display = 'block';
previewContainer.style.display = 'block';
downloadBtn.style.display = 'flex';
}
</script>
</body>
</html>

You might also like