Convertir imágenes png a jpg
#1
Posted 21 January 2012 - 07:08 AM
Hace tiempo que no ando por aquí. Espero que hayan empezado bien el año 2012
Necesito saber si hay alguna forma de convertir imágenes png a jpg sin tener que abrir cada una de las imágenes. Tengo varios miles de imágenes png y me gustaría tenerlas en formato jpg
Gracias y saludos a todos
Roberto
#2
Posted 22 January 2012 - 11:44 AM
La forma mas sencilla de realizar conversiones de archivos de imagen, sin usar complicadas librerías gráficas, es usando las capacidades del propio S.O. Windows en su librería GDI+.
Hace unos meses publiqué un truco para leer archivos de varios formatos gráficos usando GDI+.
Para responder a robert01 voy a poner un ejemplo del uso de GDI+ para leer un archivo y codificarlo en jpeg. La pequeña aplicación de ejemplo, copiada en la carpeta que deseamos explorar, convertirá todos los archivos encontrados con extensión ".png" en archivos jpeg con el mismo nombre y nueva extensión ".jpg".
Esta aplicación puede ser adaptada, con algunos cambios y algo de código añadido, para ajustar la calidad de compresión y codificar en otros formatos, además de jpg.
El código es el siguiente, escrito y compilado en Builder C++ 5:
//--------------------------------------------------------------------------- #define STRICT #include <windows.h> #include <algorithm> using std::min; using std::max; #include "Gdiplus.h" #include <vcl.h> #pragma hdrstop #pragma comment(lib, "Gdiplus.lib") //--------------------------------------------------------------------------- Gdiplus::GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; // Encontrar el CLSID para codificar en el formato deseado. bool GetEncoderClsid(const WCHAR* Format, CLSID* Clsid) { UINT i=0, N=0, Size=0; Gdiplus::GetImageEncodersSize(&N, &Size); if(!Size) return false; Gdiplus::ImageCodecInfo* ICInfo = new Gdiplus::ImageCodecInfo[Size]; Gdiplus::GetImageEncoders(N, Size, ICInfo); while (i<N && wcscmp(ICInfo[i].MimeType, Format)) i++; if(i<N) *Clsid = ICInfo[i].Clsid; delete [] ICInfo; return (i<N); } void ToJpg(WCHAR* FileName) { CLSID Clsid; GetEncoderClsid(L"image/jpeg", &Clsid); Gdiplus::Bitmap SrcBitmap(FileName, 0); wcscpy(&FileName[wcslen(FileName)-4], L".jpg"); SrcBitmap.Save(FileName, &Clsid, NULL); } #pragma argsused WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Initialize GDI+. if(GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL)) return 0; HANDLE hFindFile; WIN32_FIND_DATAW WFData; if((hFindFile = FindFirstFileW(L"*.png", &WFData))!=INVALID_HANDLE_VALUE){ do{ ToJpg(WFData.cFileName); } while (FindNextFileW(hFindFile, &WFData)); FindClose(hFindFile); } //shutdown GDI+ Gdiplus::GdiplusShutdown(gdiplusToken); return 0; } //---------------------------------------------------------------------------
Para usar el programita, se debe copiar en la carpeta donde se alojan los archivos a convertir, seguidamente se ejecuta, lo hará en segundo plano, convirtiendo todos los archivos png encontrados en jpg.
Espero que sea de utlidad y sirva de respuesta a la pregunta planteada.
Subo un archivo con el código fuente y compilado.
Saludos.
Attached Files
#3
Posted 22 January 2012 - 12:43 PM
Muchas gracias Escafandra por haber respondido, sobre todo siendo día domingo
Saludos
#4
Posted 23 January 2012 - 03:44 AM
#5
Posted 23 January 2012 - 05:53 PM
Saludos.
#6
Posted 25 January 2012 - 06:24 PM
Y también en delphi.
En un ratillo libre me he entretenido jugando con la API Flat del GDI plus y he escrito una aplicación muy similar a la que hice en C++ con alguna mejora y en delphi.
La aplicación trabaja en consola, permite establecer la calidad de compresión jpg y va indicando los archivos convertidos.
Se trata de un ejemplo de lo que se puede hacer con la API GDI plus desde versiones antiguas del delphi usando API pura en una aplicación de muy poco peso:
program PngToJpg; {$APPTYPE CONSOLE} uses Windows; type TCLSID = TGUID; PCLSID = ^TCLSID; TImageCodecInfo = packed record Clsid: TCLSID; FormatID: TGUID; CodecName: PWCHAR; DllName: PWCHAR; FormatDescription: PWCHAR; FilenameExtension: PWCHAR; MimeType: PWCHAR; Flags: DWORD; Version: DWORD; SigCount: DWORD; SigSize: DWORD; SigPattern: PBYTE; SigMask: PBYTE; end; PImageCodecInfo = ^TImageCodecInfo; TEncoderParameter = packed record Guid: TGUID; NumberOfValues: ULONG; Type_: ULONG; Value: Pointer; end; PEncoderParameter = ^TEncoderParameter; TEncoderParameters = packed record Count : UINT; Parameter : array[0..0] of TEncoderParameter; end; PEncoderParameters = ^TEncoderParameters; function atoi(str: PCHAR): Integer; cdecl external 'crtdll'; function wcscpy(wstr1, wstr2: PWCHAR): Integer; cdecl external 'crtdll'; function wcscmp(wstr1, wstr2: PWCHAR): Integer; cdecl external 'crtdll'; function wcslen(wstr: PWCHAR): Integer; cdecl external 'crtdll'; function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): Cardinal; stdcall external 'gdiplus'; procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus'; function GdipCreateHBITMAPFromBitmap(GBitmap: THANDLE; var hBitmap: HBITMAP; BKColor: DWORD): Cardinal; stdcall external 'gdiplus'; function GdipGetImageEncodersSize(var numEncoders: DWORD; var size: DWORD): Cardinal; stdcall external 'gdiplus'; function GdipGetImageEncoders(numEncoders, size: DWORD; encoders: PImageCodecInfo): Cardinal; stdcall external 'gdiplus'; function GdipSaveGraphics(graphics: Pointer; state: Pointer): Cardinal; stdcall external 'gdiplus'; function GdipLoadImageFromFile(filename: PWCHAR; var image: THANDLE): Cardinal; stdcall external 'gdiplus'; function GdipSaveImageToFile(image: THANDLE; filename: PWCHAR; var clsidEncoder: TCLSID; encoderParams: Pointer): Cardinal; stdcall external 'gdiplus'; // Calidad de imagen y factor de compresión // Quality = 100 es la maxima calidad. procedure GetEncoderParameters(EP: PEncoderParameters; Quality: PULONG); const EncoderQuality: TGUID = '{1d5be4b5-fa4a-452d-9cdd-5db35105e7eb}'; begin EP.Count:= 1; EP.Parameter[0].Guid:= EncoderQuality; EP.Parameter[0].Type_:= 4; //Gdiplus::EncoderParameterValueTypeLong; EP.Parameter[0].NumberOfValues:= 1; EP.Parameter[0].Value:= Quality; end; // Obtener el CLSID para la codificación de un formato gráfico function GetEncoderClsid(Format: PWCHAR; var Clsid: TCLSID): boolean; var i, N, Size: Cardinal; ICInfo: array of TImageCodecInfo; begin Result:= false; i:= 0; N:= 0; Size:= 0; GdipGetImageEncodersSize(N, Size); if Size > 0 then begin SetLength(ICInfo, Size); GdipGetImageEncoders(N, Size, @ICInfo[0]); while (i<N) and (wcscmp(ICInfo[i].MimeType, Format)<>0) do inc(i); if i<N then Clsid:= ICInfo[i].Clsid; end; Result:= boolean(i<N); end; // La conversión de formato procedure _ToJpg(FileName: PWCHAR; Parameters: PEncoderParameters); var Clsid: TCLSID; Image: THANDLE; begin GetEncoderClsid('image/jpeg', Clsid); GdipLoadImageFromFile(FileName, Image); wcscpy(@FileName[wcslen(FileName)-4], '.jpg'); GdipSaveImageToFile(Image, FileName, Clsid, Parameters); end; var gdiplusToken: DWORD; GdiPlusStartupInput: array[0..2] of int64; hFindFile: Cardinal; WFData: WIN32_FIND_DATAW; EP: TEncoderParameters; Quality: ULONG; buffer: array [0..20] of char; begin // Inicializamos GDI+. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0; if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) <> 0 then begin Write('GDI+ Error.'); exit; end; // Ajustamos Calidad de compresión Write('Choose Quality 1-100: '); Readln(buffer); Quality:= atoi(buffer); GetEncoderParameters(@EP, @Quality); // Buscamos los archivos png y los convertimos hFindFile:= FindFirstFileW('*.png', WFData); if(hFindFile <> INVALID_HANDLE_VALUE) then repeat _ToJpg(WFData.cFileName, @EP); WriteLn(WFData.cFileName); until not FindNextFileW(hFindFile, WFData); FindClose(hFindFile); // Terminamos la la aplicación Write('Press Enter to continue...'); Readln; //shutdown GDI+ GdiplusShutdown(gdiplusToken); end.
Subo el fuente y el binario. Espero que sea de utilidad, o al menos de curiosidad.
Saludos.
Attached Files
#7
Posted 26 January 2012 - 06:31 PM
Discúlpa Escafandra, no se porque no me llegó a mi correo ninguna notificación de que hubiera más mensajes para el problema planteado
Voy a ingresar diariamente al foro par evitar que vuelva a ocurrir
Saludos
Roberto