GenerateThumbnailForURL.m 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // Adapted from QuickLook-pfm-master/src/GenerateThumbnailForURL.m by Andreas
  2. // Steinel (https://github.com/lnxbil/quicklook-pfm)
  3. #import <CoreFoundation/CoreFoundation.h>
  4. #import <CoreServices/CoreServices.h>
  5. #import <QuickLook/QuickLook.h>
  6. #import <Foundation/Foundation.h>
  7. #import <AppKit/NSImage.h>
  8. #include "render_to_buffer.h"
  9. // Creates a bitmap context for ARGB images (not sure if we really need a
  10. // separate function for this... I think there should be something builtin that
  11. // works just as well)
  12. // Taken from https://github.com/lnxbil/quicklook-pfm
  13. CGContextRef CreateARGBBitmapContext (CGSize size)
  14. {
  15. CGContextRef context = NULL;
  16. CGColorSpaceRef colorSpace;
  17. void * bitmapData;
  18. int bitmapByteCount;
  19. int bitmapBytesPerRow;
  20. // Get image width, height. We'll use the entire image.
  21. size_t pixelsWide = (size_t) size.width; //CGImageGetWidth(inImage);
  22. size_t pixelsHigh = (size_t) size.height; //CGImageGetHeight(inImage);
  23. // Declare the number of bytes per row. Each pixel in the bitmap in this
  24. // example is represented by 4 bytes; 8 bits each of red, green, blue, and
  25. // alpha.
  26. bitmapBytesPerRow = (pixelsWide * 4);
  27. bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
  28. // Use the generic RGB color space.
  29. // FIXME: Das verstehe ich net. Die Doku sagt nicht, dass es Deprecated ist und
  30. // gibt auch keine Auswahlmöglichkeit an :-(
  31. colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
  32. if (colorSpace == NULL)
  33. {
  34. NSLog(@"Error allocating color space\n");
  35. return NULL;
  36. }
  37. // Allocate memory for image data. This is the destination in memory
  38. // where any drawing to the bitmap context will be rendered.
  39. bitmapData = malloc( bitmapByteCount );
  40. if (bitmapData == NULL)
  41. {
  42. NSLog(@"Memory not allocated!");
  43. CGColorSpaceRelease( colorSpace );
  44. return NULL;
  45. }
  46. // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
  47. // per component. Regardless of what the source image format is
  48. // (CMYK, Grayscale, and so on) it will be converted over to the format
  49. // specified here by CGBitmapContextCreate.
  50. context = CGBitmapContextCreate (bitmapData,
  51. pixelsWide,
  52. pixelsHigh,
  53. 8, // bits per component
  54. bitmapBytesPerRow,
  55. colorSpace,
  56. kCGBitmapByteOrderDefault|kCGImageAlphaPremultipliedLast);
  57. if (context == NULL)
  58. {
  59. free (bitmapData);
  60. NSLog(@"Context not created!");
  61. }
  62. // Make sure and release colorspace before returning
  63. CGColorSpaceRelease( colorSpace );
  64. return context;
  65. }
  66. // Generate a thumbnail for a given file
  67. OSStatus GenerateThumbnailForURL(
  68. void *thisInterface,
  69. QLThumbnailRequestRef thumbnail,
  70. CFURLRef url,
  71. CFStringRef contentTypeUTI,
  72. CFDictionaryRef options,
  73. CGSize maxSize)
  74. {
  75. if (QLThumbnailRequestIsCancelled(thumbnail))
  76. return noErr;
  77. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  78. CFStringRef file = CFURLCopyFileSystemPath(url,kCFURLPOSIXPathStyle);
  79. if (QLThumbnailRequestIsCancelled(thumbnail))
  80. return noErr;
  81. // raw pixel data memory of 64 * 64 pixel size
  82. // http://stackoverflow.com/a/3797923/148668
  83. // Multi-sampling for anti-aliasing
  84. const double MS = 2;
  85. const int width = maxSize.width;
  86. // Widescreen aspect ratio
  87. const int height = (270./460.)*maxSize.height;
  88. const int bwidth = MS*width;
  89. const int bheight = MS*height;
  90. const int bchannels = 4;
  91. UInt8 buffer[bwidth * bheight * bchannels];
  92. const char *cs = CFStringGetCStringPtr( file, CFStringGetSystemEncoding()) ;
  93. char cs_buf[1024];
  94. // http://stackoverflow.com/a/1609664/148668
  95. if(cs == NULL)
  96. {
  97. CFStringGetCString(file, cs_buf, [(NSString*)file length]+1, kCFStringEncodingUTF8);
  98. cs = cs_buf;
  99. }
  100. const float OPAQUE_WHITE[4] = {1,1,1,1};
  101. render_to_buffer(cs,OPAQUE_WHITE,bwidth,bheight,buffer);
  102. CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
  103. CFDataRef rgbData = CFDataCreate(NULL, buffer, bwidth * bheight * 4);
  104. CGDataProviderRef provider = CGDataProviderCreateWithCFData(rgbData);
  105. // http://forum.sparrow-framework.org/topic/create-uiimage-from-pixel-data-problems
  106. CGImageRef image = CGImageCreate(
  107. bwidth,
  108. bheight,
  109. 8,
  110. 8*4,
  111. bwidth * 4,
  112. colorspace,
  113. kCGBitmapByteOrderDefault|kCGImageAlphaPremultipliedLast,
  114. provider,
  115. NULL,
  116. true,
  117. kCGRenderingIntentDefault);
  118. CFRelease(rgbData);
  119. CGDataProviderRelease(provider);
  120. CGColorSpaceRelease(colorspace);
  121. NSSize size = {width,height};
  122. if (QLThumbnailRequestIsCancelled(thumbnail))
  123. return noErr;
  124. // Draw onto context as textured rectangle
  125. CGContextRef cgctx = CreateARGBBitmapContext(size);
  126. CGRect rect = CGRectMake(0,0, width, height);
  127. CGContextClearRect(cgctx,rect);
  128. CGContextDrawImage(cgctx, rect, image);
  129. CGImageRef newCGImage = CGBitmapContextCreateImage(cgctx);
  130. CGContextRelease(cgctx);
  131. QLThumbnailRequestSetImage(thumbnail, newCGImage, NULL);
  132. // Releasing image
  133. CGImageRelease(newCGImage);
  134. [pool release];
  135. return noErr;
  136. }
  137. void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail)
  138. {
  139. // implement only if supported
  140. }