Entradas

Mostrando las entradas con la etiqueta Receta

Reducir el tamaño de un archivo PDF con GhostScript

Mientras buscaba un documento en PDF, me encontré con éste script, que reduce el tamaño de un archivo PDF, entre el 35% y 95% de su tamaño original.  En resumidas cuentas, convierte las imágenes a escala de grises con la calidad más baja posible y el texto le quita el formato.  

Recuerdo que se usó para enviar 150 MB de evidencias a una cuenta de correo del auditor que sólo aceptaba archivos adjuntos con un total de 15 MB.

gswin64c ^
 -q -dNOPAUSE -dBATCH -dSAFER ^
 -sDEVICE=pdfwrite ^
 -dCompatibilityLevel=1.4 ^
 -dPDFSETTINGS=/screen ^
 -dBlackText=true ^
 -dUseFastColor ^
 -dEmbedAllFonts=true -dSubsetFonts=true ^
 -sProcessColorModel=DeviceGray ^
 -sColorConversionStrategy=Gray ^
 -dOverrideICC ^
 -dGrayImageDownsampleType=/Bicubic ^
 -dDownsampleGrayImages=true ^
 -dGrayImageDownsampleThreshold=1.0 ^
 -dGrayImageResolution=8 ^
 -sOutputFile="compress/%~n1.pdf" ^
"%~1"

Saber la ruta física de una base de datos local de Microsoft SQL Server (LOCALDB)

Listar las instancias de LocalDB

SqlLocalDB i

Consulta

SELECT 
    db.name AS DatabaseName,
    mf.name AS LogicalName,
    mf.physical_name AS PhysicalFilePath,
    mf.type_desc AS FileType
FROM 
    sys.master_files mf
INNER JOIN 
    sys.databases db ON db.database_id = mf.database_id
WHERE 
    db.name = 'YourDatabaseName';

Tabla de Entidades de HTML

Trabajando con ChatGPT, escribí una página que realiza el formato de sintáxis de distintos tipos de códigos para éste blog, entre otros proyectos; Y he notado un problema: al usar HTML y reemplazar código, éste se pueden confundir los caracteres típicos que componen las etiquetas de HTML (&, <, > y =) , con símbolos especiales de algún lenguaje, tales como operadores o definición de plantillas.

La mejor solución es simplemente, reemplazar éstos caracteres molestos por su equivalente en entidad de HTML, como se muestra en la tabla siguiente:

Operador Entidad
& &amp;
< &lt;
> &gt;
= &equals;

Código de limpieza

code = code
	.replace(/&/g, "&amp;")
	.replace(/</g, "&lt;")
	.replace(/>/g, "&gt;")
	.replace(/=/g, "&equals;");

Referencias

Comandos básicos de .NET CLI

Variables de Entorno

Deshabilitar Telemetría
DOTNET_CLI_TELEMETRY_OPTOUT = 1

Crear Solución

Crea un archivo .sln con el nombre proporcionado por el argumento --name.
dotnet new sln --name BlazorServerExample

Crear Proyecto a partir de Plantilla

Genera los archivos relacionados con la plantilla especificada, en una carpeta y proyecto cuyo nombre se define con el argumento -o.
dotnet new blazor -o BlazorApp
Para ver la lista de plantillas de proyectos, se puede usar el siguiente comando:
dotnet new list
Nombre de la plantilla Nombre corto Idioma Etiquetas
API web ASP.NET Core (native AOT) webapiaot [C#] Web/Web API/API/Service
Aplicación Blazor Server blazorserver [C#] Web/Blazor
Aplicación Blazor Server vacía blazorserver-empty [C#] Web/Blazor/Empty
... ... ... ...
Worker Service worker [C#],F# Common/Worker/Web

Se pueden saber más opciones de la plantilla con
dotnet new blazor --help

Agregar Proyecto a Solución

dotnet sln BlazorServerExample.sln add ./BlazorApp/BlazorApp.csproj

Crear aplicación SPA de Blazor (WASM)

dotnet new blazorwasm -o MyBlazorSpa

Ejemplo de creación de solución para servidor Blazor

dotnet new sln --name BlazorServerExample
dotnet new blazor -o BlazorApp -int Server
dotnet sln BlazorServerExample.sln add ./BlazorApp/BlazorApp.csproj

Ejemplo de creación de solución de consola

dotnet new sln --name ConsoleApp
dotnet new console -o ConsoleApp
dotnet sln ConsoleApp.sln add ./ConsoleApp/ConsoleApp.csproj

Actualizar paquetes

dotnet package update

Referencias

Consulta de registros de IIS con Log Parser

Estamos llegando al final del ciclo de vida de los servidores actuales y nos estamos preparando para migrar de IIS a RedHat. Mientras se lleva a cabo la planificación de esta migración, es necesario obtener estadísticas sobre el tráfico en ciertas carpetas y los horarios de uso. Esto nos permitirá decidir qué se migrará y qué se conservará únicamente en el snapshot final.

Para esta tarea, recurrí a Log Parser, una herramienta lanzada en 2010 que permite ejecutar consultas sobre archivos de texto (en mi caso, archivos .log) utilizando una sintaxis similar a SQL. Sin embargo, me encontré con una sorpresa: aunque utiliza SQL, no se trata del estándar, ni siquiera del SQL usado por SQL Server. Su sintaxis es particular y algo de nicho, lo que hace que sea complicado obtener ayuda directa de herramientas de inteligencia artificial.

Probé generar consultas con ChatGPT y Gemini, pero ambas herramientas fallaron al dar una respuesta precisa debido a la naturaleza especializada, y no estandarizada del lenguaje que usa Log Parser. Por ello, aquí dejo algunos ejemplos de consultas que me han funcionado para generar estadísticas simples, por si a alguien más le resulta útil.

Configuración

Descarga Log Parser desde el sitio oficial https://www.microsoft.com/en-us/download/details.aspx?id=24659

Aparentemente, la ruta de Log Parser no se agrega a la ruta de variables de entorno, lo que significa que no se puede llamar simplemente desde la consola, por lo que se tiene especificar su ruta completa (C:\Program Files (x86)\Log Parser 2.2\LogParser.exe)

En mi caso hice un archivo.bat para que pueda escribir los archivos .sql aparte.
"C:\Program Files (x86)\Log Parser 2.2\logparser.exe" -i:IISW3C -o:CSV file:%~1

Documentación

Dependiendo de lo que se quiera consultar, Log Parser utiliza determinadas columnas que espera estén en los archivos de texto, mismas columnas se puede consultar con el parámetro -h (help) e -i: (input), donde especificamos el formato a consultar, en mi caso son los logs de IIS (IISW3C)
logparser -h -i:IISW3C
Lo que nos devuelve la lista de columnas con su respectivo tipo, en éste caso lo remuevo para mayor facilidad al copiar y pegar, adicionalmente de algunos ejemplos.
LogFilename , LogRow , date , time , c-ip , cs-username , s-sitename , s-computername , s-ip , s-port , cs-method , cs-uri-stem , cs-uri-query , sc-status , sc-substatus , sc-win32-status , sc-bytes , cs-bytes , time-taken , cs-version , cs-host , cs(User-Agent),  , cs(Cookie),  , cs(Referer),  , s-event , s-process-type , s-user-time , s-kernel-time , s-page-faults , s-total-procs , s-active-procs , s-stopped-procs

Consultas

Quiero hacer una lista de carpetas que se han usado en éste año (u_ex25*.log), y saber cúantas veces ha sido servido un recurso, (asociado a una carpeta, usando EXTRACT_TOKEN para obtener el primer folder), de manera exitosa (status 200).
SELECT 
	COUNT(*) AS Hits,
	EXTRACT_TOKEN(cs-uri-stem, 1, '/') AS Service
INTO servicios.csv	
FROM C:\inetpub\logs\LogFiles\W3SVC3\u_ex25*.log
WHERE 
	sc-status = 200 AND 
	cs-uri-stem LIKE '/%'
GROUP BY Service 
ORDER BY Hits DESC

Curiosamente, la herramienta ya estaba instalada en el servidor, lo que me hace pensar que ya había intentado usarla en el pasado… y que seguramente me desesperó. Conociéndome, es muy probable que en aquel momento incluso haya escrito alguna herramienta propia para obtener las estadísticas que necesitaba.

Generar entorno Portable de Python

Entorno de python portable

Últimamente me ha dado por hacer y usar algunas herramientas con Python, pero algunas veces, es preferible tener un entorno de Python aislado a la hora de instalar dependencias: ya van al menos 3 veces que he tenido que reinstalar tensor compilado para cuda, porque un script de requisitos lo reemmplaza por la versión para cpu. Winpython nos provee de una versión de Python portable, que corre en windows.

Enlace de descarga: https://github.com/winpython/winpython/releases/

Se descarga un archivo .ZIP, en mi caso es Winpython64-3.12.9.0dot.zip, donde copiamos las carpetas:

  • Notebooks
  • python
  • scripts
  • settings
y creamos un archivo bat para lanzar nuestra aplicación de Python. Lo único opcional es la línea python app.py
@echo off
cd /d ./scripts/
call activate.bat
python app.py

Cómo Reducir el Tamaño de una Base de Datos en SQL Server

Cuando trabajamos con una base de datos en entornos de desarrollo o pruebas, es común que crezca más de lo necesario; sin embargo, al momento publicarla o compartirla, es fundamental reducir su tamaño al mínimo posible.

En este artículo te mostraré los comandos esenciales de SQL Server que te permitirán reducir el tamaño físico de tu base de datos.

Obtener el nombre de archivos y su tamaño, se usa la siguiente consulta:

SELECT name, type_desc, size/128 AS SizeMB FROM sys.database_files;

Nos da el siguiente resultado:

name type_desc SizeMB
db_Prueba ROWS 9
db_Prueba_log LOG 28

Se usa SHRINKFILE para reducir el tamaño de archivo y sp_MSforeachtable para regenerar los índices. Si no usa RECOVERY SIMPLE, el tamaño del log no cambia.

ALTER DATABASE db_CorreosInstitucionales_UPIICSA SET RECOVERY SIMPLE;
DBCC SHRINKFILE ('db_Prueba_log', 1);
DBCC SHRINKFILE ('db_Prueba', 1);
EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REBUILD';
ALTER DATABASE db_CorreosInstitucionales_UPIICSA SET RECOVERY FULL;

Volviendo a ejecutar la consulta para obtener el tamaño, obtenemos:

name type_desc SizeMB
db_Prueba ROWS 7
db_Prueba_log LOG 1

Lo que nos confirma que sí se redujo el tamaño del archivo.

Agregar o eliminar usuarios en Windows desde la consola (y quitar la expiración de contraseña)

Agregar usuario (y agregarlo a los administradores)

NET USER Usuario contraseña /add
NET LOCALGROUP administradores Usuario /add

Eliminar usuario (y quitarlo de los administradores)

NET LOCALGROUP administradores Usuario /delete
NET USER Usuario /delete

Deshabilitar la expiración de contraseña

Se necesita WMIC para hacer la configuración desde la línea de comando, pero fue depreciado en enero de 2024. se puede reinstalar la utilidad con DISM con el siguinte comando:
DISM /Online /Add-Capability /CapabilityName:WMIC~~~~
Deshabilitar la expiración de contraseña:
wmic UserAccount where Name="Usuario" set PasswordExpires=False

Inicio de sesión automático (Archivo.REG)

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]
"AutoAdminLogon"="1"
"DefaultUserName"="Usuario"
"DefaultPassword"="contraseña"
Se ejecuta con:
regedit.exe /S Archivo.REG

Enlaces

Script en Python para renombrar múltiples archivos PNG fácilmente

Normalmente, el comando rename de DOS hace bien su trabajo. Pero en casos especiales, donde los archivos deben seguir un patrón específico, se queda corto. En mi caso, solo necesitaba renombrarlos de forma secuencial. Es la segunda vez en menos de un mes que me enfrento a esta necesidad, así que decidí dejar por aquí un pequeño script generado por ChatGPT.
import os

# Get all .png files in the current directory
png_files = sorted([f for f in os.listdir('.') if f.lower().endswith('.png')])

# Rename each file
for i, filename in enumerate(png_files, start=1):
    new_name = f"image_{i:05}.png"
    os.rename(filename, new_name)
    print(f'Renamed "{filename}" -> "{new_name}"')

Instalación de insightface para ComfyUI

Hay que ir a la carpeta ComfyUI\python_embeded

Es necesario saber la versión de Python

python -V


 En este caso la versión de Python es la 3.12.8, así que descargamos el wheel insightface-0.7.3-cp312-cp312-win_amd64.whl de la página https://github.com/Gourieff/Assets/tree/main/Insightface

Y se instala con el siguiente comando:

python -m pip install insightface-0.7.3-cp312-cp312-win_amd64.whl

Listar directorios en JAVA

java.io.File dir = new java.io.File(".");
                
for(java.io.File entry : dir.listFiles())
{
	if(entry.isDirectory())
	{
		System.out.println(entry.getName());
	}
}

Instrucciones comunes para Postgresql

/* == VERSIÓN == */
SELECT version();
/* LISTAR DETALLES DE COLUMNAS DE LA BASE DE DATOS ACTUAL */
SELECT
	table_schema, 
	table_name, 
	column_name,
	data_type,
	is_nullable,
	column_default,
	character_maximum_length, 
	numeric_precision, 
	datetime_precision
FROM
	information_schema.columns
WHERE
	table_schema NOT IN ('information_schema','pg_catalog')
ORDER BY table_schema, table_name, ordinal_position

Archivo de configuración de Visual Studio Code para depurar archivos PHP con Xdebug

.vscode\launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        },
        {
            "name": "Launch currently open script",
            "type": "php",
            "request": "launch",
            "program": "${file}",
            "cwd": "${fileDirname}",
            "port": 0,
            "runtimeArgs": [
                "-dxdebug.start_with_request=yes"
            ],
            "env": {
                "XDEBUG_MODE": "debug,develop",
                "XDEBUG_CONFIG": "client_port=${port}"
            }
        }
    ]
}

Comandos comunes de MS-DOS

Activar el uso UTF-8 (Palabras con Acentos)

chcp 65001 

Ejecutar comando por cada archivo/directorio (Incluyendo nombres con espacios)

ECHO OFF
FOR /f delims^=^ eol^= %%f IN ('dir d:\downloads\ /b') DO (
ECHO "%%f"
)

Fecha y Hora (funciona para Español para México, en otros idiomas podría cambiar la posición de cada elemento, dada la configuración regional)

ECHO OFF
ECHO FECHA (YYYY/MM/DD):
ECHO %date:~-4,4%/%date:~-7,2%/%date:~-10,2% 
ECHO.
ECHO HORA (HH:MM:SS):
ECHO %time:~0,2%:%time:~3,2%:%time:~6%
ECHO.

Obtener la ruta del escritorio

::https://stackoverflow.com/a/34706178/3930332
for /f "usebackq tokens=1,2,*" %%B IN (`reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop`) do set DESKTOP=%%D
ECHO %DESKTOP%

Remover espacios en variables

SET "VAR=%VAR: =%"

Mostrar todas las líneas del archivo archivo.txt que no se encuentran en el archivo quitar.txt

findstr /i /L /V /g:"quitar.txt" "archivo.txt"

Referencias:

https://stackoverflow.com/questions/11270453/how-to-remove-spaces-from-file-names-in-bulk 

Fórmula para la mezcla de colores RGB

Estoy trabajando en un ampliador de imágenes de PixelArt y por enésima vez se me olvida la fórmula para combinar dos colores (RGB). 

Donde a y b son los compenentes RGB de cada color. Se tiene que evaluar por cada par de R, G y B.

Referencias

Compilar aplicaciones nativas de Windows (C/C++) en Ubuntu (WSL, Windows Subsystem Linux) y MSYS2

Requisitos

APT

sudo apt install mingw-w64 binutils-mingw-w64 binutils-mingw-w64-x86-64 g++ g++-mingw-w64 -y

PACMAN

pacman -S mingw-w64-x86_64-gcc mingw-w64-cross-binutils

Código Fuente

Ejecutable

Si el código fuente se guarda con codificación ANSI, se pueden mostrar acentos.
//test.cpp
#include <windows.h>

int APIENTRY WinMain(
 HINSTANCE hInstance, 
 HINSTANCE hPrevInstance, 
 LPSTR lpCmdLine, 
 int nCmdShow
)
{
 int respuesta = MessageBox
 (
  NULL,//Owner
  "¡Hola, Mundo! :V\n\ráéíóú",//Mensaje (Cuerpo)
  "Prueba", //Título
  MB_ICONINFORMATION | MB_YESNO | MB_DEFBUTTON1 //Apariencia
 );
 
 return respuesta == MB_OK ? ERROR_SUCCESS : ERROR_GEN_FAILURE;
}

Ícono (opcional)

//app.rc
APP_ICON ICON "app.ico"


Compilación

Ícono (Opcional)

Debe de compilarse antes que el ejecutable.
x86_64-w64-mingw32-windres app.rc -O coff -o app.res
Con MSYS2 podemos quitar el prefijo x86_64-w64-mingw32-
windres app.rc -O coff -o app.res

Ejecutable

Si queremos que nuestro ejecutable tenga un ícono, agregamos el archivo .res que compilamos del ícono.
Usamos el parámetro mwindows para indicar que se genere una aplicación GUI en lugar de consola.
x86_64-w64-mingw32-g++ -mwindows -o test.exe test.cpp app.res
g++ -mwindows -o test.exe test.cpp app.res


Resultado

Referencias

Generar archivos de Excel en C#, fácilmente con EPPlus

Limitaciones

  • No se pueden evaluar fórmulas
  • Únicamente el estilo "Normal" está definido (Hay que definir el estilo de "Contabilidad", para poder usar el formato de moneda).

Páquete de Nuget

Install-Package EPPlus

Referencias

using System.IO;
using System.Drawing;

using OfficeOpenXml;
using OfficeOpenXml.Style;
using OfficeOpenXml.Style.XmlAccess;

Código

FileStream fs = new FileStream("prueba.xlsx", FileMode.Create);
ExcelPackage Excel = new ExcelPackage(fs);

/* Creación del estilo. */
Excel.Workbook.Styles.CreateNamedStyle("Moneda");
ExcelNamedStyleXml moneda = Excel.Workbook.Styles.NamedStyles[1];// 0 = Normal, 1 (El que acabamos de agregar).

moneda.Style.Numberformat.Format = "_-$* #,##0.00_-;-$* #,##0.00_-;_-$* \"-\"??_-;_-@_-";
moneda.Style.Fill.PatternType = ExcelFillStyle.Solid;
moneda.Style.Fill.BackgroundColor.SetColor(Color.Yellow);

/* Creación de hoja de trabajo. */
Excel.Workbook.Worksheets.Add("Hoja de Prueba 1");
ExcelWorksheet hoja = Excel.Workbook.Worksheets["Hoja de Prueba 1"];

/* Num Caracteres + 1.29 de Margen.
Los índices de columna empiezan desde 1. */
hoja.Column(1).Width = 11.29f;
            
ExcelRange rango = hoja.Cells["A1"];

rango.Value = 1.0M;
rango.StyleName = "Moneda";

Excel.Save();
            
// No estoy seguro de ésta parte, pero mejor cerramos el stream de archivo.
fs.Close();
fs.Dispose();
            
Excel.Dispose();

Referencias

Adjuntar archivos de texto a otro archivo de texto

Tengo una gran cantidad de archivos SQL generados (uno por tabla), por un programa de copia de seguridad que hice, elimino los archivos que no necesito y los junto en un archivo para llenar mi Base de Datos.

El problema: No quiero abrir archivo por archivo e ir copiando y pegando las líneas de código. ¿La Solución? , nuestro viejo amigo redireccionamiento de MS-DOS…


@ECHO OFF
REM Borrando archivo de destino
DEL master.txt

REM Adjuntando el contenido de cada archivo SQL a master.txt

REM Omito usar la extensión .sql para evitar que archivo generado
REM se incluya en el DIR .

REM *Nota Mental* ECHO. da un salto de línea...

FOR /f %%f IN ('dir /b *.sql') DO (
 TYPE %%f >> master.txt
 ECHO ; >> master.txt
)

PAUSE

Código de prueba de base de datos (MySQL) en PHP


Lo mínimo necesario para probar los datos de conexión a una base de datos de MySQL (o MariaDB), con su consulta de prueba, pobremente optimizada.

Código

<?php
$mysqli = new mysqli("localhost","usuario","clave", "base_de_datos");

/* comprobar la conexión */
if ($mysqli->connect_errno) {
 printf("Falló la conexión: %s\n", $mysqli->connect_error);
 exit();
}else{
 print("Conexión a Base de Datos Correcta.\n\n");
}

if($resultado = $mysqli->query("SELECT NOW() AS Fecha;"))
{
 print '<pre>';
 while ($fila = $resultado->fetch_assoc()) 
 {
  print_r($fila);
 }
 $resultado->free();
 print '</pre>';
}else{
 printf("ERROR: %s",mysqli_error($mysqli));
}

$mysqli->close();
?> 

Rotar una imágen basándose en los metadados EXIF (C#)

Mientras estaba escribiendo un generador de miniaturas para un sistema, noté que algunas imágenes generadas no coincidían con el original, y oh sorpresa!, todas las imágenes tenían algo en común: fueron tomadas con celular....

Al abrir las imágenes con Microsoft Paint (Versión XP), pude constatar que las imágenes generadas coincidían con las miniaturas, a pesar que el explorador de archivos y el navegador web decían lo contrario, ¿el culpable? ¡Metadatos!.

Los metadatos son datos adicionales incrustados en un archivo, generalmente al final del mismo; y su función es proporcionar información adicional, que en mi caso es orientación de la imagen.

Existen 8 distintos tipos de Orientación:


1 - Horizontal (normal) - RotateNoneFlipNone

2 - Mirror horizontal - Rotate180FlipY

3 - Rotate 180 - Rotate180FlipNone


4 - Mirror vertical - RotateNoneFlipY

5 - Mirror horizontal and rotate 270 CW - Rotate270FlipY

6 - Rotate 90 CW - Rotate90FlipNone

7 - Mirror horizontal and rotate 90 CW - Rotate90FlipY

8 - Rotate 270 CW - Rotate270FlipNone

Referencias

using System.Drawing;
using System.Drawing.Imaging;

Código

RotateFlipType rotation = RotateFlipType.RotateNoneFlipNone;
            
foreach (PropertyItem item in bitmap.PropertyItems)
{
 if (item.Id == 0x0112)
 {
  int orientation = BitConverter.ToInt16(item.Value, 0);
  switch (orientation)
  {
   case 2: rotation = RotateFlipType.Rotate180FlipY; break;
   case 3: rotation = RotateFlipType.Rotate180FlipNone; break;
   case 4: rotation = RotateFlipType.RotateNoneFlipY; break;
   case 5: rotation = RotateFlipType.Rotate270FlipY; break;
   case 6: rotation = RotateFlipType.Rotate90FlipNone; break;
   case 7: rotation = RotateFlipType.Rotate90FlipY; break;
   case 8: rotation = RotateFlipType.Rotate270FlipNone; break;
  }
  break;
 }
}
image.RotateFlip(rotation); 

Fuentes