1/*
2 * Copyright (c) 2001-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 *  BLGenerateOFLabel.c
25 *  bless
26 *
27 *  Created by Shantonu Sen <ssen@apple.com> on Sat Feb 23 2002.
28 *  Copyright (c) 2002-2007 Apple Inc. All Rights Reserved.
29 *
30 */
31
32#include <CoreFoundation/CoreFoundation.h>
33
34#include <sys/types.h>
35
36#include "bless.h"
37#include "bless_private.h"
38
39static const char clut[] =
40  {
41    0x00, /* 0x00 0x00 0x00 white */
42    0xF6, /* 0x11 0x11 0x11 */
43    0xF7, /* 0x22 0x22 0x22 */
44
45    0x2A, /* 0x33 = 1*6^2 + 1*6 + 1 = 43 colors */
46
47    0xF8, /* 0x44 */
48    0xF9, /* 0x55 */
49
50    0x55, /* 0x66 = 2*(36 + 6 + 1) = 86 colors */
51
52    0xFA, /* 0x77 */
53    0xFB, /* 0x88 */
54
55    0x80, /* 0x99 = (3*43) = 129 colors*/
56
57    0xFC, /* 0xAA */
58    0xFD, /* 0xBB */
59
60    0xAB, /* 0xCC = 4*43 = 172 colors */
61
62    0xFE, /* 0xDD */
63    0xFF, /* 0xEE */
64
65    0xD6, /* 0xFF = 5*43 = 215 */
66  };
67
68static int makeLabelOfSize(const char *label, unsigned char *bitmapData,
69        uint16_t width, uint16_t height, int scale, uint16_t *newwidth);
70
71static int refitToWidth(unsigned char *bitmapData,
72        uint16_t width, uint16_t height, uint16_t newwidth);
73
74
75
76int BLGenerateLabelData(BLContextPtr context, const char *label, int scale, CFDataRef *data)
77{
78    uint16_t width = 340 * scale;
79    uint16_t height = 12 * scale;
80    uint16_t newwidth;
81    int err;
82    int i;
83    CFDataRef bits = NULL;
84    unsigned char *bitmapData;
85
86    contextprintf(context, kBLLogLevelError,
87                  "CoreGraphics is not available for rendering\n");
88    return 1;
89
90    bitmapData = (unsigned char *)malloc(width*height+5);
91    if (!bitmapData) {
92        contextprintf(context, kBLLogLevelError,
93                      "Could not alloc CoreGraphics backing store\n");
94        return 1;
95    }
96    bzero(bitmapData, width*height+5);
97
98    err = makeLabelOfSize(label, bitmapData+5, width, height, scale, &newwidth);
99	if (err) {
100        free(bitmapData);
101        *data = NULL;
102        return 2;
103	}
104
105	// cap at 340*scale pixels wide.
106	if (newwidth > width) newwidth = width;
107
108    contextprintf(context, kBLLogLevelVerbose, "Refitting to width %d\n", newwidth);
109
110	err = refitToWidth(bitmapData+5, width, height, newwidth);
111	if (err) {
112        free(bitmapData);
113        *data = NULL;
114        return 3;
115	}
116
117	bitmapData = realloc(bitmapData, newwidth*height+5);
118	if (!bitmapData) {
119        contextprintf(context, kBLLogLevelError,
120                      "Could not realloc to shrink CoreGraphics backing store\n");
121
122        return 4;
123	}
124
125    bitmapData[0] = 1;
126    *(uint16_t *)&bitmapData[1] = CFSwapInt16HostToBig(newwidth);
127    *(uint16_t *)&bitmapData[3] = CFSwapInt16HostToBig(height);
128
129    for(i=5; i < newwidth*height+5; i++) {
130        bitmapData[i] = clut[bitmapData[i] >> 4];
131    }
132
133	//	bits = CFDataCreate(kCFAllocatorDefault, bitmapData, newwidth*height+5);
134	bits = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)bitmapData, newwidth*height+5, kCFAllocatorMalloc);
135	//        free(bitmapData);
136
137	if(bits == NULL) {
138        contextprintf(context, kBLLogLevelError,
139                      "Could not create CFDataRef\n");
140		return 6;
141	}
142
143    *data = (void *)bits;
144
145    return 0;
146}
147
148
149int BLGenerateOFLabel(BLContextPtr context,
150                    const char label[],
151CFDataRef* data) {
152
153
154    uint16_t width = 340;
155    uint16_t height = 12;
156    uint16_t newwidth;
157    int err;
158    int i;
159    CFDataRef bits = NULL;
160    unsigned char *bitmapData;
161
162    contextprintf(context, kBLLogLevelError,
163    "CoreGraphics is not available for rendering\n");
164    return 1;
165
166    bitmapData = (unsigned char *)malloc(width*height+5);
167    if(!bitmapData) {
168        contextprintf(context, kBLLogLevelError,
169        "Could not alloc CoreGraphics backing store\n");
170        return 1;
171    }
172    bzero(bitmapData, width*height+5);
173
174    err = makeLabelOfSize(label, bitmapData+5, width, height, 1, &newwidth);
175	if(err) {
176        free(bitmapData);
177        *data = NULL;
178        return 2;
179	}
180
181	// cap at 300 pixels wide.
182	if(newwidth > width) newwidth = width;
183
184    contextprintf(context, kBLLogLevelVerbose, "Refitting to width %d\n", newwidth);
185
186
187	err = refitToWidth(bitmapData+5, width, height, newwidth);
188	if(err) {
189        free(bitmapData);
190        *data = NULL;
191        return 3;
192	}
193
194	bitmapData = realloc(bitmapData, newwidth*height+5);
195	if(NULL == bitmapData) {
196        contextprintf(context, kBLLogLevelError,
197        "Could not realloc to shrink CoreGraphics backing store\n");
198
199        return 4;
200	}
201
202    bitmapData[0] = 1;
203    *(uint16_t *)&bitmapData[1] = CFSwapInt16HostToBig(newwidth);
204    *(uint16_t *)&bitmapData[3] = CFSwapInt16HostToBig(height);
205
206    for(i=5; i < newwidth*height+5; i++) {
207        bitmapData[i] = clut[bitmapData[i] >> 4];
208    }
209
210	//	bits = CFDataCreate(kCFAllocatorDefault, bitmapData, newwidth*height+5);
211	bits = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)bitmapData, newwidth*height+5, kCFAllocatorMalloc);
212	//        free(bitmapData);
213
214	if(bits == NULL) {
215        contextprintf(context, kBLLogLevelError,
216        "Could not create CFDataRef\n");
217		return 6;
218	}
219
220    *data = (void *)bits;
221
222    return 0;
223}
224
225#undef USE_COREGRAPHICS
226#define USE_COREGRAPHICS 0
227
228#if USE_COREGRAPHICS
229#include <ApplicationServices/ApplicationServices.h>
230
231static int makeLabelOfSize(const char *label, unsigned char *bitmapData,
232uint16_t width, uint16_t height, int scale, uint16_t *newwidth) {
233
234    int bitmapByteCount;
235    int bitmapBytesPerRow;
236
237    CGContextRef    context = NULL;
238    CGColorSpaceRef colorSpace = NULL;
239
240
241    bitmapBytesPerRow = width*1;
242    bitmapByteCount = bitmapBytesPerRow * height;
243
244    colorSpace = CGColorSpaceCreateDeviceGray();
245
246
247    context = CGBitmapContextCreate( bitmapData,
248    width,
249    height,
250    8,
251    bitmapBytesPerRow,
252    colorSpace,
253    kCGImageAlphaNone);
254
255    if(context == NULL) {
256        fprintf(stderr, "Could not init CoreGraphics context\n");
257        return 1;
258    }
259
260
261#if USE_CORETEXT
262    {
263        CFStringRef s1;
264        CFAttributedStringRef s2;
265        CTLineRef ct1;
266        CGRect rect;
267        CFMutableDictionaryRef dict;
268        CGColorRef color;
269        CTFontRef fontRef;
270
271        // white text on black background, for OF/EFI bitmap
272        const CGFloat components[] = {
273            (CGFloat)1.0, (CGFloat)1.0
274        };
275
276        /* set to white background for testing
277        CGContextSetGrayFillColor(context, 1.0, 1.0);
278        CGContextFillRect(context,CGRectInfinite);
279        */
280
281        color = CGColorCreate(colorSpace, components);
282        if(color == NULL) return 1;
283
284        fontRef = CTFontCreateWithName(CFSTR("Helvetica"), 10.0 * scale, NULL);
285        if(fontRef == NULL) return 1;
286
287        dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
288        CFDictionarySetValue(dict, kCTForegroundColorAttributeName, color);
289        CFDictionarySetValue(dict, kCTFontAttributeName, fontRef);
290        CFRelease(color);
291        CFRelease(fontRef);
292
293        s1 = CFStringCreateWithCString(kCFAllocatorDefault, label, kCFStringEncodingUTF8);
294        s2 = CFAttributedStringCreate(kCFAllocatorDefault,s1,dict);
295        CFRelease(s1);
296        CFRelease(dict);
297
298        ct1 = CTLineCreateWithAttributedString(s2);
299        CFRelease(s2);
300        if(ct1 == NULL) return 2;
301
302        rect = CTLineGetImageBounds(ct1, context);
303
304        CGContextSetTextPosition(context, 2.0 * scale, 2.0 * scale);
305
306        CTLineDraw(ct1, context);
307
308        CGContextFlush(context);
309
310        CFRelease(ct1);
311
312        if(newwidth) { *newwidth = (int)rect.size.width + 4 * scale; }
313 //           printf("[%f,%f] (%f,%f)\n", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
314
315    }
316#else
317    {
318        CGPoint pt;
319
320        CGContextSetTextDrawingMode(context, kCGTextFill);
321        CGContextSelectFont(context, "Helvetica", 10.0 * scale, kCGEncodingMacRoman);
322        CGContextSetGrayFillColor(context, 1.0, 1.0);
323        CGContextSetShouldAntialias(context, 1);
324        CGContextSetCharacterSpacing(context, 0.5 * scale);
325
326        pt = CGContextGetTextPosition(context);
327
328        CGContextShowTextAtPoint(context, 2.0 * scale, 2.0 * scale, label, strlen(label));
329
330        pt = CGContextGetTextPosition(context);
331
332        if(newwidth) { *newwidth = (int)pt.x + 2; }
333
334    }
335#endif
336
337
338#if 0
339//    CFShow(CGImageDestinationCopyTypeIdentifiers());
340    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, bitmapData, height*width, NULL);
341    CGImageRef imageRef = CGImageCreate(width,height,8,8,bitmapBytesPerRow,colorSpace,0, dataProvider, NULL, 0, 0);
342    CFURLRef output = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)"foo.tiff", strlen("foo.tiff"), 0);
343    CGImageDestinationRef dest = CGImageDestinationCreateWithURL(output, CFSTR("public.tiff"), 1, NULL);
344
345    CGImageDestinationAddImage(dest, imageRef, NULL);
346
347    CGImageDestinationFinalize(dest);
348
349    CFRelease(dest);
350    CFRelease(output);
351    CFRelease(imageRef);
352    CFRelease(dataProvider);
353    //    write(1, bitmapData, height*width);
354
355#endif
356
357    CGColorSpaceRelease(colorSpace);
358    CGContextRelease(context);
359
360
361    return 0;
362
363}
364
365#else // !USE_COREGRAPHICS
366static int makeLabelOfSize(const char *label, unsigned char *bitmapData,
367						   uint16_t width, uint16_t height, int scale, uint16_t *newwidth) {
368
369	// just make a blank label
370	*newwidth = 10;
371	return 0;
372}
373#endif // !USE_COREGRAPHICS
374
375/*
376 * data is of the form:
377 *  111111000111111000111111000 ->
378 *  111111111111111111
379 */
380
381static int refitToWidth(unsigned char *bitmapData,
382        uint16_t width, uint16_t height, uint16_t newwidth)
383{
384  uint16_t row;
385  for(row=1; row < height; row++) {
386    bcopy(&bitmapData[row*width], &bitmapData[row*newwidth], newwidth);
387  }
388
389  return 0;
390}
391