00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include <mach/mach.h>
00045 #include <Carbon/Carbon.h>
00046
00047 #undef DPRINTF
00048 #include <celutil/debug.h>
00049
00050 class CGFrame : public CGRect
00051 {
00052 public:
00053
00054 CGFrame(float x0, float y0, float w, float h)
00055 {
00056 *this = CGRectMake(x0,y0,w,h);
00057 }
00058
00059 explicit CGFrame(float w = 0, float h = 0)
00060 {
00061 *this = CGRectMake(0,0,w,h);
00062 }
00063
00064 CGFrame(const Rect& rect)
00065 {
00066 origin.x = rect.left, size.width = rect.right - rect.left;
00067 origin.y = rect.top, size.height = rect.bottom - rect.top;
00068 }
00069
00070 CGFrame(const CGRect& copy)
00071 {
00072 origin = copy.origin;
00073 size = copy.size;
00074 }
00075
00076 CGFrame(const CGSize& size)
00077 {
00078 origin.x = origin.y = 0;
00079 this->size = size;
00080 }
00081
00082 CGFrame(float x, float y, const CGSize& size)
00083 {
00084 *this = CGRectMake(x, y, size.width, size.height);
00085 }
00086
00087 CGFrame(const CGPoint& pos, const CGSize& size)
00088 {
00089 *this = CGRectMake(pos.x, pos.y, size.width, size.height);
00090 }
00091
00092 void Offset(float dx, float dy)
00093 {
00094 origin.x += dx, origin.y += dy;
00095 }
00096
00097 void Inset(float dx, float dy)
00098 {
00099 origin.x += dx, origin.y += dy;
00100 size.width -= dx*2, size.height -= dy*2;
00101 }
00102 };
00103
00104 class MemoryBuffer
00105 {
00106 size_t size;
00107 int ref_count;
00108
00109 MemoryBuffer(char* const data, size_t size) : size(size), ref_count(1), data(data)
00110 {
00111 }
00112
00113 ~MemoryBuffer()
00114 {
00115 vm_deallocate((vm_map_t) mach_task_self(), (vm_address_t) data, size);
00116 }
00117
00118 public:
00119
00120 friend class _MemoryBuffer;
00121
00122 char* const data;
00123
00124 MemoryBuffer* Retain()
00125 {
00126 ++ref_count;
00127 return this;
00128 }
00129
00130 void Release()
00131 {
00132 if (--ref_count == 0)
00133 delete this;
00134 }
00135
00136 static MemoryBuffer* Create(size_t size)
00137 {
00138 char* data;
00139 kern_return_t err = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*) &data, size, TRUE);
00140
00141 return (err == KERN_SUCCESS) ? new MemoryBuffer(data, size) : NULL;
00142 }
00143 };
00144
00145 class Datafile
00146 {
00147 int ref_count;
00148 FILE* file;
00149
00150 public:
00151 MemoryBuffer* data_buffer;
00152 unsigned long data_size;
00153
00154 Datafile() : ref_count(1), file(NULL), data_buffer(NULL), data_size(0)
00155 {
00156 }
00157
00158 ~Datafile()
00159 {
00160 Reset();
00161 }
00162
00163 Datafile* Retain()
00164 {
00165 ++ref_count;
00166 return this;
00167 }
00168
00169 void Release()
00170 {
00171 if (--ref_count==0)
00172 delete this;
00173 }
00174
00175 int Open(const char* path)
00176 {
00177 file = fopen(path,"r");
00178 if (!file) {
00179 DPRINTF(0,"Datafile::Open() - Couldn't open %s\n", path);
00180 Reset();
00181 return 0;
00182 }
00183 fseek(file, 0, SEEK_END);
00184 data_size = ftell(file);
00185 data_buffer = MemoryBuffer::Create(data_size);
00186 if (!data_buffer) {
00187 DPRINTF(0,"Datafile::Open() - Couldn't allocate MemoryBuffer of size %d\n", data_size);
00188 Reset();
00189 return 0;
00190 }
00191
00192 return 1;
00193 }
00194
00195 int Read()
00196 {
00197 if ((file == NULL) || (data_buffer == NULL) || (data_size == 0)) {
00198 DPRINTF(0,"Datafile::Read() - No file open, file of zero size, or no valid MemoryBuffer\n");
00199 Reset();
00200 return 0;
00201 }
00202
00203 fseek(file, 0, SEEK_SET);
00204 if (fread((void*)data_buffer->data, 1, data_size, file) != data_size) {
00205 DPRINTF(0,"Datafile::Read() - Didn't read to finish?");
00206 Reset();
00207 return 0;
00208 }
00209
00210
00211 return 1;
00212 }
00213
00214 void Close()
00215 {
00216 if (file) {
00217 fclose(file);
00218 file = NULL;
00219 }
00220 }
00221
00222 void Reset()
00223 {
00224 Close();
00225 if (data_buffer) {
00226 data_buffer->Release();
00227 data_buffer = NULL;
00228 }
00229 }
00230 };
00231
00232 class CGBuffer
00233 {
00234 Datafile file;
00235 CGImageRef image_ref;
00236 CGContextRef context_ref;
00237
00238 int ref_count;
00239
00240 void Init()
00241 {
00242 ref_count = 1;
00243 buffer = NULL;
00244 image_ref = NULL;
00245 context_ref = NULL;
00246 image_finished = false;
00247 }
00248
00249 bool CreateCGContext()
00250 {
00251 if (context_ref)
00252 {
00253 CGContextRelease(context_ref);
00254 context_ref = NULL;
00255 }
00256
00257 if (buffer)
00258 {
00259 buffer->Release();
00260 buffer = NULL;
00261 }
00262
00263 size_t buffer_rowbytes = (size_t)(image_size.width * ((image_depth == 8) ? 1 : 4));
00264
00265 buffer = MemoryBuffer::Create(buffer_rowbytes * (size_t)image_size.height);
00266
00267 if (!buffer)
00268 return false;
00269
00270 CGColorSpaceRef colorspace_ref = (image_depth == 8) ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
00271
00272 if (!colorspace_ref)
00273 return false;
00274
00275 CGImageAlphaInfo alpha_info = (image_depth == 8) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast;
00276
00277 context_ref = CGBitmapContextCreate(buffer->data, (size_t)image_size.width, (size_t)image_size.height, 8, buffer_rowbytes, colorspace_ref, alpha_info);
00278
00279 if (context_ref)
00280 {
00281 CGContextSetFillColorSpace(context_ref, colorspace_ref);
00282 CGContextSetStrokeColorSpace(context_ref, colorspace_ref);
00283
00284
00285 CGContextTranslateCTM(context_ref, 0.0, image_size.height);
00286 CGContextScaleCTM(context_ref, 1.0, -1.0);
00287 }
00288
00289 CGColorSpaceRelease(colorspace_ref);
00290 colorspace_ref = NULL;
00291
00292 return !!context_ref;
00293 }
00294
00295 void RenderCGImage(const CGRect& dst_rect)
00296 {
00297 if (!context_ref || !image_ref)
00298 return;
00299
00300 CGContextDrawImage(context_ref, dst_rect, image_ref);
00301 }
00302
00303 public:
00304
00305 MemoryBuffer* buffer;
00306 CGSize image_size;
00307 size_t image_depth;
00308 bool image_finished;
00309
00310 CGBuffer(const char* path)
00311 {
00312 Init();
00313 Open(path);
00314 }
00315
00316 ~CGBuffer()
00317 {
00318 Reset();
00319 }
00320
00321 CGBuffer* Retain()
00322 {
00323 ++ref_count;
00324 return this;
00325 }
00326
00327 void Release()
00328 {
00329 if (--ref_count == 0)
00330 delete this;
00331 }
00332
00333 bool Open(const char* path)
00334 {
00335 file.Reset();
00336 return file.Open(path);
00337 }
00338
00339 bool LoadJPEG()
00340 {
00341 if (!file.Read())
00342 return false;
00343
00344 file.Close();
00345
00346 CGDataProviderRef src_provider_ref = CGDataProviderCreateWithData(this, file.data_buffer->data, file.data_size, NULL);
00347
00348 if (!src_provider_ref)
00349 return false;
00350
00351 image_ref = CGImageCreateWithJPEGDataProvider(src_provider_ref, NULL, true, kCGRenderingIntentDefault);
00352
00353 CGDataProviderRelease(src_provider_ref);
00354 src_provider_ref = NULL;
00355
00356 if (!image_ref)
00357 return false;
00358
00359 image_size = CGSizeMake(CGImageGetWidth(image_ref), CGImageGetHeight(image_ref));
00360 image_depth = CGImageGetBitsPerPixel(image_ref);
00361
00362 return !!image_ref;
00363 }
00364
00365 bool Render()
00366 {
00367 if (!image_ref)
00368 return false;
00369
00370 if (!CreateCGContext())
00371 return false;
00372
00373 RenderCGImage(CGFrame(image_size));
00374
00375 CGContextRelease(context_ref);
00376 context_ref = NULL;
00377
00378 CGImageRelease(image_ref);
00379 image_ref = NULL;
00380
00381 file.Reset();
00382
00383 return true;
00384 }
00385
00386 void Reset()
00387 {
00388 if (buffer)
00389 {
00390 buffer->Release();
00391 buffer = NULL;
00392 }
00393
00394 if (image_ref)
00395 {
00396 CGImageRelease(image_ref);
00397 image_ref = NULL;
00398 }
00399
00400 if (context_ref)
00401 {
00402 CGContextRelease(context_ref);
00403 context_ref = NULL;
00404 }
00405 }
00406 };