Search bar and adjust contrast
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<div th:fragment="card" class="feature-card" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)}">
|
||||
<div th:fragment="card" class="feature-card" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)}" data-tags="${tags}">
|
||||
<a th:href="${cardLink}">
|
||||
<div class="d-flex align-items-center"> <!-- Add a flex container to align the SVG and title -->
|
||||
<img th:if="${svgPath}" id="card-icon" class="home-card-icon home-card-icon-colour" th:src="${svgPath}" alt="Icon" width="30" height="30">
|
||||
|
||||
@@ -205,6 +205,23 @@
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<!-- Search Button and Search Bar -->
|
||||
<li class="nav-item position-relative">
|
||||
<a href="#" class="nav-link" id="search-icon">
|
||||
<img class="navbar-icon" src="images/search.svg" alt="icon" width="24" height="24">
|
||||
</a>
|
||||
<!-- Search Bar -->
|
||||
<div class="collapse position-absolute" id="navbarSearch">
|
||||
<form class="d-flex p-2 bg-white border" id="searchForm">
|
||||
<input class="form-control" type="search" placeholder="Search" aria-label="Search" id="navbarSearchInput">
|
||||
</form>
|
||||
<!-- Search Results -->
|
||||
<div id="searchResults" class="border p-2 bg-white"></div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -212,6 +229,7 @@
|
||||
|
||||
</div>
|
||||
<script src="js/favourites.js"></script>
|
||||
<script src="js/search.js"></script>
|
||||
</nav>
|
||||
|
||||
<div th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></div>
|
||||
|
||||
@@ -20,8 +20,13 @@
|
||||
</div>
|
||||
<br class="d-md-none">
|
||||
<!-- Features -->
|
||||
<div class="features-container container">
|
||||
|
||||
<script src="js/homecard.js"></script>
|
||||
|
||||
<div class=" container">
|
||||
<input type="text" id="searchBar" onkeyup="filterCards()" placeholder="Search for features...">
|
||||
<div class="features-container ">
|
||||
|
||||
|
||||
<div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg')}"></div>
|
||||
|
||||
<div th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', svgPath='images/tools.svg')}"></div>
|
||||
@@ -70,13 +75,13 @@
|
||||
|
||||
<div th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', svgPath='images/add-page-numbers.svg')}"></div>
|
||||
<div th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', svgPath='images/fonts.svg')}"></div>
|
||||
|
||||
<div th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', svgPath='images/adjust-contrast.svg')}"></div>
|
||||
|
||||
|
||||
|
||||
<script src="js/homecard.js"></script>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div> </div>
|
||||
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -13,15 +13,215 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 th:text="#{extractImages.header}"></h2>
|
||||
<input type="file" id="pdf-file" accept="application/pdf" />
|
||||
<canvas id="pdf-canvas"></canvas>
|
||||
|
||||
<form id="multiPdfForm" th:action="@{adjust-contrast}" method="post" enctype="multipart/form-data">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
|
||||
<div class="form-group">
|
||||
<label for="contrastRange">Contrast</label>
|
||||
<input name="contrastRange" type="range" class="form-control-range" id="contrastRange" min="-100" max="100" value="0" step="1">
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{extractImages.submit}"></button>
|
||||
</form>
|
||||
<h4>Contrast: <span id="contrast-val">100</span>%</h4>
|
||||
<input type="range" min="0" max="200" value="100" id="contrast-slider" />
|
||||
|
||||
<h4>Brightness: <span id="brightness-val">100</span>%</h4>
|
||||
<input type="range" min="0" max="200" value="100" id="brightness-slider" />
|
||||
|
||||
<h4>Saturation: <span id="saturation-val">100</span>%</h4>
|
||||
<input type="range" min="0" max="200" value="100" id="saturation-slider" />
|
||||
|
||||
<button id="download-button">Download</button>
|
||||
|
||||
<script src="pdfjs/pdf.js"></script>
|
||||
<script>
|
||||
var canvas = document.getElementById('pdf-canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
var originalImageData = null;
|
||||
|
||||
function renderPDFAndSaveOriginalImageData(file) {
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
var data = new Uint8Array(this.result);
|
||||
pdfjsLib.getDocument({data: data}).promise.then(function(pdf) {
|
||||
pdf.getPage(1).then(function(page) {
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale });
|
||||
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
viewport: viewport
|
||||
};
|
||||
|
||||
var renderTask = page.render(renderContext);
|
||||
renderTask.promise.then(function () {
|
||||
originalImageData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function adjustImageProperties() {
|
||||
var contrast = parseFloat(document.getElementById('contrast-slider').value);
|
||||
var brightness = parseFloat(document.getElementById('brightness-slider').value);
|
||||
var saturation = parseFloat(document.getElementById('saturation-slider').value);
|
||||
|
||||
contrast /= 100; // normalize to range [0, 2]
|
||||
brightness /= 100; // normalize to range [0, 2]
|
||||
saturation /= 100; // normalize to range [0, 2]
|
||||
|
||||
if (originalImageData) {
|
||||
var newImageData = context.createImageData(originalImageData.width, originalImageData.height);
|
||||
newImageData.data.set(originalImageData.data);
|
||||
|
||||
for(var i=0; i<newImageData.data.length; i+=4)
|
||||
{
|
||||
var r = newImageData.data[i];
|
||||
var g = newImageData.data[i+1];
|
||||
var b = newImageData.data[i+2];
|
||||
// Adjust contrast
|
||||
r = adjustContrastForPixel(r, contrast);
|
||||
g = adjustContrastForPixel(g, contrast);
|
||||
b = adjustContrastForPixel(b, contrast);
|
||||
// Adjust brightness
|
||||
r = adjustBrightnessForPixel(r, brightness);
|
||||
g = adjustBrightnessForPixel(g, brightness);
|
||||
b = adjustBrightnessForPixel(b, brightness);
|
||||
// Adjust saturation
|
||||
if(i==100){
|
||||
console.log('r',r)
|
||||
console.log('g',g)
|
||||
console.log('b',b)
|
||||
console.log('saturation',saturation)
|
||||
}
|
||||
var rgb = adjustSaturationForPixel(r, g, b, saturation);
|
||||
if(i==100){
|
||||
console.log('rgb',rgb)
|
||||
}
|
||||
newImageData.data[i] = rgb[0];
|
||||
newImageData.data[i+1] = rgb[1];
|
||||
newImageData.data[i+2] = rgb[2];
|
||||
}
|
||||
|
||||
context.putImageData(newImageData, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function rgbToHsl(r, g, b) {
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2;
|
||||
|
||||
if (max === min) {
|
||||
h = s = 0; // achromatic
|
||||
} else {
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
|
||||
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, s, l];
|
||||
}
|
||||
|
||||
function hslToRgb(h, s, l) {
|
||||
var r, g, b;
|
||||
|
||||
if (s === 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
var hue2rgb = function hue2rgb(p, q, t) {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
|
||||
r = hue2rgb(p, q, h + 1 / 3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1 / 3);
|
||||
}
|
||||
|
||||
return [r * 255, g * 255, b * 255];
|
||||
}
|
||||
|
||||
function adjustContrastForPixel(pixel, contrast) {
|
||||
// Normalize to range [-0.5, 0.5]
|
||||
var normalized = pixel / 255 - 0.5;
|
||||
|
||||
// Apply contrast
|
||||
normalized *= contrast;
|
||||
|
||||
// Denormalize back to [0, 255]
|
||||
return (normalized + 0.5) * 255;
|
||||
}
|
||||
function clamp(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
|
||||
function adjustSaturationForPixel(r, g, b, saturation) {
|
||||
var hsl = rgbToHsl(r, g, b);
|
||||
|
||||
// Adjust saturation
|
||||
hsl[1] = clamp(hsl[1] * saturation, 0, 1);
|
||||
|
||||
// Convert back to RGB
|
||||
var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
|
||||
|
||||
// Return adjusted RGB values
|
||||
return rgb;
|
||||
}
|
||||
|
||||
function adjustBrightnessForPixel(pixel, brightness) {
|
||||
return Math.max(0, Math.min(255, pixel * brightness));
|
||||
}
|
||||
|
||||
function downloadImage() {
|
||||
var downloadLink = document.createElement('a');
|
||||
downloadLink.href = canvas.toDataURL('image/png');
|
||||
downloadLink.download = 'download.png';
|
||||
downloadLink.click();
|
||||
}
|
||||
|
||||
// Event listeners
|
||||
document.getElementById('pdf-file').addEventListener('change', function(e) {
|
||||
if (e.target.files.length > 0) {
|
||||
renderPDFAndSaveOriginalImageData(e.target.files[0]);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('contrast-slider').addEventListener('input', function() {
|
||||
document.getElementById('contrast-val').textContent = this.value;
|
||||
adjustImageProperties();
|
||||
});
|
||||
|
||||
document.getElementById('brightness-slider').addEventListener('input', function() {
|
||||
document.getElementById('brightness-val').textContent = this.value;
|
||||
adjustImageProperties();
|
||||
});
|
||||
|
||||
document.getElementById('saturation-slider').addEventListener('input', function() {
|
||||
document.getElementById('saturation-val').textContent = this.value;
|
||||
adjustImageProperties();
|
||||
});
|
||||
|
||||
document.getElementById('download-button').addEventListener('click', function() {
|
||||
downloadImage();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user