Ir al contenido



Foto

[MULTILENGUAJE] Extrayendo los archivos multiframe con GDIplus


  • Por favor identifícate para responder
2 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.789 mensajes
  • LocationMadrid - España

Escrito 09 septiembre 2018 - 09:42

En esta ocasión os voy a mostrar una pequeña aplicación de consola que extrae y escribe en disco cada imagen de un archivo multiframe. El formato de escritura será cualquiera de los que soporta GDI+, por defecto es jpg y la calidad de compresión será configurable de 1 a 100, siendo 100 por defecto. Los nombres de los archivos escritos serán como el del original añadiendo un número que corresponde al indice del frame extraído.
 
La sintaxis:


delphi
  1. GrExtract FileName [format graphic Ext] [%Quality]

Esta es la unidad corazón del sistema:


delphi
  1. unit GDI_Extract;
  2.  
  3. //------------------------------------------------------------------------------
  4. // GDI_Extract V 1.0
  5. // escafandra 2018
  6. // Clase para extraer archivos de un archivo grafico multipágina
  7. // Usa GDI+
  8.  
  9.  
  10. interface
  11.  
  12. uses
  13. Windows;
  14.  
  15.  
  16. type
  17. TCLSID = TGUID;
  18. PCLSID = ^TCLSID;
  19. TImageCodecInfo = packed record
  20. Clsid: TCLSID;
  21. FormatID: TGUID;
  22. CodecName: PWCHAR;
  23. DllName: PWCHAR;
  24. FormatDescription: PWCHAR;
  25. FilenameExtension: PWCHAR;
  26. MimeType: PWCHAR;
  27. Flags: DWORD;
  28. Version: DWORD;
  29. SigCount: DWORD;
  30. SigSize: DWORD;
  31. SigPattern: PBYTE;
  32. SigMask: PBYTE;
  33. end;
  34. PImageCodecInfo = ^TImageCodecInfo;
  35.  
  36. TEncoderParameter = packed record
  37. Guid: TGUID;
  38. NumberOfValues: ULONG;
  39. Type_: ULONG;
  40. Value: Pointer;
  41. end;
  42. PEncoderParameter = ^TEncoderParameter;
  43.  
  44. TEncoderParameters = packed record
  45. Count : UINT;
  46. Parameter : array[0..0] of TEncoderParameter;
  47. end;
  48. PEncoderParameters = ^TEncoderParameters;
  49.  
  50. function Extract(FileName, _format: PWCHAR; Quality: ULONG = 100): boolean;
  51.  
  52. function wcscmp(wstr1, wstr2: PWCHAR): Integer; cdecl external 'crtdll';
  53. function wsprintfW(lpOut, lpFmt: PWCHAR): Integer; cdecl; varargs; external 'User32.dll' name 'wsprintfW';
  54. function AttachConsole(dwProcessId: DWORD): BOOL; stdcall external 'Kernel32.dll';
  55.  
  56. // GDI+ Flat API...
  57. function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): Cardinal; stdcall external 'gdiplus';
  58. procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus';
  59. function GdipLoadImageFromFile(lpFileName: PWideChar; var hImage: THANDLE): DWORD; stdcall external 'gdiplus';
  60. function GdipImageGetFrameDimensionsList(hImage: THANDLE; dimensionIDs: PGUID; Count: Integer): DWORD; stdcall external 'gdiplus';
  61. function GdipImageGetFrameCount(hImage: THANDLE; lpDimensionID: PGUID; out Count: UINT): DWORD; stdcall external 'gdiplus';
  62. function GdipImageSelectActiveFrame(hImage: THANDLE; DimensionID: PGUID; frameIndex: Integer): DWORD; stdcall external 'gdiplus';
  63. function GdipGetImageEncodersSize(var numEncoders: DWORD; var size: DWORD): Cardinal; stdcall external 'gdiplus';
  64. function GdipGetImageEncoders(numEncoders, size: DWORD; encoders: PImageCodecInfo): Cardinal; stdcall external 'gdiplus';
  65. function GdipDisposeImage(image: THANDLE): Cardinal; stdcall external 'gdiplus';
  66. function GdipSaveImageToFile(image: THANDLE; FileName: PWCHAR; var clsidEncoder: TCLSID; encoderParams: Pointer): Cardinal; stdcall external 'gdiplus';
  67.  
  68.  
  69. implementation
  70.  
  71. // Calidad de imagen y factor de compresión
  72. // Quality = 100 es la maxima calidad.
  73. procedure GetEncoderParameters(EP: PEncoderParameters; Quality: PULONG);
  74. const
  75. EncoderQuality: TGUID = '{1d5be4b5-fa4a-452d-9cdd-5db35105e7eb}';
  76. begin
  77. EP.Count:= 1;
  78. EP.Parameter[0].Guid:= EncoderQuality;
  79. EP.Parameter[0].Type_:= 4; //Gdiplus::EncoderParameterValueTypeLong;
  80. EP.Parameter[0].NumberOfValues:= 1;
  81. EP.Parameter[0].Value:= Quality;
  82. end;
  83.  
  84. // Obtener el CLSID para la codificación de un formato gráfico
  85. function GetEncoderClsid(Format: PWCHAR; var Clsid: TCLSID): boolean;
  86. var
  87. i, N, Size: Cardinal;
  88. ICInfo: array of TImageCodecInfo;
  89. begin
  90. i:= 0; N:= 0; Size:= 0;
  91. GdipGetImageEncodersSize(N, Size);
  92. if Size > 0 then
  93. begin
  94. SetLength(ICInfo, Size);
  95. GdipGetImageEncoders(N, Size, @ICInfo[0]);
  96. while (i<N) and (wcscmp(ICInfo[i].MimeType, Format)<>0) do inc(i);
  97. if i<N then Clsid:= ICInfo[i].Clsid;
  98. end;
  99. Result:= boolean(i<N);
  100. end;
  101.  
  102. function Extract(FileName, _format: PWCHAR; Quality: ULONG = 100): boolean;
  103. var
  104. gdiplusToken: DWORD;
  105. GdiPlusStartupInput: array[0..2] of int64;
  106. hGdipImage: THANDLE;
  107. Clsid: TCLSID;
  108. EP: TEncoderParameters;
  109. dimensionID: TGUID;
  110. Frames: UINT;
  111. Index: integer;
  112. Format: Array [0..80] of WCHAR;
  113. lpFile: Array [0..MAX_PATH] of WCHAR;
  114. Ext: PWCHAR;
  115. begin
  116. Result:= false;
  117.  
  118. // Inicializamos GDI+.
  119. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0;
  120. if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) <> 0 then exit;
  121.  
  122. if lstrcmpiW(_format, 'jpg') = 0 then
  123. wsprintfW(@Format, 'image/jpeg')
  124.   else if lstrcmpiW(_format, 'tif') = 0 then
  125.     wsprintfW(@Format, 'image/tiff')
  126. else
  127. wsprintfW(@Format, 'image/%s', _format);
  128.  
  129. lstrcpyW(@lpFile, FileName);
  130. Ext:= @lpFile[lstrlenW(@lpFile)-4];
  131.  
  132. if GdipLoadImageFromFile(FileName, hGdipImage) <> 0 then exit;
  133. if hGdipImage = 0 then exit;
  134.  
  135. GetEncoderClsid(@Format, Clsid);
  136. GetEncoderParameters(@EP, @Quality);
  137.  
  138. if hGdipImage <> 0 then
  139. begin
  140. GdipImageGetFrameDimensionsList(hGdipImage, @dimensionID, 1);
  141. GdipImageGetFrameCount(hGdipImage, @dimensionID, Frames);
  142. for Index:= 0 to Frames-1 do
  143. begin
  144. GdipImageSelectActiveFrame(hGdipImage, @dimensionID, Index);
  145. wsprintfW(Ext, '%d.%s', Index, _format);
  146. GdipSaveImageToFile(hGdipImage, @lpFile, Clsid, @EP);
  147. end;
  148. end;
  149. GdipDisposeImage(hGdipImage);
  150. GdiplusShutdown(gdiplusToken);
  151. Result:= true;
  152. end;
  153.  
  154. end.

Y esta es la aplicación de consola que sirve de interface:


delphi
  1. program Gr_Extract;
  2.  
  3.  
  4. uses
  5. Windows, ShellAPI, GDI_Extract;
  6.  
  7.  
  8. function _wtoi(wstr: PWCHAR): Integer; cdecl external 'crtdll';
  9.  
  10. type
  11. AWCHAR = Array [0..10] of PWCHAR;
  12. PAWCHAR = ^AWCHAR;
  13.  
  14. var
  15. Argc: integer;
  16. Argv: PAWCHAR;
  17. Help: ShortString;
  18. F: THANDLE;
  19. begin
  20. // Buscando los parámetros pasados
  21. Argv:= PAWCHAR(CommandLineToArgvW(GetCommandLineW, Argc));
  22.  
  23. // Si no hay parámetros, muestro ayuda
  24. if Argc <= 1 then
  25. begin
  26. Help:= #10+#10+'GrExtract FileName [format graphic Ext] [%Quality]' +#10 + #0;
  27. AttachConsole(DWORD(-1));
  28. F:= CreateFile('CONOUT$', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  29. WriteConsole(F, @Help[1], lstrlen(@Help[1]), PDWORD(nil)^, nil);
  30. CloseHandle(F);
  31. FreeConsole;
  32. end
  33. else if Argc = 2 then
  34. Extract(Argv[1], 'jpg')
  35. else if Argc = 3 then
  36. Extract(Argv[1], Argv[2])
  37. else if Argc > 3 then
  38. Extract(Argv[1], Argv[2], _wtoi(Argv[3]));
  39.  
  40. end.

Si la aplicación se ejecuta en una consola mostrará los errores de sintaxis en ella. En caso contrario será mudo. Para realizar la extracción de los frames de un archivo Gif o Tif, soltadlo sobre el ejecutable o usad la consola para pasar más parámetros.
 
 
 
Saludos.

Archivos adjuntos


  • 0

#2 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.789 mensajes
  • LocationMadrid - España

Escrito 09 septiembre 2018 - 09:45

La versión C/Cpp es idéntica:
 

La sintaxis:


php
  1. GrExtract FileName [format graphic Ext] [%Quality]

La unidad extractora:


cpp
  1. //------------------------------------------------------------------------------
  2. // GifExtract V 1.0
  3. // escafandra 2018
  4. // Clase para representar un gif estático o animado sobre cualquier ventana.
  5. // Usa GDI+
  6.  
  7.  
  8. #include <windows.h>
  9. #include <initguid.h>
  10. #pragma hdrstop
  11.  
  12. #pragma link "gdiplus.lib"
  13.  
  14. struct EncoderParameter
  15. {
  16. GUID Guid; // GUID of the parameter
  17. ULONG NumberOfValues; // Number of the parameter values
  18. ULONG Type; // Value type, like ValueTypeLONG etc.
  19. VOID* Value; // A pointer to the parameter values
  20. };
  21.  
  22. struct EncoderParameters
  23. {
  24. UINT Count; // Number of parameters in this struct
  25. EncoderParameter Parameter[1]; // Parameter values
  26. };
  27.  
  28. struct ImageCodecInfo
  29. {
  30. CLSID Clsid;
  31. GUID FormatID;
  32. PWCHAR CodecName;
  33. PWCHAR DllName;
  34. PWCHAR FormatDescription;
  35. PWCHAR FilenameExtension;
  36. PWCHAR MimeType;
  37. DWORD Flags;
  38. DWORD Version;
  39. DWORD SigCount;
  40. DWORD SigSize;
  41. PBYTE SigPattern;
  42. PBYTE SigMask;
  43. };
  44.  
  45. extern "C"{
  46. DWORD __stdcall GdiplusStartup(ULONG_PTR *hToken, void *input, void *Output);
  47. void __stdcall GdiplusShutdown(ULONG_PTR token);
  48. DWORD __stdcall GdipLoadImageFromFile(PWCHAR FileName, HANDLE &hImage);
  49. DWORD __stdcall GdipSaveImageToFile(HANDLE himage, PWCHAR FileName, CLSID &clsidEncoder, void *encoderParams);
  50. DWORD __stdcall GdipGetImageEncodersSize(UINT *numEncoders, UINT *size);
  51. DWORD __stdcall GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders);
  52. DWORD __stdcall GdipImageGetFrameDimensionsList(HANDLE image, GUID* dimensionIDs, UINT count);
  53. DWORD __stdcall GdipImageGetFrameCount(HANDLE image, const GUID* dimensionIDs, UINT *count);
  54. DWORD __stdcall GdipImageSelectActiveFrame(HANDLE image, const GUID* dimensionIDs, UINT frameIndex);
  55. DWORD __stdcall GdipDisposeImage(HANDLE hImage);
  56. }
  57.  
  58.  
  59. WCHAR lpFile[MAX_PATH];
  60.  
  61. //---------------------------------------------------------------------------
  62.  
  63. void GetEncoderParameters(EncoderParameters *EP, PULONG Quality)
  64. {
  65. // Calidad de imagen y dfactor de compresión
  66. // 100 = maxima calidad
  67. // _GUID _EncoderQuality: Adaptado de GdiplusImaging.h para evitar error en Link
  68. _GUID _EncoderQuality = {0x1d5be4b5,0xfa4a,0x452d,0x9c,0xdd,0x5d,0xb3,0x51,0x05,0xe7,0xeb};
  69. EP->Count = 1;
  70. EP->Parameter[0].Guid = _EncoderQuality;
  71. EP->Parameter[0].Type = 4; //Gdiplus::EncoderParameterValueTypeLong; //GdiplusEnums.h
  72. EP->Parameter[0].NumberOfValues = 1;
  73. EP->Parameter[0].Value = Quality;
  74. }
  75. //---------------------------------------------------------------------------
  76.  
  77. bool GetEncoderClsid(const WCHAR* Format, CLSID* Clsid)
  78. {
  79. UINT i=0, N=0, Size=0;
  80.  
  81. GdipGetImageEncodersSize(&N, &Size);
  82. if(!Size) return false;
  83.  
  84. ImageCodecInfo* ICInfo = new ImageCodecInfo[Size];
  85. GdipGetImageEncoders(N, Size, ICInfo);
  86.  
  87. while (i<N && wcscmp(ICInfo[i].MimeType, Format)) i++;
  88. if(i<N) *Clsid = ICInfo[i].Clsid;
  89. delete [] ICInfo;
  90.  
  91. return (i<N);
  92. }
  93. //---------------------------------------------------------------------------
  94.  
  95.  
  96. BOOL __stdcall Extract(PWCHAR FileName, PWCHAR format, ULONG Quality = 100)
  97. {
  98. ULONG_PTR gdiplusToken;
  99. char GdiPlusStartupInput[16] = {1,0};
  100. HANDLE hGdipImage;
  101. GUID dimensionID;
  102. UINT Frames;
  103. CLSID Clsid;
  104. EncoderParameters EP;
  105. WCHAR Format[20];
  106.  
  107. GdiplusStartup(&gdiplusToken, GdiPlusStartupInput, NULL);
  108.  
  109. if(!lstrcmpiW(format, L"jpg"))
  110. wsprintfW(Format, L"image/jpeg");
  111.   else if(!lstrcmpiW(format, L"tif"))
  112.     wsprintfW(Format, L"image/tiff");
  113. else
  114. wsprintfW(Format, L"image/%s", format);
  115.  
  116. lstrcpyW(lpFile, FileName);
  117. PWCHAR Ext = &lpFile[lstrlenW(lpFile)-4];
  118.  
  119. if(GdipLoadImageFromFile(FileName, hGdipImage) !=0) return false;
  120. if(!hGdipImage) return false;
  121. GetEncoderClsid(Format, &Clsid);
  122. GetEncoderParameters(&EP, &Quality);
  123.  
  124. if(hGdipImage){
  125. GdipImageGetFrameDimensionsList(hGdipImage, &dimensionID, 1);
  126. GdipImageGetFrameCount(hGdipImage, &dimensionID, &Frames);
  127. for(int Index = 0; Index < Frames; Index++){
  128. GdipImageSelectActiveFrame(hGdipImage, &dimensionID, Index);
  129. wsprintfW(Ext, L"%d.%s", Index, format);
  130. GdipSaveImageToFile(hGdipImage, lpFile, Clsid, &EP);
  131. }
  132. }
  133. GdipDisposeImage(hGdipImage);
  134. GdiplusShutdown(gdiplusToken);
  135. return true;
  136. }

Y la interface de consola:


cpp
  1. //---------------------------------------------------------------------------
  2.  
  3. #include <windows.h>
  4. #pragma hdrstop
  5.  
  6. #pragma link "gdiplus.lib"
  7.  
  8. typedef BOOL (WINAPI *PAttachConsole)(DWORD dwProcessId);
  9.  
  10. BOOL __stdcall Extract(PWCHAR FileName, PWCHAR format, ULONG Quality = 100);
  11.  
  12. PWCHAR lpFileName;
  13.  
  14. //---------------------------------------------------------------------------
  15. #pragma argsused
  16. WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  17. {
  18. int Argc;
  19. LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
  20. if(Argc <= 1){
  21. char Help[] = "\nGrExtract FileName [format graphic Ext] [%Quality]\n";
  22. PAttachConsole AttachConsole = (PAttachConsole)GetProcAddress(GetModuleHandle("Kernel32.dll"), "AttachConsole");
  23. AttachConsole(-1);
  24. HANDLE F = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0 );
  25. WriteConsole(F, Help, lstrlen(Help), 0, 0);
  26. }
  27. else if(Argc == 2)
  28. Extract(Argv[1], L"jpg");
  29. else if(Argc == 3)
  30. Extract(Argv[1], Argv[2]);
  31. else if(Argc > 3)
  32. Extract(Argv[1], Argv[2], _wtoi(Argv[3]));
  33. return 0;
  34. }
  35. //---------------------------------------------------------------------------

Saludos.

Archivos adjuntos


  • 0

#3 ELKurgan

ELKurgan

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 533 mensajes
  • LocationEspaña

Escrito 10 septiembre 2018 - 12:54

Como siempre, impresionante

 

Gracias por el aporte


  • 0