From 3f163d9aa380000a6701c052f389470a8c97c5a3 Mon Sep 17 00:00:00 2001 From: Rodrigo Martins Date: Wed, 1 Jan 2025 22:44:05 -0300 Subject: [PATCH] Estiliza pagina de upload externo - responsiva (novo47) --- document_history.php | 85 ++++ document_processor.php | 915 +++++++++++++++++++++++++++++++++++++++++ index.php | 4 + menu.php | 9 +- process_document.php | 85 ++++ style.css | 47 +++ 6 files changed, 1144 insertions(+), 1 deletion(-) create mode 100644 document_history.php create mode 100644 document_processor.php create mode 100644 process_document.php diff --git a/document_history.php b/document_history.php new file mode 100644 index 0000000..5681ca4 --- /dev/null +++ b/document_history.php @@ -0,0 +1,85 @@ +connect_error) { + die("Connection failed: " . $mysqli->connect_error); +} + +// Buscar histórico de documentos processados +$query = "SELECT pd.*, u.username FROM processed_documents pd + LEFT JOIN users u ON pd.user_id = u.id + ORDER BY pd.created_at DESC"; +$result = $mysqli->query($query); +?> + +
+

Histórico de Documentos Processados

+ + + + + + + + + + + + + fetch_assoc()): ?> + + + + + + + + + +
Data/HoraUsuárioDocumento OriginalDocumento ProcessadoAções
+ + Ver Original + + + + Ver Processado + + + +
+
+ + diff --git a/document_processor.php b/document_processor.php new file mode 100644 index 0000000..971ba82 --- /dev/null +++ b/document_processor.php @@ -0,0 +1,915 @@ +outputPath = $outputPath; + + // Detecta o tipo da imagem e carrega + $imageInfo = getimagesize($imagePath); + if ($imageInfo === false) { + throw new Exception('Failed to load image'); + } + + switch ($imageInfo[2]) { + case IMAGETYPE_JPEG: + $this->srcImage = imagecreatefromjpeg($imagePath); + break; + case IMAGETYPE_PNG: + $this->srcImage = imagecreatefrompng($imagePath); + break; + default: + throw new Exception('Unsupported image type'); + } + + if ($this->srcImage === false) { + throw new Exception('Failed to create image resource'); + } + + // Analisa qualidade da imagem e define parâmetros + $this->analyzeImageQuality() + ->determineOptimalParameters(); + + // Pipeline de processamento adaptativo + $this->detectAndCropDocument() + ->convertToGrayscale() + ->applyAdaptiveEnhancements() + ->saveResult(); + + return $this->outputPath; + } + + private function detectAndCropDocument() { + $width = imagesx($this->srcImage); + $height = imagesy($this->srcImage); + + // Cria cópia para processamento + $work = imagecreatetruecolor($width, $height); + imagecopy($work, $this->srcImage, 0, 0, 0, 0, $width, $height); + + // Pré-processamento para melhorar detecção + imagefilter($work, IMG_FILTER_GAUSSIAN_BLUR); + imagefilter($work, IMG_FILTER_GRAYSCALE); + + // Detecta bordas usando Sobel + $edges = $this->detectEdgesSobel($work); + + // Encontra pontos de contorno + $contourPoints = []; + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $rgb = imagecolorat($edges, $x, $y); + if ($rgb > 0) { + $contourPoints[] = [$x, $y]; + } + } + } + + // Encontra os 4 cantos do documento + $corners = $this->findCornerPoints($contourPoints); + + if ($corners) { + // Aplica transformação perspectiva + $this->processedImage = $this->cropAndTransform($this->srcImage, $corners); + } else { + $this->processedImage = $this->srcImage; + } + + imagedestroy($work); + imagedestroy($edges); + + return $this; + } + + private function detectEdgesSobel($image) { + $width = imagesx($image); + $height = imagesy($image); + $edges = imagecreatetruecolor($width, $height); + + // Kernels Sobel + $sobelX = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]; + $sobelY = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]]; + + for ($x = 1; $x < $width-1; $x++) { + for ($y = 1; $y < $height-1; $y++) { + $pixelX = $pixelY = 0; + + // Aplica kernels + for ($i = -1; $i <= 1; $i++) { + for ($j = -1; $j <= 1; $j++) { + $rgb = imagecolorat($image, $x + $i, $y + $j); + $colors = imagecolorsforindex($image, $rgb); + $gray = $colors['red']; + + $pixelX += $gray * $sobelX[$i+1][$j+1]; + $pixelY += $gray * $sobelY[$i+1][$j+1]; + } + } + + // Magnitude do gradiente + $magnitude = min(255, sqrt($pixelX * $pixelX + $pixelY * $pixelY)); + + // Aplica threshold para reduzir ruído + $magnitude = ($magnitude > 50) ? 255 : 0; + + $color = imagecolorallocate($edges, $magnitude, $magnitude, $magnitude); + imagesetpixel($edges, $x, $y, $color); + } + } + + return $edges; + } + + private function findDocumentBounds($binary) { + $width = imagesx($binary); + $height = imagesy($binary); + $left = $width; + $right = 0; + $top = $height; + $bottom = 0; + + // Encontra os limites do documento + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $rgb = imagecolorat($binary, $x, $y); + if ($rgb == 0) { // Pixel preto + $left = min($left, $x); + $right = max($right, $x); + $top = min($top, $y); + $bottom = max($bottom, $y); + } + } + } + + if ($left < $right && $top < $bottom) { + return [ + 'left' => $left, + 'right' => $right, + 'top' => $top, + 'bottom' => $bottom + ]; + } + + return null; + } + + private function isEdgePoint($img, $x, $y) { + $threshold = 30; + + // Verifica pixels vizinhos + $center = $this->getPixelIntensity($img, $x, $y); + $left = $this->getPixelIntensity($img, $x - 1, $y); + $right = $this->getPixelIntensity($img, $x + 1, $y); + $top = $this->getPixelIntensity($img, $x, $y - 1); + $bottom = $this->getPixelIntensity($img, $x, $y + 1); + + return (abs($center - $left) > $threshold || + abs($center - $right) > $threshold || + abs($center - $top) > $threshold || + abs($center - $bottom) > $threshold); + } + + private function getPixelIntensity($img, $x, $y) { + if ($x < 0 || $y < 0 || $x >= imagesx($img) || $y >= imagesy($img)) { + return 0; + } + + $rgb = imagecolorat($img, $x, $y); + $colors = imagecolorsforindex($img, $rgb); + return ($colors['red'] + $colors['green'] + $colors['blue']) / 3; + } + + private function findCornerPoints($points) { + // Encontra os pontos mais extremos + $topLeft = null; + $topRight = null; + $bottomLeft = null; + $bottomRight = null; + $minSum = PHP_FLOAT_MAX; + $maxSum = PHP_FLOAT_MIN; + $minDiff = PHP_FLOAT_MAX; + $maxDiff = PHP_FLOAT_MIN; + + foreach ($points as $point) { + $sum = $point[0] + $point[1]; + $diff = $point[0] - $point[1]; + + if ($sum < $minSum) { + $minSum = $sum; + $topLeft = $point; + } + if ($sum > $maxSum) { + $maxSum = $sum; + $bottomRight = $point; + } + if ($diff < $minDiff) { + $minDiff = $diff; + $bottomLeft = $point; + } + if ($diff > $maxDiff) { + $maxDiff = $diff; + $topRight = $point; + } + } + + if ($topLeft && $topRight && $bottomLeft && $bottomRight) { + return [$topLeft, $topRight, $bottomRight, $bottomLeft]; + } + + return null; + } + + private function cropAndTransform($img, $corners) { + $width = abs($corners[1][0] - $corners[0][0]); + $height = abs($corners[3][1] - $corners[0][1]); + + $dest = imagecreatetruecolor($width, $height); + + // Preserva transparência + imagealphablending($dest, false); + imagesavealpha($dest, true); + + // Define pontos de destino + $dest_points = [ + 0, 0, + $width - 1, 0, + $width - 1, $height - 1, + 0, $height - 1 + ]; + + // Define pontos de origem + $src_points = []; + foreach ($corners as $corner) { + $src_points[] = $corner[0]; + $src_points[] = $corner[1]; + } + + // Aplica transformação perspectiva + imagecopyresampled( + $dest, $img, + 0, 0, min($src_points[0], $src_points[6]), min($src_points[1], $src_points[3]), + $width, $height, + max($src_points[2], $src_points[4]) - min($src_points[0], $src_points[6]), + max($src_points[5], $src_points[7]) - min($src_points[1], $src_points[3]) + ); + + return $dest; + } + + private function convertToGrayscale() { + if (!isset($this->processedImage)) { + $this->processedImage = $this->srcImage; + } + + imagefilter($this->processedImage, IMG_FILTER_GRAYSCALE); + return $this; + } + + private function enhanceContrast() { + $width = imagesx($this->processedImage); + $height = imagesy($this->processedImage); + + // Calcula histograma + $histogram = array_fill(0, 256, 0); + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $rgb = imagecolorat($this->processedImage, $x, $y); + $colors = imagecolorsforindex($this->processedImage, $rgb); + $histogram[$colors['red']]++; + } + } + + // Encontra limites para stretch + $min = 0; + $max = 255; + $pixelCount = $width * $height; + $cutoffPercent = 0.005; // 0.5% + + $sum = 0; + for ($i = 0; $i < 256; $i++) { + $sum += $histogram[$i]; + if ($sum >= $pixelCount * $cutoffPercent) { + $min = $i; + break; + } + } + + $sum = 0; + for ($i = 255; $i >= 0; $i--) { + $sum += $histogram[$i]; + if ($sum >= $pixelCount * $cutoffPercent) { + $max = $i; + break; + } + } + + // Aplica contrast stretching + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $rgb = imagecolorat($this->processedImage, $x, $y); + $colors = imagecolorsforindex($this->processedImage, $rgb); + $gray = $colors['red']; + + // Normaliza valor + $newGray = ($gray - $min) * (255 / ($max - $min)); + $newGray = min(255, max(0, $newGray)); + + $color = imagecolorallocate($this->processedImage, $newGray, $newGray, $newGray); + imagesetpixel($this->processedImage, $x, $y, $color); + } + } + + return $this; + } + + private function sharpenImage() { + $sharpenMatrix = [ + [-1, -1, -1], + [-1, 16, -1], + [-1, -1, -1] + ]; + + $this->applyConvolution($sharpenMatrix); + + // Ajuste fino pós-sharpening + imagefilter($this->processedImage, IMG_FILTER_CONTRAST, -5); + + return $this; + } + + private function applyConvolution($matrix) { + if (!$this->processedImage) { + return $this; + } + + $width = imagesx($this->processedImage); + $height = imagesy($this->processedImage); + $temp = imagecreatetruecolor($width, $height); + + if (!$temp) { + return $this; + } + + imagecopy($temp, $this->processedImage, 0, 0, 0, 0, $width, $height); + + $matrixSize = count($matrix); + $halfSize = floor($matrixSize / 2); + + for ($x = $halfSize; $x < $width - $halfSize; $x++) { + for ($y = $halfSize; $y < $height - $halfSize; $y++) { + $r = $g = $b = 0; + + for ($i = -$halfSize; $i <= $halfSize; $i++) { + for ($j = -$halfSize; $j <= $halfSize; $j++) { + $rgb = imagecolorat($temp, $x + $i, $y + $j); + $colors = imagecolorsforindex($temp, $rgb); + + $weight = $matrix[$i + $halfSize][$j + $halfSize]; + $r += $colors['red'] * $weight; + $g += $colors['green'] * $weight; + $b += $colors['blue'] * $weight; + } + } + + $r = min(255, max(0, $r)); + $g = min(255, max(0, $g)); + $b = min(255, max(0, $b)); + + $color = imagecolorallocate($this->processedImage, $r, $g, $b); + imagesetpixel($this->processedImage, $x, $y, $color); + } + } + + imagedestroy($temp); + return $this; + } + + private function removeNoise() { + // Aplica filtro mediano + $temp = imagecreatetruecolor(imagesx($this->processedImage), imagesy($this->processedImage)); + imagecopy($temp, $this->processedImage, 0, 0, 0, 0, imagesx($this->processedImage), imagesy($this->processedImage)); + + for ($x = 1; $x < imagesx($this->processedImage) - 1; $x++) { + for ($y = 1; $y < imagesy($this->processedImage) - 1; $y++) { + $values = array(); + // Coleta valores dos pixels vizinhos + for ($i = -1; $i <= 1; $i++) { + for ($j = -1; $j <= 1; $j++) { + $rgb = imagecolorat($temp, $x + $i, $y + $j); + $colors = imagecolorsforindex($temp, $rgb); + $values[] = $colors['red']; + } + } + sort($values); + $median = $values[4]; // Valor mediano + $color = imagecolorallocate($this->processedImage, $median, $median, $median); + imagesetpixel($this->processedImage, $x, $y, $color); + } + } + + imagedestroy($temp); + return $this; + } + + private function adjustBrightnessContrast() { + // Ajustes mais suaves + imagefilter($this->processedImage, IMG_FILTER_BRIGHTNESS, 5); + imagefilter($this->processedImage, IMG_FILTER_CONTRAST, -8); + return $this; + } + + private function normalizeBackground() { + if (!$this->processedImage) { + return $this; + } + + $width = imagesx($this->processedImage); + $height = imagesy($this->processedImage); + + // Corrigir loop infinito na amostragem das bordas + $samples = []; + $borderSize = 10; + + // Amostra pixels das bordas com índice y corrigido + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $borderSize; $y++) { + $rgb = imagecolorat($this->processedImage, $x, $y); + $colors = imagecolorsforindex($this->processedImage, $rgb); + $samples[] = $colors['red']; + } + // Corrigir incremento do y + for ($y = $height - $borderSize; $y < $height; $y++) { + $rgb = imagecolorat($this->processedImage, $x, $y); + $colors = imagecolorsforindex($this->processedImage, $rgb); + $samples[] = $colors['red']; + } + } + + $mean = array_sum($samples) / count($samples); + $stdDev = sqrt(array_sum(array_map(function($x) use ($mean) { + return pow($x - $mean, 2); + }, $samples)) / count($samples)); + + // Normaliza fundo usando estatísticas + $threshold = $mean - ($stdDev * 2.5); + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $rgb = imagecolorat($this->processedImage, $x, $y); + $colors = imagecolorsforindex($this->processedImage, $rgb); + + if ($colors['red'] > $threshold) { + $color = imagecolorallocate($this->processedImage, 255, 255, 255); + imagesetpixel($this->processedImage, $x, $y, $color); + } + } + } + + return $this; + } + + private function saveResult() { + if (!isset($this->processedImage)) { + throw new Exception('No processed image to save'); + } + + $extension = strtolower(pathinfo($this->outputPath, PATHINFO_EXTENSION)); + + switch ($extension) { + case 'jpg': + case 'jpeg': + imagejpeg($this->processedImage, $this->outputPath, 90); + break; + case 'png': + imagepng($this->processedImage, $this->outputPath, 9); + break; + default: + throw new Exception('Unsupported output image type'); + } + + if (is_resource($this->srcImage)) { + imagedestroy($this->srcImage); + } + if (is_resource($this->processedImage)) { + imagedestroy($this->processedImage); + } + + return $this; + } + + private function getAdaptiveThreshold($image) { + $width = imagesx($image); + $height = imagesy($image); + $blockSize = 40; // Tamanho do bloco para threshold adaptativo + $C = 10; // Constante de ajuste + + // Cria imagem para o resultado + $result = imagecreatetruecolor($width, $height); + + // Para cada bloco + for ($x = 0; $x < $width; $x += $blockSize) { + for ($y = 0; $y < $height; $y += $blockSize) { + // Calcula média do bloco + $sum = 0; + $count = 0; + + $blockW = min($blockSize, $width - $x); + $blockH = min($blockSize, $height - $y); + + for ($bx = 0; $bx < $blockW; $bx++) { + for ($by = 0; $by < $blockH; $by++) { + $rgb = imagecolorat($image, $x + $bx, $y + $by); + $colors = imagecolorsforindex($image, $rgb); + $gray = $colors['red']; // Já está em escala de cinza + $sum += $gray; + $count++; + } + } + + // Calcula threshold local + $threshold = ($count > 0) ? ($sum / $count) - $C : 128; + + // Aplica threshold ao bloco + for ($bx = 0; $bx < $blockW; $bx++) { + for ($by = 0; $by < $blockH; $by++) { + $rgb = imagecolorat($image, $x + $bx, $y + $by); + $colors = imagecolorsforindex($image, $rgb); + $gray = $colors['red']; + + if ($gray > $threshold) { + $color = imagecolorallocate($result, 255, 255, 255); + } else { + $color = imagecolorallocate($result, 0, 0, 0); + } + + imagesetpixel($result, $x + $bx, $color); + } + } + } + } + + return $threshold; + } + + private function analyzeImageQuality() { + if (!$this->srcImage) { + $this->imageQualityMetrics = [ + 'brightness' => 0, + 'contrast' => 0, + 'noise' => 0, + 'blur' => 0 + ]; + return $this; + } + + $width = imagesx($this->srcImage); + $height = imagesy($this->srcImage); + + // Inicializa métricas + $this->imageQualityMetrics = [ + 'brightness' => 0, + 'contrast' => 0, + 'noise' => 0, + 'blur' => 0 + ]; + + // Calcula brilho médio e contraste + $histogram = array_fill(0, 256, 0); + $totalPixels = $width * $height; + + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $rgb = imagecolorat($this->srcImage, $x, $y); + $colors = imagecolorsforindex($this->srcImage, $rgb); + $gray = ($colors['red'] + $colors['green'] + $colors['blue']) / 3; + $histogram[(int)$gray]++; + } + } + + // Calcula métricas de qualidade + $this->imageQualityMetrics['brightness'] = $this->calculateAverageBrightness($histogram, $totalPixels); + $this->imageQualityMetrics['contrast'] = $this->calculateImageContrast($histogram, $totalPixels); + $this->imageQualityMetrics['noise'] = $this->estimateImageNoise(); + $this->imageQualityMetrics['blur'] = $this->estimateBlurLevel(); + + return $this; + } + + private function determineOptimalParameters() { + // Define parâmetros baseados nas métricas + $this->processingParams = [ + 'contrast_adjustment' => $this->calculateContrastAdjustment(), + 'brightness_adjustment' => $this->calculateBrightnessAdjustment(), + 'sharpen_intensity' => $this->calculateSharpenIntensity(), + 'noise_reduction' => $this->calculateNoiseReduction() + ]; + + return $this; + } + + private function applyAdaptiveEnhancements() { + if (!$this->processedImage || !isset($this->processingParams)) { + return $this; + } + + // Verificar existência das chaves antes de usar + $brightnessAdjustment = isset($this->processingParams['brightness_adjustment']) ? + (int)$this->processingParams['brightness_adjustment'] : 0; + + $contrastAdjustment = isset($this->processingParams['contrast_adjustment']) ? + (int)$this->processingParams['contrast_adjustment'] : 0; + + $noiseReduction = isset($this->processingParams['noise_reduction']) ? + (int)$this->processingParams['noise_reduction'] : 0; + + $sharpenIntensity = isset($this->processingParams['sharpen_intensity']) ? + (int)$this->processingParams['sharpen_intensity'] : 0; + + // Aplicar ajustes com valores convertidos + if ($brightnessAdjustment !== 0) { + imagefilter($this->processedImage, IMG_FILTER_BRIGHTNESS, $brightnessAdjustment); + } + + if ($contrastAdjustment !== 0) { + imagefilter($this->processedImage, IMG_FILTER_CONTRAST, $contrastAdjustment); + } + + if ($noiseReduction > 0) { + $this->applyAdaptiveNoiseReduction($noiseReduction); + } + + if ($sharpenIntensity > 0) { + $this->applyAdaptiveSharpening($sharpenIntensity); + } + + return $this; + } + + private function calculateAverageBrightness($histogram, $totalPixels) { + $sum = 0; + for ($i = 0; $i < 256; $i++) { + $sum += $i * $histogram[$i]; + } + return $sum / $totalPixels; + } + + private function calculateImageContrast($histogram, $totalPixels) { + $mean = $this->imageQualityMetrics['brightness']; + $variance = 0; + + for ($i = 0; $i < 256; $i++) { + $variance += pow($i - $mean, 2) * ($histogram[$i] / $totalPixels); + } + + return sqrt($variance); + } + + private function estimateImageNoise() { + $width = imagesx($this->srcImage); + $height = imagesy($this->srcImage); + $noise = 0; + $samples = 1000; + + // Amostragem aleatória para estimar ruído + for ($i = 0; $i < $samples; $i++) { + $x = rand(1, $width - 2); + $y = rand(1, $height - 2); + $noise += $this->calculateLocalVariance($x, $y); + } + + return $noise / $samples; + } + + private function estimateBlurLevel() { + if (!$this->processedImage) { + return 0; + } + + // Cria uma cópia temporária para aplicar o Laplaciano + $width = imagesx($this->processedImage); + $height = imagesy($this->processedImage); + $temp = imagecreatetruecolor($width, $height); + + if (!$temp) { + return 0; + } + + imagecopy($temp, $this->processedImage, 0, 0, 0, 0, $width, $height); + + $laplacian = [ + [0, 1, 0], + [1, -4, 1], + [0, 1, 0] + ]; + + $blurValue = $this->applyConvolutionSafe($temp, $laplacian); + imagedestroy($temp); + + return $blurValue; + } + + private function calculateContrastAdjustment() { + $contrast = $this->imageQualityMetrics['contrast']; + $optimal = 128; // Valor ideal de contraste + + if ($contrast < $optimal * 0.7) { + return min(50, (int)((1 - $contrast/$optimal) * 100)); + } elseif ($contrast > $optimal * 1.3) { + return max(-50, (int)(($optimal/$contrast - 1) * 100)); + } + + return 0; + } + + private function calculateBrightnessAdjustment() { + $brightness = $this->imageQualityMetrics['brightness']; + $optimal = 128; // Valor ideal de brilho + + // Forçar conversão explícita para inteiro + return (int)(($optimal - $brightness) * 0.5); + } + + private function calculateSharpenIntensity() { + $blurLevel = $this->imageQualityMetrics['blur']; + return $this->ensureInteger(min(100, $blurLevel * 50)); + } + + private function calculateNoiseReduction() { + $noise = $this->imageQualityMetrics['noise']; + return $this->ensureInteger(min(5, $noise * 2)); + } + + private function calculateLocalVariance($x, $y) { + $values = []; + $windowSize = 3; + $halfWindow = floor($windowSize / 2); + + // Coleta valores na janela + for ($i = -$halfWindow; $i <= $halfWindow; $i++) { + for ($j = -$halfWindow; $j <= $halfWindow; $j++) { + $px = $x + $i; + $py = $y + $j; + + if ($px >= 0 && $px < imagesx($this->srcImage) && + $py >= 0 && $py < imagesy($this->srcImage)) { + $rgb = imagecolorat($this->srcImage, $px, $py); + $colors = imagecolorsforindex($this->srcImage, $rgb); + $values[] = ($colors['red'] + $colors['green'] + $colors['blue']) / 3; + } + } + } + + // Calcula variância local + if (count($values) > 0) { + $mean = array_sum($values) / count($values); + $variance = array_sum(array_map(function($v) use ($mean) { + return pow($v - $mean, 2); + }, $values)) / count($values); + return $variance; + } + + return 0; + } + + private function calculateVariance($image) { + $width = imagesx($image); + $height = imagesy($image); + $values = []; + + // Amostra de pixels para cálculo + $sampleSize = min(1000, $width * $height); + for ($i = 0; $i < $sampleSize; $i++) { + $x = rand(0, $width - 1); + $y = rand(0, $height - 1); + $rgb = imagecolorat($image, $x, $y); + $colors = imagecolorsforindex($image, $rgb); + $values[] = ($colors['red'] + $colors['green'] + $colors['blue']) / 3; + } + + if (count($values) > 0) { + $mean = array_sum($values) / count($values); + return array_sum(array_map(function($v) use ($mean) { + return pow($v - $mean, 2); + }, $values)) / count($values); + } + + return 0; + } + + private function applyAdaptiveNoiseReduction($intensity) { + $width = imagesx($this->processedImage); + $height = imagesy($this->processedImage); + $temp = imagecreatetruecolor($width, $height); + imagecopy($temp, $this->processedImage, 0, 0, 0, 0, $width, $height); + + $windowSize = 2 * $intensity + 1; + $halfWindow = floor($windowSize / 2); + + for ($x = $halfWindow; $x < $width - $halfWindow; $x++) { + for ($y = $halfWindow; $y < $height - $halfWindow; $y++) { + $values = []; + + for ($i = -$halfWindow; $i <= $halfWindow; $i++) { + for ($j = -$halfWindow; $j <= $halfWindow; $j++) { + $rgb = imagecolorat($temp, $x + $i, $y + $j); + $colors = imagecolorsforindex($temp, $rgb); + $values[] = $colors['red']; + } + } + + sort($values); + $median = $values[count($values) / 2]; + $color = imagecolorallocate($this->processedImage, $median, $median, $median); + imagesetpixel($this->processedImage, $x, $y, $color); + } + } + + imagedestroy($temp); + return $this; + } + + private function applyAdaptiveSharpening($intensity) { + $matrix = [ + [-1, -1, -1], + [-1, 8 + $intensity, -1], + [-1, -1, -1] + ]; + + $this->applyConvolution($matrix); + return $this; + } + + private function applyConvolutionSafe($image, $matrix) { + if (!$image) { + return 0; + } + + $width = imagesx($image); + $height = imagesy($image); + $temp = imagecreatetruecolor($width, $height); + + if (!$temp) { + return 0; + } + + imagecopy($temp, $image, 0, 0, 0, 0, $width, $height); + $variance = 0; + + $matrixSize = count($matrix); + $halfSize = floor($matrixSize / 2); + + // Calcula apenas uma amostra para performance + $sampleSize = min(1000, $width * $height); + $values = []; + + for ($i = 0; $i < $sampleSize; $i++) { + $x = rand($halfSize, $width - $halfSize - 1); + $y = rand($halfSize, $height - $halfSize - 1); + + $sum = 0; + for ($mx = -$halfSize; $mx <= $halfSize; $mx++) { + for ($my = -$halfSize; $my <= $halfSize; $my++) { + $rgb = imagecolorat($temp, $x + $mx, $y + $my); + $colors = imagecolorsforindex($temp, $rgb); + $gray = ($colors['red'] + $colors['green'] + $colors['blue']) / 3; + $sum += $gray * $matrix[$mx + $halfSize][$my + $halfSize]; + } + } + $values[] = abs($sum); + } + + imagedestroy($temp); + + if (count($values) > 0) { + return array_sum($values) / count($values); + } + + return 0; + } + + // Método auxiliar para verificar recursos de imagem + private function isValidImage($image) { + return $image && is_resource($image) || (is_object($image) && $image instanceof GdImage); + } + + private function ensureProcessedImage() { + if (!$this->processedImage) { + $this->processedImage = $this->srcImage; + } + return $this->isValidImage($this->processedImage); + } + + // Adicionar método para garantir valores inteiros + private function ensureInteger($value) { + return (int)round($value); + } +} diff --git a/index.php b/index.php index 442e759..c089384 100644 --- a/index.php +++ b/index.php @@ -52,6 +52,10 @@ include 'top_menu.php'; include 'clientes/edit_note.php'; } elseif ($page == 'delete_note' && isset($_POST['id'])) { include 'clientes/delete_note.php'; + } elseif ($page == 'process_document') { + include 'process_document.php'; + } elseif ($page == 'document_history') { + include 'document_history.php'; } else { echo "

Bem-vindo ao Sistema de Ferramentas

"; } diff --git a/menu.php b/menu.php index afd199e..4cd19d0 100644 --- a/menu.php +++ b/menu.php @@ -12,7 +12,7 @@ if (!isset($_SESSION['user_id'])) {
  • Autenticador de Provas Digitais @@ -24,6 +24,13 @@ if (!isset($_SESSION['user_id'])) {
  • Listagem de Clientes
  • +
  • + Processamento de Documentos + +
  • diff --git a/process_document.php b/process_document.php new file mode 100644 index 0000000..0e93852 --- /dev/null +++ b/process_document.php @@ -0,0 +1,85 @@ +processDocument($uploadFile, $processedFile); + + // Salva o registro no banco de dados + $mysqli = new mysqli("10.15.0.42", "root", "34641747", "valida"); + $stmt = $mysqli->prepare("INSERT INTO processed_documents (user_id, original_path, processed_path, created_at) VALUES (?, ?, ?, NOW())"); + $stmt->bind_param("iss", $_SESSION['user_id'], $uploadFile, $processedFile); + $stmt->execute(); + + $message = "Documento processado com sucesso!"; + $success = true; + } else { + throw new Exception("Falha ao fazer upload do arquivo."); + } + } catch (Exception $e) { + $message = "Erro: " . $e->getMessage(); + $success = false; + } +} +?> + +
    +

    Processamento de Documentos

    + + +
    + +
    + + +
    +
    + + +
    + + +
    + + +
    +

    Resultado:

    +
    +
    +

    Original:

    + Original +
    +
    +

    Processado:

    + Processado +
    +
    +
    + +
    diff --git a/style.css b/style.css index 4eb5acf..2723ee2 100644 --- a/style.css +++ b/style.css @@ -209,3 +209,50 @@ textarea { #search-button:hover { background-color: #0056b3; } + +/* Estilos para processamento de documentos */ +.upload-form { + max-width: 600px; + margin: 20px auto; + padding: 20px; + background: #f5f5f5; + border-radius: 5px; +} + +.result-preview { + margin-top: 30px; +} + +.image-comparison { + display: flex; + justify-content: space-around; + margin-top: 20px; + flex-wrap: wrap; +} + +.image-comparison img { + max-width: 45%; + height: auto; + margin: 10px; + border: 1px solid #ddd; + box-shadow: 0 0 5px rgba(0,0,0,0.2); +} + +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} + +.alert-success { + color: #155724; + background-color: #d4edda; + border-color: #c3e6cb; +} + +.alert-error { + color: #721c24; + background-color: #f8d7da; + border-color: #f5c6cb; +}