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
+
+
+
+
+ | Data/Hora |
+ Usuário |
+ Documento Original |
+ Documento Processado |
+ Ações |
+
+
+
+ fetch_assoc()): ?>
+
+ |
+ |
+
+
+ Ver Original
+
+ |
+
+
+ Ver Processado
+
+ |
+
+
+ |
+
+
+
+
+
+
+
diff --git a/document_processor.php b/document_processor.php
new file mode 100644
index 0000000..0142fd0
--- /dev/null
+++ b/document_processor.php
@@ -0,0 +1,1063 @@
+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);
+
+ // Reduz a amostragem para análise mais rápida
+ $sampleStep = max(1, (int)($width * $height / 100000));
+ $histogram = array_fill(0, 256, 0);
+ $totalSamples = 0;
+
+ // Amostragem reduzida para cálculo mais rápido
+ for ($x = 0; $x < $width; $x += $sampleStep) {
+ for ($y = 0; $y < $height; $y += $sampleStep) {
+ $rgb = imagecolorat($this->srcImage, $x, $y);
+ $colors = imagecolorsforindex($this->srcImage, $rgb);
+ $gray = (int)(($colors['red'] + $colors['green'] + $colors['blue']) / 3);
+ $histogram[$gray]++;
+ $totalSamples++;
+ }
+ }
+
+ $this->imageQualityMetrics = [
+ 'brightness' => $this->calculateAverageBrightness($histogram, $totalSamples),
+ 'contrast' => $this->calculateImageContrast($histogram, $totalSamples),
+ 'noise' => $this->estimateImageNoise(50), // Reduz número de amostras
+ 'blur' => $this->estimateBlurLevel(100) // Reduz número de amostras
+ ];
+
+ 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;
+ }
+
+ $params = $this->processingParams;
+
+ // Verifica e aplica ajustes com validação de parâmetros
+ if (isset($params['brightness_adjustment']) || isset($params['contrast_adjustment'])) {
+ $brightness = isset($params['brightness_adjustment']) ? (int)$params['brightness_adjustment'] : 0;
+ $contrast = isset($params['contrast_adjustment']) ? (int)$params['contrast_adjustment'] : 0;
+ $this->applyBrightnessContrastOptimized($brightness, $contrast);
+ }
+
+ if (isset($params['noise_reduction']) && $params['noise_reduction'] > 0) {
+ $this->applyFastNoiseReduction((int)$params['noise_reduction']);
+ }
+
+ if (isset($params['sharpen_intensity']) && $params['sharpen_intensity'] > 0) {
+ $this->applyFastSharpening((int)$params['sharpen_intensity']);
+ }
+
+ 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($samples = 50) {
+ $width = imagesx($this->srcImage);
+ $height = imagesy($this->srcImage);
+ $noise = 0;
+
+ // Reduz número de amostras e otimiza cálculo
+ for ($i = 0; $i < $samples; $i++) {
+ $x = rand(1, $width - 2);
+ $y = rand(1, $height - 2);
+ $noise += $this->fastLocalVariance($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 (int)round(min(50, (1 - $contrast/$optimal) * 100));
+ } elseif ($contrast > $optimal * 1.3) {
+ return (int)round(max(-50, ($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)round(($optimal - $brightness) * 0.5);
+ }
+
+ private function calculateSharpenIntensity() {
+ $blurLevel = $this->imageQualityMetrics['blur'];
+ return (int)round(min(100, $blurLevel * 50));
+ }
+
+ private function calculateNoiseReduction() {
+ $noise = $this->imageQualityMetrics['noise'];
+ return (int)round(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);
+
+ // Garantir que intensity seja inteiro
+ $intensity = (int)$intensity;
+ $windowSize = 2 * $intensity + 1;
+ $halfWindow = (int)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);
+ // Garantir índice inteiro para o valor mediano
+ $medianIndex = (int)floor(count($values) / 2);
+ $median = $values[$medianIndex];
+ $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);
+ }
+
+ private function fastLocalVariance($x, $y) {
+ $sum = 0;
+ $sumSq = 0;
+ $count = 0;
+
+ // Analisa apenas 4 pixels vizinhos em vez de 9
+ $positions = [
+ [$x, $y],
+ [$x-1, $y],
+ [$x+1, $y],
+ [$x, $y-1],
+ [$x, $y+1]
+ ];
+
+ foreach ($positions as [$px, $py]) {
+ $rgb = imagecolorat($this->srcImage, $px, $py);
+ $colors = imagecolorsforindex($this->srcImage, $rgb);
+ $value = ($colors['red'] + $colors['green'] + $colors['blue']) / 3;
+ $sum += $value;
+ $sumSq += $value * $value;
+ $count++;
+ }
+
+ $mean = $sum / $count;
+ return ($sumSq / $count) - ($mean * $mean);
+ }
+
+ private function applyBrightnessContrastOptimized($brightness, $contrast) {
+ $width = imagesx($this->processedImage);
+ $height = imagesy($this->processedImage);
+
+ // Pré-calcula tabela de lookup para otimizar
+ $lookup = array_fill(0, 256, 0);
+ for ($i = 0; $i < 256; $i++) {
+ $value = $i;
+ if ($brightness != 0) {
+ $value += $brightness;
+ }
+ if ($contrast != 0) {
+ $value = (($value - 128) * (1 + $contrast/100)) + 128;
+ }
+ $lookup[$i] = min(255, max(0, (int)$value));
+ }
+
+ // Aplica lookup table em uma única passagem
+ for ($x = 0; $x < $width; $x++) {
+ for ($y = 0; $y < $height; $y++) {
+ $rgb = imagecolorat($this->processedImage, $x, $y);
+ $colors = imagecolorsforindex($this->processedImage, $rgb);
+ $newColor = imagecolorallocate(
+ $this->processedImage,
+ $lookup[$colors['red']],
+ $lookup[$colors['green']],
+ $lookup[$colors['blue']]
+ );
+ imagesetpixel($this->processedImage, $x, $y, $newColor);
+ }
+ }
+ }
+
+ private function applyFastNoiseReduction($intensity) {
+ if (!$this->processedImage) {
+ return $this;
+ }
+
+ $width = imagesx($this->processedImage);
+ $height = imagesy($this->processedImage);
+
+ // Otimização: processa apenas uma parte dos pixels
+ $step = max(1, (int)($intensity / 2));
+
+ for ($x = 0; $x < $width - 2; $x += $step) {
+ for ($y = 0; $y < $height - 2; $y += $step) {
+ $values = [];
+
+ // Coleta 5 pixels em vez de 9 para maior velocidade
+ $pixels = [
+ [$x, $y],
+ [$x + 1, $y],
+ [$x, $y + 1],
+ [$x + 1, $y + 1],
+ [$x + 2, $y + 2]
+ ];
+
+ foreach ($pixels as [$px, $py]) {
+ if ($px < $width && $py < $height) {
+ $rgb = imagecolorat($this->processedImage, $px, $py);
+ $colors = imagecolorsforindex($this->processedImage, $rgb);
+ $values[] = $colors['red'];
+ }
+ }
+
+ if (!empty($values)) {
+ sort($values);
+ $median = $values[(int)(count($values) / 2)];
+ $color = imagecolorallocate($this->processedImage, $median, $median, $median);
+ if ($color !== false) {
+ imagesetpixel($this->processedImage, $x, $y, $color);
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ private function applyFastSharpening($intensity) {
+ if (!$this->processedImage) {
+ return $this;
+ }
+
+ // Matriz de sharpening otimizada
+ $matrix = [
+ [-0.5, -0.5, -0.5],
+ [-0.5, 6 + ($intensity * 0.1), -0.5],
+ [-0.5, -0.5, -0.5]
+ ];
+
+ $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);
+
+ // Processamento otimizado com passo variável
+ $step = max(1, min(3, (int)($width * $height / 1000000)));
+
+ for ($x = 1; $x < $width - 1; $x += $step) {
+ for ($y = 1; $y < $height - 1; $y += $step) {
+ $r = $g = $b = 0;
+
+ for ($i = -1; $i <= 1; $i++) {
+ for ($j = -1; $j <= 1; $j++) {
+ $rgb = imagecolorat($temp, $x + $i, $y + $j);
+ $colors = imagecolorsforindex($temp, $rgb);
+ $weight = $matrix[$i + 1][$j + 1];
+
+ $r += $colors['red'] * $weight;
+ $g += $colors['green'] * $weight;
+ $b += $colors['blue'] * $weight;
+ }
+ }
+
+ $r = min(255, max(0, (int)$r));
+ $g = min(255, max(0, (int)$g));
+ $b = min(255, max(0, (int)$b));
+
+ $color = imagecolorallocate($this->processedImage, $r, $g, $b);
+ if ($color !== false) {
+ imagesetpixel($this->processedImage, $x, $y, $color);
+ }
+ }
+ }
+
+ imagedestroy($temp);
+ return $this;
+ }
+}
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:
+
; ?>)
+
+
+
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;
+}