1 /*************************************************************************
2 
3    Copyright 2011 Yuri Dario <mc6530@mclink.it>
4 
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8 
9        http://www.apache.org/licenses/LICENSE-2.0
10 
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16 
17  ************************************************************************/
18 
19 #define INCL_WIN
20 #include <svpm.h>
21 
22 #ifndef _OS2CLIPBOARD_HXX_
23 #include "Os2Clipboard.hxx"
24 #endif
25 
26 // same typedefs from win32 sdk
27 typedef unsigned short WORD;
28 typedef unsigned long DWORD;
29 
30 #pragma pack(push, 1)
31 
32 typedef struct {
33   PM_BYTE rgbBlue;
34   PM_BYTE rgbGreen;
35   PM_BYTE rgbRed;
36   PM_BYTE rgbReserved;
37 } RGBQUAD, *LPRGBQUAD;
38 
39 typedef struct
40 {
41     WORD    bfType;
42     DWORD   bfSize;
43     WORD    bfReserved1;
44     WORD    bfReserved2;
45     DWORD   bfOffBits;
46 } W32_BITMAPFILEHEADER, *PW32_BITMAPFILEHEADER;
47 
48 typedef struct
49 {
50     DWORD 	biSize;
51     LONG  	biWidth;
52     LONG  	biHeight;
53     WORD 	biPlanes;
54     WORD 	biBitCount;
55     DWORD 	biCompression;
56     DWORD 	biSizeImage;
57     LONG  	biXPelsPerMeter;
58     LONG  	biYPelsPerMeter;
59     DWORD 	biClrUsed;
60     DWORD 	biClrImportant;
61 } W32_BITMAPINFOHEADER, *PW32_BITMAPINFOHEADER;
62 
63 #pragma pack(pop)
64 
65 // store screen bitcount
66 LONG	lBitCountScreen;
67 
68 /*
69  * Convert an OOo bitmap to an OS/2 bitmap handle
70  *
71  * An OOo bitmap is a BITMAPFILEHEADER structure followed by a Windows DIB
72  *
73  * OS/2 InfoHeader is a superset of Win32 InhoHeader, so we can just copy
74  * the win32 memory over the os2 memory and fix the cbFix field.
75  * colortable and bitmap data share the same format.
76  *
77 */
78 HBITMAP	OOoBmpToOS2Handle( Any &aAnyB)
79 {
80 	// copy bitmap to clipboard
81 	Sequence<sal_Int8> ByteStream;
82 	aAnyB >>= ByteStream;
83 
84 	// get w32 file header data
85 	PW32_BITMAPFILEHEADER pbfh = (PW32_BITMAPFILEHEADER)ByteStream.getArray();
86 	// get w32 info header
87 	PW32_BITMAPINFOHEADER pbih = (PW32_BITMAPINFOHEADER) (pbfh+1);
88 
89 	// create os2 infoheader2 (same fields of w32)
90 	BITMAPINFOHEADER2 bih2;
91 	memset( &bih2, 0, sizeof( bih2));
92 	memcpy( &bih2, pbih, pbih->biSize);
93 	bih2.cbFix = sizeof(bih2);
94 
95 	// Determine size of color table
96 	int iNumColors, numbits=bih2.cPlanes * bih2.cBitCount;
97 	if (numbits != 24)
98 		iNumColors = bih2.cclrUsed ? bih2.cclrUsed : 2<<numbits;
99 	else
100 		iNumColors = bih2.cclrUsed;
101 	int iColorTableSize = iNumColors*sizeof(RGB2);
102 
103 	// allocate bitmap info2 (header2+colortable)
104 	PBITMAPINFO2 pbi2=(PBITMAPINFO2) malloc( sizeof(BITMAPINFOHEADER2)+iColorTableSize);
105 	// setup header fields
106 	memcpy( pbi2, &bih2, sizeof(BITMAPINFOHEADER2));
107 	// copy color palette (follows pbih)
108 	memcpy( &pbi2->argbColor[0], (pbih+1), iColorTableSize);
109 
110 	// get bitmap data
111 	PBYTE pbPelData = (PBYTE)ByteStream.getArray() + pbfh->bfOffBits;
112 	HPS hps = WinGetPS(HWND_DESKTOP);
113 	HBITMAP hbm = GpiCreateBitmap( hps, &bih2, CBM_INIT, pbPelData, pbi2);
114 	debug_printf( "OOoBmpToOS2Handle hbm %x\n", hbm);
115 	WinReleasePS(hps);
116 
117 	// return handle
118 	return hbm;
119 }
120 
121 /*
122  * Convert an OS/2 bitmap handle to OOo bitmap
123  *
124  * First we need to copy the bitmap to a PS, then we can get bitmap data.
125  *
126 */
127 int	OS2HandleToOOoBmp( HBITMAP hbm, Sequence< sal_Int8 >* OOoDIBStream)
128 {
129 	HAB 	hab = WinQueryAnchorBlock(HWND_DESKTOP);
130 	HDC 	hdc;
131 	SIZEL 	sizl;
132 	HPS 	hps;
133 	PM_BYTE*	pbBuffer;
134 	ULONG	cbBuffer;
135 
136 	struct {
137 		BITMAPINFOHEADER2 bmp2;
138 		RGB2 argb2Color[0x100];
139 	} bm;
140 
141 	if (!lBitCountScreen) {
142 		HPS hps = WinGetPS(HWND_DESKTOP);
143 		HDC hdc = GpiQueryDevice(hps);
144 		DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1L, &lBitCountScreen);
145 		WinReleasePS(hps);
146 	}
147 
148 	// STEP 1: get OS/2 bitmap data and header
149 	// get bitmap header
150 	memset(&(bm.bmp2), 0, sizeof(bm.bmp2));
151 	bm.bmp2.cbFix = 16;
152 	GpiQueryBitmapInfoHeader(hbm, &bm.bmp2);
153 
154 	/* Data only actually stored in clipboard quality */
155 	if ( lBitCountScreen < bm.bmp2.cBitCount )
156 		bm.bmp2.cBitCount = lBitCountScreen;
157 
158 	if ( bm.bmp2.cBitCount == 16 )
159 		bm.bmp2.cBitCount = 24;
160 
161 	if ( bm.bmp2.cPlanes != 1 ) {
162 		return 0;
163 	}
164 
165 	if ( (hdc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL)) == (HDC) NULL ) {
166 		return 0;
167 	}
168 
169 	sizl.cx = bm.bmp2.cx;
170 	sizl.cy = bm.bmp2.cy;
171 	if ( (hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL ) {
172 		DevCloseDC(hdc);
173 		return 0;
174 	}
175 	// copy bitmap to hps
176 	GpiSetBitmap(hps, hbm);
177 
178 	// buffer lengths
179 	cbBuffer = (((bm.bmp2.cBitCount * bm.bmp2.cx) + 31) / 32) * 4 * bm.bmp2.cy * bm.bmp2.cPlanes;
180 	pbBuffer = (PM_BYTE*) malloc( cbBuffer);
181 	// now get bitmap data
182 	GpiQueryBitmapBits(hps, 0L, (LONG) bm.bmp2.cy, pbBuffer, (BITMAPINFO2*)&bm);
183 	// free OS/2 resources
184 	GpiSetBitmap(hps, (HBITMAP) NULL);
185 	GpiDestroyPS(hps);
186 	DevCloseDC(hdc);
187 
188 	// STEP 2: now convert to Win32 DIB
189 	// Determine size of color table
190 	int iNumColors, numbits=bm.bmp2.cPlanes * bm.bmp2.cBitCount;
191 	if (numbits != 24)
192 		iNumColors = bm.bmp2.cclrUsed ? bm.bmp2.cclrUsed : 2<<numbits;
193 	else
194 		iNumColors = bm.bmp2.cclrUsed;
195 	int iColorTableSize = iNumColors*sizeof(RGBQUAD);
196 
197 	// reallocate data stream object size
198 	OOoDIBStream->realloc( sizeof( W32_BITMAPFILEHEADER )
199 				+ sizeof( W32_BITMAPINFOHEADER) + iColorTableSize + cbBuffer);
200 
201 	// fill w32 file header data
202 	PW32_BITMAPFILEHEADER pbfh = (PW32_BITMAPFILEHEADER) OOoDIBStream->getArray();
203 	memset( pbfh, 0, sizeof( W32_BITMAPFILEHEADER));
204 	pbfh->bfType = 'MB';
205 	pbfh->bfSize = sizeof( W32_BITMAPFILEHEADER )
206 				+ sizeof( W32_BITMAPINFOHEADER) + iColorTableSize + cbBuffer;
207 	pbfh->bfOffBits = sizeof( W32_BITMAPFILEHEADER) + sizeof( W32_BITMAPINFOHEADER) + iColorTableSize;
208 
209 	// fill w32 info header
210 	PW32_BITMAPINFOHEADER pbih = (PW32_BITMAPINFOHEADER) (pbfh+1);
211 	// copy header fields (only win32 ones) and fix size
212 	memcpy( pbih, &bm.bmp2, sizeof(W32_BITMAPINFOHEADER));
213 	pbih->biSize = sizeof(W32_BITMAPINFOHEADER);
214 
215 	// fill color palette (follows pbih)
216 	memcpy( (pbih+1), &bm.argb2Color[0], iColorTableSize);
217 
218 	// fill bitmap data
219 	memcpy( (char*) pbfh + pbfh->bfOffBits, pbBuffer, cbBuffer);
220 
221 	// done
222 	free( pbBuffer);
223 	return 1;
224 }
225 
226 #ifdef TESTBMP
227 
228 #include <io.h>
229 #include <fcntl.h>
230 #include <stdio.h>
231 
232 int main( void)
233 {
234 	HAB hAB = WinQueryAnchorBlock( HWND_DESKTOP );
235 
236 	// query clipboard data to get mimetype
237 	if( WinOpenClipbrd( hAB ) )
238 	{
239 		ULONG handle = WinQueryClipbrdData( hAB, CF_BITMAP);
240 		if (handle) {
241 			Sequence< sal_Int8 > winDIBStream;
242 			// convert to oustring and return it
243 			if (OS2HandleToOOoBmp( handle, &winDIBStream) == 1) {
244 				printf( "Conversion ok.\n");
245 				int fd = open( "test.bmp", O_BINARY | O_CREAT | O_TRUNC | O_RDWR);
246 				printf( "writing to fd %d\n", fd);
247 				write( fd, winDIBStream.getArray(), winDIBStream.getLength());
248 				close( fd);
249 			} else
250 				printf( "failed conversion.\n");
251 
252 		}
253 		WinCloseClipbrd( hAB);
254 	}
255 	return 0;
256 }
257 
258 #endif //TESTBMP
259 
260