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
We take content rights seriously. If you suspect this is your content, claim it here.
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
We take content rights seriously. If you suspect this is your content, claim it here.
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