Jump to content


Photo

[MULTILENGUAJE] Escribir archivos gráficos multipágina


  • Please log in to reply
3 replies to this topic

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 18 June 2014 - 07:09 AM

Como complemento al truco Leer archivos gráficos multipágina en varios formatos publico la forma de hacer lo contrario.

Debe quedar claro que hasta el momento no funciona salvo para archivos.tif pues M$ no lo ha implementado para gif en la versión GDI+ 1.0.
 

delphi
  1. uses
  2.   Windows;
  3.  
  4. type
  5. TCLSID = TGUID;
  6. PCLSID = ^TCLSID;
  7. TImageCodecInfo = packed record
  8.   Clsid:            TCLSID;
  9.   FormatID:          TGUID;
  10.   CodecName:        PWCHAR;
  11.   DllName:          PWCHAR;
  12.   FormatDescription: PWCHAR;
  13.   FilenameExtension: PWCHAR;
  14.   MimeType:          PWCHAR;
  15.   Flags:            DWORD;
  16.   Version:          DWORD;
  17.   SigCount:          DWORD;
  18.   SigSize:          DWORD;
  19.   SigPattern:        PBYTE;
  20.   SigMask:          PBYTE;
  21. end;
  22. PImageCodecInfo = ^TImageCodecInfo;
  23.  
  24. TEncoderParameter = packed record
  25.   Guid:          TGUID;
  26.   NumberOfValues: ULONG;
  27.   Type_:          ULONG;
  28.   Value:          Pointer;
  29. end;
  30. PEncoderParameter = ^TEncoderParameter;
  31.  
  32. TEncoderParameters = packed record
  33.   Count    : UINT;
  34.   Parameter : array[0..1] of TEncoderParameter;
  35. end;
  36. PEncoderParameters = ^TEncoderParameters;
  37.  
  38. function  wcscmp(wstr1, wstr2: PWCHAR): Integer; cdecl external 'crtdll';
  39.  
  40. // GDI+ Flat API...
  41. function  GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): Cardinal; stdcall external 'gdiplus';
  42. procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus';
  43. function  GdipCreateBitmapFromHBITMAP(hbm: HBITMAP; hpal: HPALETTE; var GBitmap: THANDLE): Cardinal; stdcall external 'gdiplus';
  44. function  GdipCreateHBITMAPFromBitmap(GBitmap: THANDLE; var hBitmap: HBITMAP; BKColor: DWORD): DWORD; stdcall external 'gdiplus';
  45. function  GdipGetImageEncodersSize(var numEncoders: DWORD; var size: DWORD): Cardinal; stdcall external 'gdiplus';
  46. function  GdipGetImageEncoders(numEncoders, size: DWORD; encoders: PImageCodecInfo): Cardinal; stdcall external 'gdiplus';
  47. function  GdipDisposeImage(image: THANDLE): Cardinal; stdcall external 'gdiplus';
  48. function  GdipCreateBitmapFromFile(lpFileName: PWCHAR; var GBitmap: THANDLE): DWORD; stdcall external 'gdiplus';
  49. function  GdipSaveImageToFile(image: THANDLE; FileName: PWCHAR; var clsidEncoder: TCLSID; encoderParams: Pointer): Cardinal; stdcall external 'gdiplus';
  50.  
  51. function  GdipImageGetFrameDimensionsList(image: THANDLE; var dimensionIDs: TGUID; count: DWORD): DWORD; stdcall external 'gdiplus';
  52. function  GdipImageGetFrameCount(image: THANDLE; var dimensionID: TGUID; var count: DWORD): DWORD; stdcall external 'gdiplus';
  53. function  GdipImageSelectActiveFrame(image: THANDLE; var dimensionID: TGUID; frameIndex: DWORD): DWORD; stdcall external 'gdiplus';
  54.  
  55. function GdipSaveAddImage(image: THANDLE; newImage: THANDLE; encoderParams: Pointer): DWORD; stdcall external 'gdiplus';
  56. function GdipSaveAdd(image: THANDLE; encoderParams: Pointer): DWORD; stdcall external 'gdiplus';
  57.  
  58. // Obtener el CLSID para la codificación de un formato gráfico
  59. function GetEncoderClsid(Format: PWCHAR; var Clsid: TCLSID): boolean;
  60. var
  61.   i, N, Size: Cardinal;
  62.   ICInfo: array of TImageCodecInfo;
  63. begin
  64.   i:= 0; N:= 0; Size:= 0;
  65.   GdipGetImageEncodersSize(N, Size);
  66.   if Size > 0 then
  67.   begin
  68.     SetLength(ICInfo, Size);
  69.     GdipGetImageEncoders(N, Size, @ICInfo[0]);
  70.     while (i<N) and (wcscmp(ICInfo[i].MimeType, Format)<>0) do inc(i);
  71.     if i<N then Clsid:= ICInfo[i].Clsid;
  72.   end;
  73.   Result:= boolean(i<N);
  74. end;
  75.  
  76. function CreateHBITMAPFromFilePage(FileName: PWCHAR; Index: DWORD): HBITMAP;
  77. var
  78.   GBitmap: THANDLE;
  79.   DimensionID: TGUID;
  80.   Frames: DWORD;
  81. begin
  82.   Result:= 0;
  83.  
  84.   GdipCreateBitmapFromFile(PWCHAR(FileName), GBitmap);
  85.   GdipImageGetFrameDimensionsList(GBitmap, dimensionID, 1);
  86.   GdipImageGetFrameCount(GBitmap, dimensionID, Frames);
  87.   GdipImageSelectActiveFrame(GBitmap, dimensionID, Index mod Frames);
  88.   GdipCreateHBITMAPFromBitmap(GBitmap, Result, 0);
  89.  
  90. end;
  91.  
  92. //---------------------------------------------------------------------------
  93. // Guarda un HBITMAP en un archivo con un formato gráfico determinado
  94. type
  95. ABITMAP = array of HBITMAP;
  96. procedure SaveBitmapToMultipageFileW(Bitmaps: ABITMAP; FileName, Format: PWCHAR; Quality: ULONG=100);
  97. const
  98.   EncoderQuality: TGUID = '{1d5be4b5-fa4a-452d-9cdd-5db35105e7eb}';
  99.   EncoderSaveFlag: TGUID = '{292266fc-ac40-47bf-8cfc-a85b89a655de}';
  100.   EncoderParameterValueTypeLong = 4;
  101.   EncoderValueMultiFrame = 18;
  102.   EncoderValueLastFrame = 19;
  103.   EncoderValueFlush = 20;
  104.   EncoderValueFrameDimensionPage = 23;
  105. var
  106.   i: integer;
  107.   Clsid: TCLSID;
  108.   EP: TEncoderParameters;
  109.   Image, newImage: THANDLE;
  110.   parameterValue: ULONG;
  111. begin
  112.   EP.Count:= 2;
  113.   EP.Parameter[0].Guid:= EncoderQuality;
  114.   EP.Parameter[0].Type_:= EncoderParameterValueTypeLong;
  115.   EP.Parameter[0].NumberOfValues:= 1;
  116.   EP.Parameter[0].Value:= @Quality;
  117.   EP.Parameter[1].Guid:= EncoderSaveFlag;
  118.   EP.Parameter[1].Type_:= EncoderParameterValueTypeLong;
  119.   EP.Parameter[1].NumberOfValues:= 1;
  120.   EP.Parameter[1].Value:= @parameterValue;
  121.  
  122.   parameterValue:= EncoderValueMultiFrame;
  123.   GetEncoderClsid(Format, Clsid);
  124.   GdipCreateBitmapFromHBITMAP(Bitmaps[0], 0, Image);
  125.   GdipSaveImageToFile(Image, FileName, Clsid, @EP);
  126.  
  127.   parameterValue:= EncoderValueFrameDimensionPage;
  128.   for i:= 1 to Length(Bitmaps)-1 do
  129.   begin
  130.     GdipCreateBitmapFromHBITMAP(Bitmaps[i], 0, newImage);
  131.     GdipSaveAddImage(Image, newImage, @EP);
  132.   end;
  133.   parameterValue:= EncoderValueFlush;
  134.   GdipSaveAdd(Image, @EP);
  135.  
  136.   GdipDisposeImage(Image);
  137.   GdipDisposeImage(newImage);
  138. end;

SaveBitmapToMultipageFileW recibe un array de HBITMAPS y los guarda en un archivo con calidad de compresión ajustable. Dado que sólo funciona para tif, quizás el argumento Format sobre, pero si en un futuro se añaden los gif, es muy posible que funcione sin cambios en el código.

Un ejemplo de uso:



delphi
  1. var
  2.   gdiplusToken: DWORD;
  3.   GdiPlusStartupInput: array[0..2] of int64;
  4.   Bitmaps: ABITMAP;
  5.   i: integer;
  6. begin
  7.   // Inicializamos GDI+.
  8.   GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0;
  9.   if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) <> 0 then exit;
  10.  
  11.   // lo que sigue es para conseguir varias imágenes...
  12.   SetLength(Bitmaps, 5);
  13.   for i:=0 to 4 do
  14.   begin
  15.     Bitmaps[i]:= CreateHBITMAPFromFilePage('Fax1.tif', i);
  16.   end;
  17.  
  18.   // El ejemplo de uso. Solo funciona con Tif, no con Gif
  19.   SaveBitmapToMultipageFileW(Bitmaps, 'Imagen.tif', 'image/tiff');
  20.  
  21.   // Shutdown GDI+
  22.   GdiplusShutdown(gdiplusToken);
  23. end.

Saludos.
  • 0

#2 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 18 June 2014 - 07:28 AM

Y el código anterior en C



cpp
  1. #include <windows.h>
  2.  
  3. #pragma link "gdiplus.lib"
  4.  
  5. struct EncoderParameter
  6. {
  7.   GUID    Guid;              // GUID of the parameter
  8.   ULONG  NumberOfValues;    // Number of the parameter values
  9.   ULONG  Type;              // Value type, like ValueTypeLONG  etc.
  10.   VOID*  Value;              // A pointer to the parameter values
  11. };
  12.  
  13. struct EncoderParameters
  14. {
  15.   UINT Count;                    // Number of parameters in this structure
  16.   EncoderParameter Parameter[2]; // Parameter values
  17. };
  18.  
  19. struct ImageCodecInfo
  20. {
  21.   CLSID Clsid;
  22.   GUID FormatID;
  23.   PWCHAR CodecName;
  24.   PWCHAR DllName;
  25.   PWCHAR FormatDescription;
  26.   PWCHAR FilenameExtension;
  27.   PWCHAR MimeType;
  28.   DWORD Flags;
  29.   DWORD Version;
  30.   DWORD SigCount;
  31.   DWORD SigSize;
  32.   PBYTE SigPattern;
  33.   PBYTE SigMask;
  34. };
  35.  
  36.  
  37. extern "C"{
  38. DWORD WINAPI GdiplusStartup(ULONG_PTR *hToken, void *input, void *Output);
  39. void  WINAPI GdiplusShutdown(ULONG_PTR token);
  40. DWORD WINAPI GdipCreateBitmapFromFile(WCHAR* filename, HANDLE* bitmap);
  41. DWORD WINAPI GdipCreateHBITMAPFromBitmap(HANDLE bitmap, HBITMAP* hBitmap, DWORD BKColor);
  42. DWORD WINAPI GdipCreateBitmapFromHBITMAP(HBITMAP hBmp, HPALETTE hPal, HANDLE* GBitmap);
  43. DWORD WINAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size);
  44. DWORD WINAPI GdipGetImageEncoders(UINT numEncoders,  UINT size, ImageCodecInfo *encoders);
  45. DWORD WINAPI GdipLoadImageFromFile(PWCHAR FileName, HANDLE &hImage);
  46. DWORD WINAPI GdipSaveImageToFile(HANDLE himage, PWCHAR FileName, CLSID &clsidEncoder, void *encoderParams);
  47. DWORD WINAPI GdipDisposeImage(HANDLE himage);
  48. DWORD WINAPI GdipDrawImageRect(HANDLE hGraphics, HANDLE himage, float x, float y, float width, float height);
  49. DWORD WINAPI GdipCreateFromHDC(HDC hDC, HANDLE* hGraphics);
  50. DWORD WINAPI GdipCreateBitmapFromHBITMAP(HBITMAP hBmp, HPALETTE hPal, HANDLE* GBitmap);
  51. DWORD WINAPI GdipDeleteGraphics(HANDLE hGraphics);
  52.  
  53. DWORD WINAPI GdipImageGetFrameDimensionsList(HANDLE image, PGUID dimensionIDs, UINT count);
  54. DWORD WINAPI GdipImageGetFrameCount(HANDLE image, PGUID dimensionIDs, UINT *count);
  55. DWORD WINAPI GdipImageSelectActiveFrame(HANDLE image, PGUID dimensionIDs, UINT frameIndex);
  56. DWORD WINAPI GdipSaveAddImage(HANDLE Image, HANDLE newImage, void *encoderParams);
  57. DWORD WINAPI GdipSaveAdd(HANDLE Image, void *encoderParams);
  58. }
  59.  
  60.  
  61. // Inicializamos GDI+
  62. ULONG_PTR  gdiplusToken;
  63. char GdiPlusStartupInput[16] = {1,0};
  64.  
  65. bool GetEncoderClsid(const WCHAR* Format, CLSID* Clsid)
  66. {
  67.   UINT i=0, N=0, Size=0;
  68.  
  69.   GdipGetImageEncodersSize(&N, &Size);
  70.   if(!Size) return false;
  71.  
  72.   ImageCodecInfo* ICInfo = new ImageCodecInfo[Size];
  73.   GdipGetImageEncoders(N, Size, ICInfo);
  74.  
  75.   while (i<N && wcscmp(ICInfo[i].MimeType, Format)) i++;
  76.   if(i<N) *Clsid = ICInfo[i].Clsid;
  77.   delete [] ICInfo;
  78.  
  79.   return (i<N);
  80. }
  81.  
  82. //---------------------------------------------------------------------------
  83. // Crea un HBITMAP desde un fichero pultipágina usando GDI+
  84. HBITMAP CreateHBITMAPFromFilePage(PWCHAR FileName, UINT Index)
  85. {
  86.   HBITMAP hBitmap = 0;
  87.   HANDLE GBitmap = 0;
  88.   GUID dimensionID;
  89.   UINT Frames;
  90.   GdipCreateBitmapFromFile(FileName, &GBitmap);
  91.   GdipImageGetFrameDimensionsList(GBitmap, &dimensionID, 1);
  92.   GdipImageGetFrameCount(GBitmap, &dimensionID, &Frames);
  93.   GdipImageSelectActiveFrame(GBitmap, &dimensionID, Index % Frames);
  94.   GdipCreateHBITMAPFromBitmap(GBitmap, &hBitmap, 0);
  95.   return hBitmap;
  96. }
  97.  
  98. void SaveBitmapToMultipageFileW(HBITMAP* Bitmaps, int Size, PWCHAR FileName, PWCHAR Format, ULONG Quality = 100)
  99. {
  100.   _GUID _EncoderQuality = {0x1d5be4b5,0xfa4a,0x452d,0x9c,0xdd,0x5d,0xb3,0x51,0x05,0xe7,0xeb};
  101.   _GUID _EncoderSaveFlag = {0x292266fc,0xac40,0x47bf,0x8c, 0xfc, 0xa8, 0x5b, 0x89, 0xa6, 0x55, 0xde};
  102.   int EncoderParameterValueTypeLong = 4;
  103.   int EncoderValueMultiFrame = 18;
  104.   int EncoderValueFlush = 20;
  105.   int EncoderValueFrameDimensionPage = 23;
  106.  
  107.   CLSID Clsid;
  108.   EncoderParameters EP;
  109.   HANDLE Image, newImage;
  110.   ULONG parameterValue;
  111.  
  112.   EP.Count = 2;
  113.   EP.Parameter[0].Guid = _EncoderQuality;
  114.   EP.Parameter[0].Type = EncoderParameterValueTypeLong;
  115.   EP.Parameter[0].NumberOfValues = 1;
  116.   EP.Parameter[0].Value = &Quality;
  117.   EP.Parameter[1].Guid = _EncoderSaveFlag;
  118.   EP.Parameter[1].Type = 4; //Gdiplus::EncoderParameterValueTypeLong;
  119.   EP.Parameter[1].NumberOfValues = 1;
  120.   EP.Parameter[1].Value = &parameterValue;
  121.  
  122.   parameterValue = EncoderValueMultiFrame;
  123.   GetEncoderClsid(Format, &Clsid);
  124.   GdipCreateBitmapFromHBITMAP(Bitmaps[0], 0, &Image);
  125.   GdipSaveImageToFile(Image, FileName, Clsid, &EP);
  126.   parameterValue = EncoderValueFrameDimensionPage;
  127.   for(int i = 1;  i< Size; i++){
  128.     parameterValue = EncoderValueFrameDimensionPage;
  129.     GdipCreateBitmapFromHBITMAP(Bitmaps[i], 0, &newImage);
  130.     GdipSaveAddImage(Image, newImage, &EP);
  131.   }
  132.   parameterValue = EncoderValueFlush;
  133.   GdipSaveAdd(Image, &EP);
  134.  
  135.   GdipDisposeImage(Image);
  136.   GdipDisposeImage(newImage);
  137. }




Y la forma de usarlo:


cpp
  1.   // Inicializamos GDI+
  2.   GdiplusStartup(&gdiplusToken, GdiPlusStartupInput, NULL);
  3.  
  4.   HBITMAP Bitmaps[6];
  5.   for(int i=0; i<6; i++)
  6.     Bitmaps[i] = CreateHBITMAPFromFilePage(L"archivo.gif", i);
  7.  
  8.   // Solo funciona con Tif, no con Gif
  9.   SaveBitmapToMultipageFileW(Bitmaps, 6, L"Imagen.tif", L"image/tiff");



Saludos.
  • 0

#3 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4945 posts
  • LocationMéxico

Posted 18 June 2014 - 08:06 AM

:D Gracias por el enorme aporte amigo.  No pude encontrar el enlace de gracias. :p Habrá que agregarlo al to-do
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 18 June 2014 - 08:12 AM

:D Gracias por el enorme aporte amigo.


No podía dejar cojo el tema, si puedes leer debes poder escribir  :D

No pude encontrar el enlace de gracias. :p Habrá que agregarlo al to-do

Hace un rato si estaba, quizás enecumene esté haciendo trabajos.  *-)


Saludos.
  • 0




IP.Board spam blocked by CleanTalk.