OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) { // load the actual file CFDataRef fileData = nil; CFDictionaryRef propertyDictionary = nil; SInt32 errorCode; if (CFURLCreateDataAndPropertiesFromResource(NULL, url, &fileData, &propertyDictionary, nil, &errorCode)) { CFIndex dataLength = CFDataGetLength(fileData); UInt8 *bytes = (UInt8 *)CFDataGetBytePtr(fileData); long pages = dataLength / ONE_LCD_FRAME_BYTESIZE; CGSize lcdSize = CGSizeMake(LCD_FRAME_PIXEL_WIDTH, LCD_FRAME_PIXEL_HEIGHT * pages); CGContextRef cgContext = QLThumbnailRequestCreateContext(thumbnail, lcdSize, true, NULL); if(cgContext) { CGColorRef lcdForegroundColor = CGColorCreateGenericRGB(0.467, 0.522, 0.047, 1.000); CGColorRef lcdBackgroundColor = CGColorCreateGenericRGB(0.227, 0.192, 0.000, 1.000); CGContextSetFillColorWithColor(cgContext, lcdBackgroundColor); CGContextFillRect(cgContext, CGRectMake(0,0,lcdSize.width,lcdSize.height)); CGPoint origin = CGPointMake(0,0); while (pages-- > 0) { CGContextSetFillColorWithColor(cgContext, lcdForegroundColor); // CGContextFillRect(cgContext, CGRectMake(origin.x,origin.y,10,10)); for (int y=0;y<9;y++) { for (int x=0; x < LCD_FRAME_PIXEL_WIDTH; x++) { UInt8 byte = bytes[y*LCD_FRAME_PIXEL_WIDTH + (LCD_FRAME_PIXEL_WIDTH - x - 1)]; if (byte > 0) { UInt8 byteMask = 1; for (int littleY = 0; littleY < 8; littleY++) { if ((byte & (byteMask << littleY))) { CGContextFillRect(cgContext, CGRectMake(origin.x + x,origin.y + y*8 + littleY,1,1)); } } } } } origin.y += 68; bytes += ONE_LCD_FRAME_BYTESIZE; } // When we are done with our drawing code QLPreviewRequestFlushContext() is called to flush the context QLThumbnailRequestFlushContext(thumbnail, cgContext); } CFRelease(cgContext); CFRelease(fileData); CFRelease(propertyDictionary); } return noErr; }
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) { if (url == NULL) { return -1; } //fprintf(stderr, "GenerateThumbnailForURL\n"); //CFShow(url); //fprintf(stderr, "maxSize: %fx%f\n", maxSize.width, maxSize.height); if ((maxSize.width == 200.0f) && (maxSize.height == 202.0f)) { // hack to keep atPeek preview nice maxSize.height = 200.0f; } //fprintf(stderr, "maxSize: %fx%f\n", maxSize.width, maxSize.height); //CFShow(options); Boolean opaque = false; if (CFDictionaryGetValue(options, CFSTR("opaque")) != NULL) { opaque = CFBooleanGetValue(CFDictionaryGetValue(options, CFSTR("opaque"))); } CGImageRef imageRef = GetPngImage(url, contentTypeUTI); if (imageRef != NULL) { CGRect imageRect = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); float ratio = imageRect.size.width / imageRect.size.height; //fprintf(stderr, "imageSize: %dx%d, ratio: %f\n", (int)CGImageGetWidth(imageRef), (int)CGImageGetHeight(imageRef), ratio); if ((imageRect.size.width > maxSize.width) || (imageRect.size.height > maxSize.height)) { if (imageRect.size.width > imageRect.size.height) { imageRect.size.width = maxSize.width; imageRect.size.height = maxSize.height/ratio; } else { imageRect.size.width = maxSize.width*ratio; imageRect.size.height = maxSize.height; } } imageRect.origin.x = (int)(((maxSize.width - imageRect.size.width) / 2.0) + 0.5); imageRect.origin.y = (int)(((maxSize.height - imageRect.size.height) / 2.0) + 0.5); //fprintf(stderr, "imageRect: %f,%f %fx%f\n", imageRect.origin.x , imageRect.origin.y, imageRect.size.width, imageRect.size.height); CGContextRef cgContext = QLThumbnailRequestCreateContext(thumbnail, maxSize, TRUE, NULL); if (cgContext != NULL) { CGContextSaveGState(cgContext); { if (opaque == 1) { CGRect contextRect = CGRectMake(0, 0, maxSize.width, maxSize.height); CGContextSetRGBFillColor(cgContext, 0.57, 0.57, 0.57, 1); CGContextFillRect(cgContext, contextRect); } CGContextDrawImage(cgContext, imageRect, imageRef); } CGContextRestoreGState(cgContext); QLThumbnailRequestFlushContext(thumbnail, cgContext); CFRelease(cgContext); } CFRelease(imageRef); } return noErr; }
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) { CGFloat minCartDrawSize = 64; CGFloat size = fmin(maxSize.width, maxSize.height); CGContextRef qlContext = NULL; if (size < minCartDrawSize) { size = 32; qlContext = QLThumbnailRequestCreateContext(thumbnail, CGSizeMake(size,size), true, NULL); } else { qlContext = QLThumbnailRequestCreateContext(thumbnail, CGSizeMake(size,size), false, NULL); } if (qlContext) { NDSHeader header; NDSIcon icon; int pathlen = 2047; UInt8 path[pathlen+1]; if (CFURLGetFileSystemRepresentation(url, true, path, pathlen)) { if (size < minCartDrawSize) { // at smaller sizes we only draw the game icon at native size and let QL do the scaling parseNDSInfo(path, &header, &icon); CGImageRef image = CGImageCreateWithNDSIcon(&icon); if (image) { CGContextDrawImage(qlContext, CGRectMake(0, 0, size, size), image); CGImageRelease(image); } } else { CGContextClearRect(qlContext, CGRectMake(0,0,size,size)); // draw cartridge background CFURLRef bgURL = CFBundleCopyResourceURL(CFBundleGetBundleWithIdentifier( CFSTR("net.mironer.nds.quicklookgenerator")), CFSTR("background"), CFSTR("png"), NULL); if (bgURL) { CGDataProviderRef bgPNG = CGDataProviderCreateWithURL(bgURL); if (bgPNG) { CGImageRef bg = CGImageCreateWithPNGDataProvider(bgPNG, NULL, true, kCGRenderingIntentDefault); if (bg) { CGContextDrawImage(qlContext, CGRectMake(0, 0, size, size), bg); CGImageRelease(bg); } CGDataProviderRelease(bgPNG); } CFRelease(bgURL); } // draw game icon parseNDSInfo(path, &header, &icon); CGImageRef image = CGImageCreateWithNDSIcon(&icon); if (image) { CGContextDrawImage(qlContext, CGRectMake(size / 5, size / 5, size * 3 / 5, size * 3 / 5), image); CGImageRelease(image); } // draw cartridge overlay CFURLRef ovrURL = CFBundleCopyResourceURL( CFBundleGetBundleWithIdentifier( CFSTR("net.mironer.nds.quicklookgenerator")), CFSTR("overlay"), CFSTR("png"), NULL); if (ovrURL) { CGDataProviderRef ovrPNG = CGDataProviderCreateWithURL(ovrURL); if (ovrPNG) { CGImageRef ovr = CGImageCreateWithPNGDataProvider(ovrPNG, NULL, true, kCGRenderingIntentDefault); if (ovr) { CGContextDrawImage(qlContext, CGRectMake(0, 0, size, size), ovr); CGImageRelease(ovr); } CGDataProviderRelease(ovrPNG); } CFRelease(ovrURL); } // draw serial number CFStringRef serial = CFStringCreateWithSerialNumber(&header); CFAttributedStringRef aString = CFAttributedStringCreate(kCFAllocatorDefault, serial, NULL); CFMutableAttributedStringRef attrStr = CFAttributedStringCreateMutableCopy(kCFAllocatorDefault, 128, aString); CFIndex len = CFAttributedStringGetLength(attrStr); CTFontRef font = CTFontCreateWithName(CFSTR("Lucida Sans"), size / 16, NULL); CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, len), kCTFontAttributeName, font); CTTextAlignment rightAlign = kCTRightTextAlignment; CTParagraphStyleSetting styleSettings[] = { {kCTParagraphStyleSpecifierAlignment, sizeof(rightAlign), &rightAlign} }; CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(styleSettings, 1); CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, len), kCTParagraphStyleAttributeName, paragraphStyle); CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrStr); CFRelease(attrStr); CFRelease(aString); CFRelease(serial); CFRelease(font); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, CGRectMake(-size * 1.55 / 8, -size * 6.1 / 8, size, size)); CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); CTFrameDraw(frame, qlContext); CFRelease(frame); CFRelease(framesetter); CFRelease(paragraphStyle); CFRelease(path); } } QLThumbnailRequestFlushContext(thumbnail, qlContext); CFRelease(qlContext); } return noErr; }