1//
2//  PXBitmapExporter.m
3//  Pixen-XCode
4//
5//  Created by Andy Matuschak on Wed Jun 09 2004.
6//  Copyright (c) 2004 Open Sword Group. All rights reserved.
7//
8
9#import "PXBitmapExporter.h"
10#import <QuickTime/QuickTime.h>
11//  PXBitmapExporter.m
12//  Pixen-XCode
13//
14//  Created by Andy Matuschak on Wed Jun 09 2004.
15//  Copyright (c) 2004 Open Sword Group. All rights reserved.
16//
17
18#import "PXBitmapExporter.h"
19#import <QuickTime/QuickTime.h>
20
21// BMPDataForImage by Florrent Pillet
22// myCreateHandleDataRef by Apple
23
24@implementation PXBitmapExporter
25
26Handle myCreateHandleDataRef(Handle dataHandle, Str255 fileName, OSType fileType, StringPtr mimeTypeString, Ptr initDataPtr, Size initDataByteCount)
27{
28	OSErr err;
29	Handle dataRef = nil;
30	Str31 tempName;
31	long atoms[3];
32	StringPtr name;
33
34	// First create a data reference handle for our data
35	err = PtrToHand( &dataHandle, &dataRef, sizeof(Handle));
36
37	if (err) goto bail;
38
39	// If this is QuickTime 3 or later, we can add
40	// the filename to the data ref to help importer
41	// finding process. Find uses the extension.
42
43	name = fileName;
44	if (name == nil)
45	{
46		tempName[0] = 0;
47		name = tempName;
48	}
49
50	// Only add the file name if we are also adding a
51	// file type, MIME type or initialization data
52
53	if ((fileType) || (mimeTypeString) || (initDataPtr))
54	{
55		err = PtrAndHand(name, dataRef, name[0]+1);
56		if (err) goto bail;
57	}
58
59	// If this is QuickTime 4, the handle data handler
60	// can also be told the filetype and/or
61	// MIME type by adding data ref extensions. These
62	// help the importer finding process.
63	// NOTE: If you add either of these, you MUST add
64	// a filename first -- even if it is an empty Pascal
65	// string. Under QuickTime 3, any data ref extensions
66	// will be ignored.
67
68	// to add file type, you add a classic atom followed
69	// by the Mac OS filetype for the kind of file
70	if (fileType)
71	{
72		atoms[0] = EndianU32_NtoB(sizeof(long) * 3);
73		atoms[1] = EndianU32_NtoB(kDataRefExtensionMacOSFileType);
74		atoms[2] = EndianU32_NtoB(fileType);
75		err = PtrAndHand(atoms, dataRef, sizeof(long) * 3);
76		if (err) goto bail;
77	}
78
79	// to add MIME type information, add a classic atom followed by
80	// a Pascal string holding the MIME type
81
82	if (mimeTypeString)
83	{
84		atoms[0] = EndianU32_NtoB(sizeof(long) * 2 + mimeTypeString[0]+1);
85		atoms[1] = EndianU32_NtoB(kDataRefExtensionMIMEType);
86		err = PtrAndHand(atoms, dataRef, sizeof(long) * 2);
87		if (err) goto bail;
88		err = PtrAndHand(mimeTypeString, dataRef, mimeTypeString[0]+1);
89		if (err) goto bail;
90	}
91
92	// add any initialization data, but only if a dataHandle was
93	// not already specified (any initialization data is ignored
94	// in this case)
95	if((dataHandle == nil) && (initDataPtr))
96	{
97		atoms[0] = EndianU32_NtoB(sizeof(long) * 2 + initDataByteCount);
98		atoms[1] = EndianU32_NtoB(kDataRefExtensionInitializationData);
99		err = PtrAndHand(atoms, dataRef, sizeof(long) * 2);
100		if (err) goto bail;
101		err = PtrAndHand(initDataPtr, dataRef, initDataByteCount);
102		if (err) goto bail;
103	}
104	return dataRef;
105
106bail:
107	if (dataRef)
108	{
109		// make sure and dispose the data reference handle
110		// once we are done with it
111		DisposeHandle(dataRef);
112	}
113
114	return nil;
115}
116
117+ dataForImage:image type:(int)type
118{
119	NSRect r = NSMakeRect(0,0,[image size].width,[image size].height);
120	id whiteImage = [[NSImage alloc] initWithSize:[image size]];
121	[whiteImage lockFocus];
122	[[NSColor whiteColor] set];
123	NSRectFill(r);
124	[image compositeToPoint:NSMakePoint(0,0) operation:NSCompositeSourceAtop];
125	NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:r];
126	[whiteImage unlockFocus];
127	[whiteImage release];
128	NSData *bmpData = [rep representationUsingType:NSBMPFileType properties:nil];
129
130	if (bmpData == nil)
131	{
132		NSData *pngData = [rep representationUsingType:NSPNGFileType properties:nil];
133		if ([pngData length] == 0)
134		{
135			NSLog(@"Can't export bitmap data to BMP");
136			[rep release];
137			return nil;
138		}
139
140		// create a data reference handle for quicktime (see TN 1195 for myCreateHandleDataRef source)
141		Handle pngDataH = NULL;
142		PtrToHand([pngData bytes], &pngDataH, [pngData length]);
143		Handle dataRef = myCreateHandleDataRef(pngDataH, "\pdummy.png", kQTFileTypePNG, nil, nil, 0);
144
145		// create a Graphics Importer component that will read from the PNG data
146		ComponentInstance importComponent=0, exportComponent=0;
147		OSErr err = GetGraphicsImporterForDataRef(dataRef, HandleDataHandlerSubType, &importComponent);
148		DisposeHandle(dataRef);
149		if (err == noErr)
150		{
151			// create a Graphics Exporter component that will write BMP data
152			err = OpenADefaultComponent(GraphicsExporterComponentType, type, &exportComponent);
153			if (err == noErr)
154			{
155				// set export parameters
156				Handle bmpDataH = NewHandle(0);
157				GraphicsExportSetInputGraphicsImporter(exportComponent, importComponent);
158				GraphicsExportSetOutputHandle(exportComponent, bmpDataH);
159
160				// export data to BMP into handle
161				unsigned long actualSizeWritten = 0;
162				err = GraphicsExportDoExport(exportComponent, &actualSizeWritten);
163				if (err == noErr)
164				{
165					// export done: create the NSData that will be returned
166					HLock(bmpDataH);
167					bmpData = [NSData dataWithBytes:*bmpDataH length:GetHandleSize(bmpDataH)];
168					HUnlock(bmpDataH);
169				}
170				DisposeHandle(bmpDataH);
171				CloseComponent(exportComponent);
172			}
173			CloseComponent(importComponent);
174		}
175		DisposeHandle(pngDataH);
176	}
177	[rep release];
178	return bmpData;
179
180}
181
182+ PICTDataForImage:image
183{
184	return [self dataForImage:image type:kQTFileTypePicture];
185}
186
187+ BMPDataForImage:image
188{
189	return [self dataForImage:image type:kQTFileTypeBMP];
190}
191/*
192@end
193
194
195// BMPDataForImage by Florrent Pillet
196// myCreateHandleDataRef by Apple
197
198@implementation PXBitmapExporter
199
200Handle myCreateHandleDataRef(Handle dataHandle, Str255 fileName, OSType fileType, StringPtr mimeTypeString, Ptr initDataPtr, Size initDataByteCount)
201{
202	OSErr err;
203	Handle dataRef = nil;
204	Str31 tempName;
205	long atoms[3];
206	StringPtr name;
207
208	// First create a data reference handle for our data
209	err = PtrToHand( &dataHandle, &dataRef, sizeof(Handle));
210
211	if (err) goto bail;
212
213	// If this is QuickTime 3 or later, we can add
214	// the filename to the data ref to help importer
215	// finding process. Find uses the extension.
216
217	name = fileName;
218	if (name == nil)
219	{
220		tempName[0] = 0;
221		name = tempName;
222	}
223
224	// Only add the file name if we are also adding a
225	// file type, MIME type or initialization data
226
227	if ((fileType) || (mimeTypeString) || (initDataPtr))
228	{
229		err = PtrAndHand(name, dataRef, name[0]+1);
230		if (err) goto bail;
231	}
232
233	// If this is QuickTime 4, the handle data handler
234	// can also be told the filetype and/or
235	// MIME type by adding data ref extensions. These
236	// help the importer finding process.
237	// NOTE: If you add either of these, you MUST add
238	// a filename first -- even if it is an empty Pascal
239	// string. Under QuickTime 3, any data ref extensions
240	// will be ignored.
241
242	// to add file type, you add a classic atom followed
243	// by the Mac OS filetype for the kind of file
244	if (fileType)
245	{
246		atoms[0] = EndianU32_NtoB(sizeof(long) * 3);
247		atoms[1] = EndianU32_NtoB(kDataRefExtensionMacOSFileType);
248		atoms[2] = EndianU32_NtoB(fileType);
249		err = PtrAndHand(atoms, dataRef, sizeof(long) * 3);
250		if (err) goto bail;
251	}
252
253	// to add MIME type information, add a classic atom followed by
254	// a Pascal string holding the MIME type
255
256	if (mimeTypeString)
257	{
258		atoms[0] = EndianU32_NtoB(sizeof(long) * 2 + mimeTypeString[0]+1);
259		atoms[1] = EndianU32_NtoB(kDataRefExtensionMIMEType);
260		err = PtrAndHand(atoms, dataRef, sizeof(long) * 2);
261		if (err) goto bail;
262		err = PtrAndHand(mimeTypeString, dataRef, mimeTypeString[0]+1);
263		if (err) goto bail;
264	}
265
266	// add any initialization data, but only if a dataHandle was
267	// not already specified (any initialization data is ignored
268	// in this case)
269	if((dataHandle == nil) && (initDataPtr))
270	{
271		atoms[0] = EndianU32_NtoB(sizeof(long) * 2 + initDataByteCount);
272		atoms[1] = EndianU32_NtoB(kDataRefExtensionInitializationData);
273		err = PtrAndHand(atoms, dataRef, sizeof(long) * 2);
274		if (err) goto bail;
275		err = PtrAndHand(initDataPtr, dataRef, initDataByteCount);
276		if (err) goto bail;
277	}
278	return dataRef;
279
280bail:
281	if (dataRef)
282	{
283		// make sure and dispose the data reference handle
284		// once we are done with it
285		DisposeHandle(dataRef);
286	}
287
288	return nil;
289}
290
291+ dataForImage:image type:(int)type
292{
293	NSRect r = NSMakeRect(0,0,[image size].width,[image size].height);
294	id whiteImage = [[NSImage alloc] initWithSize:[image size]];
295	[whiteImage lockFocus];
296	[[NSColor whiteColor] set];
297	NSRectFill(r);
298	[image compositeToPoint:NSMakePoint(0,0) operation:NSCompositeSourceAtop];
299	NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:r];
300	[whiteImage unlockFocus];
301	[whiteImage release];
302	NSData *bmpData = [rep representationUsingType:NSBMPFileType properties:nil];
303
304	if (bmpData == nil)
305	{
306		NSData *pngData = [rep representationUsingType:NSPNGFileType properties:nil];
307		if ([pngData length] == 0)
308		{
309			NSLog(@"Can't export bitmap data to BMP");
310			[rep release];
311			return nil;
312		}
313
314		// create a data reference handle for quicktime (see TN 1195 for myCreateHandleDataRef source)
315		Handle pngDataH = NULL;
316		PtrToHand([pngData bytes], &pngDataH, [pngData length]);
317		Handle dataRef = myCreateHandleDataRef(pngDataH, "\pdummy.png", kQTFileTypePNG, nil, nil, 0);
318
319		// create a Graphics Importer component that will read from the PNG data
320		ComponentInstance importComponent=0, exportComponent=0;
321		OSErr err = GetGraphicsImporterForDataRef(dataRef, HandleDataHandlerSubType, &importComponent);
322		DisposeHandle(dataRef);
323		if (err == noErr)
324		{
325			// create a Graphics Exporter component that will write BMP data
326			err = OpenADefaultComponent(GraphicsExporterComponentType, type, &exportComponent);
327			if (err == noErr)
328			{
329				// set export parameters
330				Handle bmpDataH = NewHandle(0);
331				GraphicsExportSetInputGraphicsImporter(exportComponent, importComponent);
332				GraphicsExportSetOutputHandle(exportComponent, bmpDataH);
333
334				// export data to BMP into handle
335				unsigned long actualSizeWritten = 0;
336				err = GraphicsExportDoExport(exportComponent, &actualSizeWritten);
337				if (err == noErr)
338				{
339					// export done: create the NSData that will be returned
340					HLock(bmpDataH);
341					bmpData = [NSData dataWithBytes:*bmpDataH length:GetHandleSize(bmpDataH)];
342					HUnlock(bmpDataH);
343				}
344				DisposeHandle(bmpDataH);
345				CloseComponent(exportComponent);
346			}
347			CloseComponent(importComponent);
348		}
349		DisposeHandle(pngDataH);
350	}
351	[rep release];
352	return bmpData;
353
354}
355
356+ PICTDataForImage:image
357{
358	return [self dataForImage:image type:kQTFileTypePicture];
359}
360
361+ BMPDataForImage:image
362{
363	return [self dataForImage:image type:kQTFileTypeBMP];
364}
365*/
366
367@end