You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
5.6 KiB
152 lines
5.6 KiB
|
8 months ago
|
/* ——————————————————————————————————————————————————————————————————————————
|
||
|
|
Proyecto ImgResizer
|
||
|
|
—————————————————————————————————————————————————————————————————————————————
|
||
|
|
Fichero main.go
|
||
|
|
Package ImgResizer
|
||
|
|
Autor Juan V. Navarro juanvnl@activething.com
|
||
|
|
Creado 26/01/2026
|
||
|
|
—————————————————————————————————————————————————————————————————————————————
|
||
|
|
|
||
|
|
LICENSES AND TERMS OF USE
|
||
|
|
-------------------------
|
||
|
|
|
||
|
|
This software is licensed under the Elastic License v2.0 (the "License").
|
||
|
|
For full terms and additional information regarding permitted and prohibited
|
||
|
|
uses, please visit:
|
||
|
|
https://activething.com/ATGO/licenses
|
||
|
|
|
||
|
|
You may use, copy, modify, and redistribute this software internally within
|
||
|
|
your organization for any purpose, including research, development, and
|
||
|
|
testing, subject to the terms of this License.
|
||
|
|
|
||
|
|
You may NOT, however, use, provide, distribute, or make this software
|
||
|
|
available to any third party as part of a hosted service, SaaS offering, or
|
||
|
|
commercial product without first obtaining a commercial license from
|
||
|
|
Active Thing.
|
||
|
|
|
||
|
|
You may combine this software with other code, provided that such
|
||
|
|
combination does not circumvent the restrictions of this License.
|
||
|
|
|
||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. In no event shall
|
||
|
|
the authors or copyright holders be liable for any claim, damages, or other
|
||
|
|
liability arising from the use of this software.
|
||
|
|
|
||
|
|
—————————————————————————————————————————————————————————————————————————————
|
||
|
|
|
||
|
|
Web : activething.com | activething.com/ImgResizer
|
||
|
|
git : g.activething.com | github.com/activething/ImgResizer
|
||
|
|
Correo : dev@activething.com
|
||
|
|
|
||
|
|
—————————————————————————————————————————————————————————————————————————————
|
||
|
|
No deseo caminar sobre el agua", dijo Siddhartha.
|
||
|
|
Que los antiguos chamanes se contenten con tales habilidades.
|
||
|
|
—— Hermann Hesse, Siddhartha
|
||
|
|
—————————————————————————————————————————————————————————————————————————————
|
||
|
|
Copyright (c) 2026 Active Thing
|
||
|
|
————————————————————————————————————————————————————————————————————————————— */
|
||
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"flag"
|
||
|
|
"fmt"
|
||
|
|
"image"
|
||
|
|
"image/jpeg"
|
||
|
|
"image/png"
|
||
|
|
"log"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"github.com/disintegration/imaging"
|
||
|
|
// Decodificador Pure Go para WebP (No requiere CGO)
|
||
|
|
_ "golang.org/x/image/webp"
|
||
|
|
)
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
inputDir := flag.String("dir", "", "Directorio de origen")
|
||
|
|
outputDir := flag.String("out", "", "Directorio de destino")
|
||
|
|
width := flag.Int("width", 0, "Ancho (excluyente)")
|
||
|
|
height := flag.Int("height", 0, "Alto (excluyente)")
|
||
|
|
quality := flag.Int("calidad", 100, "Calidad (1-100)")
|
||
|
|
|
||
|
|
configurarAyuda()
|
||
|
|
flag.Parse()
|
||
|
|
|
||
|
|
if *inputDir == "" || *outputDir == "" || (*width == 0 && *height == 0) {
|
||
|
|
flag.Usage()
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if *width > 0 && *height > 0 {
|
||
|
|
log.Fatal("Error: -width y -height son excluyentes.")
|
||
|
|
}
|
||
|
|
|
||
|
|
os.MkdirAll(*outputDir, 0755)
|
||
|
|
|
||
|
|
files, _ := os.ReadDir(*inputDir)
|
||
|
|
|
||
|
|
for _, file := range files {
|
||
|
|
ext := strings.ToLower(filepath.Ext(file.Name()))
|
||
|
|
if ext != ".jpg" && ext != ".jpeg" && ext != ".png" && ext != ".webp" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
fmt.Printf("Procesando %s... ", file.Name())
|
||
|
|
err := processImage(filepath.Join(*inputDir, file.Name()), filepath.Join(*outputDir, file.Name()), *width, *height, *quality)
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
fmt.Printf("ERROR: %v\n", err)
|
||
|
|
} else {
|
||
|
|
fmt.Println("OK")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func processImage(src, dst string, w, h, q int) error {
|
||
|
|
// 1. Abrir imagen (Soporta WebP, JPG, PNG gracias a los imports con _)
|
||
|
|
f, err := os.Open(src)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
defer f.Close()
|
||
|
|
|
||
|
|
img, _, err := image.Decode(f)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. Redimensionar
|
||
|
|
resized := imaging.Resize(img, w, h, imaging.Lanczos)
|
||
|
|
|
||
|
|
// 3. Guardar según extensión
|
||
|
|
out, err := os.Create(dst)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
defer out.Close()
|
||
|
|
|
||
|
|
ext := strings.ToLower(filepath.Ext(dst))
|
||
|
|
switch ext {
|
||
|
|
case ".jpg", ".jpeg":
|
||
|
|
return jpeg.Encode(out, resized, &jpeg.Options{Quality: q})
|
||
|
|
case ".png":
|
||
|
|
// El encoder estándar de Go es muy robusto
|
||
|
|
return png.Encode(out, resized)
|
||
|
|
case ".webp":
|
||
|
|
// Si llegas aquí sin CGO, el programa dirá que no sabe codificar WebP
|
||
|
|
// pero al menos el resto del programa COMPILARÁ y FUNCIONARÁ
|
||
|
|
return fmt.Errorf("la escritura de WebP requiere CGO y un compilador de C (GCC)")
|
||
|
|
default:
|
||
|
|
return imaging.Save(resized, dst)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func configurarAyuda() {
|
||
|
|
flag.Usage = func() {
|
||
|
|
fmt.Printf("\nUso: resizer -dir <origen> -out <destino> [-width | -height]\n")
|
||
|
|
flag.PrintDefaults()
|
||
|
|
}
|
||
|
|
}
|