From e19e78eb79ec6dfcdba93219ca07e21dd3cf8e5d Mon Sep 17 00:00:00 2001 From: numex-admin Date: Thu, 10 Sep 2026 08:58:27 +0000 Subject: [PATCH] =?UTF-8?q?Numex=20yay=C4=B1n:=20=5Fjs=5Fcheck.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _js_check.js | 370 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 _js_check.js diff --git a/_js_check.js b/_js_check.js new file mode 100644 index 0000000..d35ed0f --- /dev/null +++ b/_js_check.js @@ -0,0 +1,370 @@ + + /** + * Numex Codex Resim Düzenleyici + * Saf Canvas API — harici kütüphane yok. + * Modüler yaklaşım: her davranış (durum, canvas, görüntü, filtre, + * kırpma, döndürme, işlemler) kendi küçük nesnesinde toplanır. + */ + (function () { + 'use strict'; + + /* ========================================================== + * 1. DURUM (State) — Uygulamanın tek gerçek kaynağı + * ========================================================== */ + const State = { + originalImage: null, // Orijinal Image nesnesi (yüklenen) + displayImage: null, // Mevcut düzenlenmiş Image (kırp/döndür sonrası) + brightness: 100, // % (100 = nötr) + contrast: 100, // % (100 = nötr) + saturation: 100, // % (100 = nötr) + grayscale: false, // Gri tonlama aktif mi + sepia: false, // Sepia aktif mi + cropMode: false, // Kırpma modu açık mı + + // Orijinal değerlere dönmek için saklanan yedek + backup() { + return { + displayImage: this.displayImage, + brightness: this.brightness, + contrast: this.contrast, + saturation: this.saturation, + grayscale: this.grayscale, + sepia: this.sepia + }; + }, + restore(snapshot) { + this.displayImage = snapshot.displayImage; + this.brightness = snapshot.brightness; + this.contrast = snapshot.contrast; + this.saturation = snapshot.saturation; + this.grayscale = snapshot.grayscale; + this.sepia = snapshot.sepia; + } + }; + + /* ========================================================== + * 2. DOM YARDIMCILARI — Element erişimini tek yerden yönet + * ========================================================== */ + const Dom = { + fileInput: document.getElementById('imageLoader'), + canvas: document.getElementById('imageCanvas'), + ctx: null, + + init() { + this.ctx = this.canvas.getContext('2d'); + } + }; + + /* ========================================================== + * 3. GÖRÜNTÜ (Image) — Yükleme, ayarlama, sıfırlama + * ========================================================== */ + const ImageManager = { + load(file) { + if (!file) return; + const reader = new FileReader(); + reader.onload = (event) => { + const img = new Image(); + img.onload = () => { + State.originalImage = img; + State.displayImage = img; + resetAdjustments(); + CanvasD.setup(img.width, img.height); + Renderer.render(); + }; + img.onerror = () => alert('Resim yüklenemedi! Lütfen geçerli bir resim dosyası seçin.'); + img.src = event.target.result; + }; + reader.readAsDataURL(file); + } + }; + + /* ========================================================== + * 4. CANVAS — Boyut ayarlama ve tuvale çizim + * ========================================================== */ + const CanvasD = { + setup(width, height) { + const maxW = 800, maxH = 600; + let w = width, h = height; + if (w > maxW || h > maxH) { + const ratio = Math.min(maxW / w, maxH / h); + w = Math.round(w * ratio); + h = Math.round(h * ratio); + } + Dom.canvas.width = w; + Dom.canvas.height = h; + }, + get ctx() { return Dom.ctx; } + }; + + /* ========================================================== + * 5. RENDER; — Tüm görsel ayarları uygulayıp tuvale çizer + * ========================================================== */ + const Renderer = { + render() { + const img = State.displayImage; + if (!img) return; + const ctx = CanvasD.ctx; + + // Mevcut kanvas boyutuna resmi sığdır (boyut korunsun) + CanvasD.setup(img.width, img.height); + ctx.clearRect(0, 0, Dom.canvas.width, Dom.canvas.height); + ctx.drawImage(img, 0, 0, Dom.canvas.width, Dom.canvas.height); + + // CSS filtreleri tek seferde birleştirip uygula + let filterString = 'none'; + if (State.brightness !== 100 || State.contrast !== 100 || State.saturation !== 100 + || State.grayscale || State.sepia) { + const parts = []; + parts.push('brightness(' + State.brightness + '%)'); + parts.push('contrast(' + State.contrast + '%)'); + parts.push('saturate(' + State.saturation + '%)'); + if (State.grayscale) parts.push('grayscale(1)'); + if (State.sepia) parts.push('sepia(1)'); + filterString = parts.join(' '); + } + ctx.filter = filterString; + ctx.drawImage(img, 0, 0, Dom.canvas.width, Dom.canvas.height); + ctx.filter = 'none'; // Sonraki çizimleri etkilemesin + } + }; + + /* ========================================================== + * 6. AYARLAR (Filters) — Parlaklık/kontrast/doygunluk + renk filtreleri + * ========================================================== */ + const Adjustments = { + brightness() { State.brightness = +DomBrightness.value; Renderer.render(); }, + contrast() { State.contrast = +DomContrast.value; Renderer.render(); }, + saturation() { State.saturation = +DomSaturation.value; Renderer.render(); }, + toggleGrayscale() { + State.grayscale = !State.grayscale; + if (State.grayscale) State.sepia = false; // ikisi birden olmaz + updateFilterButtons(); + Renderer.render(); + }, + toggleSepia() { + State.sepia = !State.sepia; + if (State.sepia) State.grayscale = false; + updateFilterButtons(); + Renderer.render(); + }, + reset() { + State.brightness = 100; + State.contrast = 100; + State.saturation = 100; + State.grayscale = false; + State.sepia = false; + updateFilterButtons(); + syncSliders(); + Renderer.render(); + } + }; + + /* ========================================================== + * 7. KIRPMA (Crop) — Sürükleme ile bölge seç, naklet + * ========================================================== */ + const Crop = { + startX: 0, startY: 0, endX: 0, endY: 0, + active: false, + + enterMode() { + if (!State.displayImage) { alert('Önce bir resim yükleyin!'); return; } + State.cropMode = true; + this.capture(); + }, + + capture() { + State.cropMode = true; + const rect = Dom.canvas.getBoundingClientRect(); + const scaleX = Dom.canvas.width / rect.width; + const scaleY = Dom.canvas.height / rect.height; + + Dom.canvas.style.cursor = 'crosshair'; + const onMouseDown = (e) => { + this.active = true; + this.startX = (e.clientX - rect.left) * scaleX; + this.startY = (e.clientY - rect.top) * scaleY; + this.endX = this.startX; + this.endY = this.startY; + }; + const onMouseMove = (e) => { + if (!this.active) return; + this.endX = (e.clientX - rect.left) * scaleX; + this.endY = (e.clientY - rect.top) * scaleY; + this.drawOverlay(); + }; + const onMouseUp = () => { + if (!this.active) return; + this.active = false; + Dom.canvas.style.cursor = 'default'; + this.commit(); + Dom.canvas.removeEventListener('mousedown', onMouseDown); + Dom.canvas.removeEventListener('mousemove', onMouseMove); + Dom.canvas.removeEventListener('mouseup', onMouseUp); + }; + + Dom.canvas.addEventListener('mousedown', onMouseDown); + Dom.canvas.addEventListener('mousemove', onMouseMove); + Dom.canvas.addEventListener('mouseup', onMouseUp); + }, + + drawOverlay() { + const ctx = CanvasD.ctx; + ctx.clearRect(0, 0, Dom.canvas.width, Dom.canvas.height); + // Orijinal görüntüyü çiz, sonra seçimi vurgula + ctx.drawImage(State.displayImage, 0, 0, Dom.canvas.width, Dom.canvas.height); + const x = Math.min(this.startX, this.endX); + const y = Math.min(this.startY, this.endY); + const w = Math.abs(this.endX - this.startX); + const h = Math.abs(this.endY - this.startY); + + ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + // Dört kenar boyunca karart + ctx.fillRect(0, 0, Dom.canvas.width, y); + ctx.fillRect(0, y + h, Dom.canvas.width, Dom.canvas.height - (y + h)); + ctx.fillRect(0, y, x, h); + ctx.fillRect(x + w, y, Dom.canvas.width - (x + w), h); + + ctx.strokeStyle = 'rgba(0, 123, 255, 0.9)'; + ctx.lineWidth = 2; + ctx.strokeRect(x, y, w, h); + }, + + commit() { + const x = Math.min(this.startX, this.endX); + const y = Math.min(this.startY, this.endY); + const w = Math.abs(this.endX - this.startX); + const h = Math.abs(this.endY - this.startY); + + if (w < 5 || h < 5) { + Renderer.render(); // Çok küçük seçim → iptal + return; + } + + // Yeni bir offscreen canvas'ta seçilen bölgeyi kırp + const cropCanvas = document.createElement('canvas'); + cropCanvas.width = Math.round(w); + cropCanvas.height = Math.round(h); + const cropCtx = cropCanvas.getContext('2d'); + cropCtx.drawImage(State.displayImage, Math.round(x), Math.round(y), Math.round(w), Math.round(h), 0, 0, Math.round(w), Math.round(h)); + + // Kırpılmış görüntüyü yeni bir Image olarak ayarla + const img = new Image(); + img.onload = () => { + State.displayImage = img; + Renderer.render(); + }; + img.src = cropCanvas.toDataURL(); + State.cropMode = false; + } + }; + + /* ========================================================== + * 8. DÖNDÜRME (Rotate) — 90° adımlarla, resim yeniden örneklenir + * ========================================================== */ + const Rotator = { + rotate(angle) { + if (!State.displayImage) { alert('Önce bir resim yükleyin!'); return; } + const img = State.displayImage; + const rotated = document.createElement('canvas'); + if (angle === 90 || angle === -90) { + rotated.width = img.height; + rotated.height = img.width; + } else { + rotated.width = img.width; + rotated.height = img.height; + } + const rctx = rotated.getContext('2d'); + rctx.translate(rotated.width / 2, rotated.height / 2); + rctx.rotate(angle * Math.PI / 180); + rctx.drawImage(img, -img.width / 2, -img.height / 2); + const result = new Image(); + result.onload = () => { + State.displayImage = result; + Renderer.render(); + }; + result.src = rotated.toDataURL(); + }, + left() { this.rotate(90); }, + right() { this.rotate(-90); } + }; + + /* ========================================================== + * 9. İNDİRME (Export) — Canvas'ı PNG olarak kaydet + * ========================================================== */ + const Export = { + download() { + if (!State.displayImage) { alert('Önce bir resim yükleyin!'); return; } + const link = document.createElement('a'); + link.download = 'duzenlenmis-resim.png'; + link.href = Dom.canvas.toDataURL('image/png'); + link.click(); + }, + reset() { + if (!State.originalImage) { alert('Henüz resim yüklenmedi, sıfırlanacak bir şey yok.'); return; } + State.displayImage = State.originalImage; + resetAdjustments(); + Renderer.render(); + } + }; + + /* ========================================================== + * 10. SLAYT SENKRON VE SIFIRLAMA YARDIMCILARI + * ========================================================== */ + const DomBrightness = document.getElementById('brightness'); + const DomContrast = document.getElementById('contrast'); + const DomSaturation = document.getElementById('saturation'); + + function resetAdjustments() { + State.brightness = 100; + State.contrast = 100; + State.saturation = 100; + State.grayscale = false; + State.sepia = false; + updateFilterButtons(); + syncSliders(); + } + function updateFilterButtons() { + const gBtn = document.getElementById('grayscaleBtn'); + const sBtn = document.getElementById('sepiaBtn'); + gBtn.classList.toggle('active-filter', State.grayscale); + sBtn.classList.toggle('active-filter', State.sepia); + } + function syncSliders() { + DomBrightness.value = State.brightness; + DomContrast.value = State.contrast; + DomSaturation.value = State.saturation; + } + + /* ========================================================== + * 11. OLAY BAĞLANTILARI (Event Wiring) + * ========================================================== */ + function wireEvents() { + Dom.fileInput.addEventListener('change', (e) => ImageManager.load(e.target.files[0])); + + document.getElementById('brightness').addEventListener('input', Adjustments.brightness); + document.getElementById('contrast').addEventListener('input', Adjustments.contrast); + document.getElementById('saturation').addEventListener('input', Adjustments.saturation); + + document.getElementById('grayscaleBtn').addEventListener('click', Adjustments.toggleGrayscale); + document.getElementById('sepiaBtn').addEventListener('click', Adjustments.toggleSepia); + document.getElementById('resetFiltersBtn').addEventListener('click', Adjustments.reset); + + document.getElementById('rotateLeftBtn').addEventListener('click', () => Rotator.left()); + document.getElementById('rotateRightBtn').addEventListener('click', () => Rotator.right()); + document.getElementById('cropBtn').addEventListener('click', () => Crop.enterMode()); + + document.getElementById('downloadBtn').addEventListener('click', Export.download); + document.getElementById('resetBtn').addEventListener('click', Export.reset); + } + + /* ========================================================== + * 12. UYGULAMA BAŞLATMA + * ========================================================== */ + function init() { + Dom.init(); + wireEvents(); + } + + document.addEventListener('DOMContentLoaded', init); + })(); + \ No newline at end of file