/
ACSharedArtImageSource.c
214 lines (183 loc) · 9.89 KB
/
ACSharedArtImageSource.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
* ACSharedArtImageSource.c
* ArtCore
*
* Created by Justin Lazarow on 7/14/09.
* Copyright 2009 Justin Lazarow. All rights reserved.
*
*/
/* The API and philosophy around ACSharedArtImageSource is similar to the ideas behind a CGImageSource. However, instead of thinking
of the disk as the "source", ArKit delegates the SArtFile.bin as the source. In a similar fashion, @see ACSharedArtImageDestination
for an abstraction around writing images/elements to an SArtFile.bin. In SArtFile.bin there are 3 "image types", the first being ARGB
data called by Apple as HIRes art that contains 2 ACSharedArtImageHeaderDataInfo entries and while the first entry points to the
image you would expect while the second holds a very very high resolution of the normally sized image seen in the first entry. The second type is ARGB image
data with only one ACSharedArtImageHeaderDataInfo entry. The third type represents PDF data. Similar to HIRes art, these have two
ACSharedArtImageHeaderDataInfo entries although the second entry seems unused as with HIRes art. The PDF data is interesting in that
it can be scaled when needed to match a certain DPI. In order to achieve this, Apple uses a CGImageSource from the PDF data and when
they call CGImageSourceCreateImageAtIndex() they provide a CFDictionary with a private constant - kCGImageSourceRasterizationDPI to
scale the PDF art. */
static CFStringRef __ACSharedArtImageSourceCopyFormat(CFTypeRef cf, CFDictionaryRef format)
{
ACSharedArtImageSourceRef isrc = (ACSharedArtImageSourceRef) cf;
CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault,0);
CFStringAppendFormat(description,NULL,CFSTR("Type: %d EntryCount: %d\n"),isrc->header->type,isrc->header->entryCount);
for (int i = 0; i < isrc->header->entryCount; i++)
{
struct __ACSharedArtImageHeaderDataInfo dataInfoAtIndex = isrc->header->data_info[i];
CFStringAppendFormat(description,NULL,CFSTR("\tImage %d Size: %dx%d Length: %d @ %d \n"),i,dataInfoAtIndex.width,dataInfoAtIndex.height,
dataInfoAtIndex.length,dataInfoAtIndex.relativeOffset);
}
return (CFStringRef) description;
}
static CFStringRef __ACSharedArtImageSourceCopyDescription(CFTypeRef cf)
{
ACSharedArtImageSourceRef isrc = (ACSharedArtImageSourceRef) cf;
CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault,0);
CFStringAppendFormat(description,NULL,CFSTR("#<ACSharedArtImageSource:%p> Type: %d EntryCount: %d\n unk1 %d unk2 %d"),isrc,isrc->header->type,
isrc->header->entryCount,isrc->header->unknown1,isrc->header->unknown2);
for (int i = 0; i < isrc->header->entryCount; i++)
{
struct __ACSharedArtImageHeaderDataInfo dataInfoAtIndex = isrc->header->data_info[i];
CFStringAppendFormat(description,NULL,CFSTR("\tImage %d Size: %dx%d Length: %d @ %d \n"),i,dataInfoAtIndex.width,dataInfoAtIndex.height,
dataInfoAtIndex.length,dataInfoAtIndex.relativeOffset);
}
return (CFStringRef) description;
}
static void __ACSharedArtImageSourceDeallocate(CFTypeRef cf)
{
ACSharedArtImageSourceRef sart = (ACSharedArtImageSourceRef) cf;
CFRelease(sart->owner);
/* Don't free the header since we don't own it */
}
static CFTypeID __kACSharedArtImageSourceTypeID = _kCFRuntimeNotATypeID;
static CFRuntimeClass __ACSharedArtImageSourceClass = {0};
void __ACSharedArtImageSourceInitialize(void) {
__ACSharedArtImageSourceClass.version = 0;
__ACSharedArtImageSourceClass.className = "ACSharedArtImageSource";
__ACSharedArtImageSourceClass.init = NULL;
__ACSharedArtImageSourceClass.copy = NULL;
__ACSharedArtImageSourceClass.finalize = __ACSharedArtImageSourceDeallocate;
__ACSharedArtImageSourceClass.equal = NULL;
__ACSharedArtImageSourceClass.hash = NULL;
__ACSharedArtImageSourceClass.copyFormattingDesc = __ACSharedArtImageSourceCopyFormat;
__ACSharedArtImageSourceClass.copyDebugDesc = __ACSharedArtImageSourceCopyDescription;
__kACSharedArtImageSourceTypeID = _CFRuntimeRegisterClass((const CFRuntimeClass *)&__ACSharedArtImageSourceClass);
}
CFTypeID ACSharedArtImageSourceGetTypeID(void) {
return __kACSharedArtImageSourceTypeID;
}
static ACSharedArtImageSourceRef __ACSharedArtImageSourceInit(CFAllocatorRef allocator, ACSharedArtRef owner, CFIndex headerIndex)
{
struct __ACSharedArtImageSource * isrc;
UInt32 size = sizeof(struct __ACSharedArtImageSource) - sizeof(CFRuntimeBase);
isrc = (struct __ACSharedArtImageSource *) _CFRuntimeCreateInstance(allocator, __kACSharedArtImageSourceTypeID,size,NULL);
CFRetain(owner);
isrc->owner = owner;
isrc->headerIndex = headerIndex;
void * headerBytes = ACSharedArtGetBytePtr(isrc->owner) + ACSharedArtGetImageHeaderOffsetForIndex(isrc->owner,headerIndex);
isrc->header = (struct __ACSharedArtImageHeader *) (headerBytes);
return (ACSharedArtImageSourceRef) isrc;
}
/* Returns the type of image data contained within this ACSharedArtImageSource represented by:
kSharedArtImageSourceTypeHIRes
kSharedArtImageSourceTypeImage
kSharedArtImageSourceTypePDF
*/
ACSharedArtImageType ACSharedArtImageSourceGetType(ACSharedArtImageSourceRef isrc)
{
return isrc->header->type;
}
bool ACSharedArtImageSourceIsSpecialHIRes(ACSharedArtImageSourceRef isrc)
{
return ACSharedArtImageSourceGetEntryCount(isrc) == 1 && ACSharedArtImageSourceGetType(isrc) == kSharedArtImageTypeHIRes;
}
/*
Returns the amount of images contained within this ACSharedArtImageSource
*/
UInt16 ACSharedArtImageSourceGetEntryCount(ACSharedArtImageSourceRef isrc)
{
return isrc->header->entryCount;
}
/*
TACes a ACSharedArtRef as the "owner" file in order to provide certain data in order to create the image source along
with an index specifying where in the HeaderOffset table should this source's offset be loaded from. You are responsible
for releasing this source when you are done with it.
Returns a ACSharedArtImageSourceRef representing various image info and data concerning this element in the SArtFile.bin
*/
ACSharedArtImageSourceRef ACSharedArtImageSourceCreate(ACSharedArtRef owner, CFIndex headerIndex)
{
ACSharedArtImageSourceRef result = __ACSharedArtImageSourceInit(kCFAllocatorDefault,owner,headerIndex);
return result;
}
/*
Attempts to create a CGImageRef from the ACSharedArtImageSourceRef. The data held by the CGImageRef can be
ARGB or PDF, one must query ACSharedArtImageSourceGetType in order to make this determination. A common
way to write this data if you need to a disk is by making a CGImageDestination, adding the CGImageRef, and
using the corresponding UTType to write it to the disk.
*/
CGImageRef ACSharedArtImageSourceCreateImageAtIndex(ACSharedArtImageSourceRef isrc, size_t index)
{
if (index >= ACSharedArtImageSourceGetEntryCount(isrc))
return NULL;
struct __ACSharedArtImageHeaderDataInfo dataInfoAtIndex = isrc->header->data_info[index];
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL,
(const void *) (ACSharedArtGetBytePtr(isrc->owner) + dataInfoAtIndex.relativeOffset + isrc->owner->header->dataOffset),
dataInfoAtIndex.length,
0);
CGColorSpaceRef clrSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef imageRef = CGImageCreate(dataInfoAtIndex.width,dataInfoAtIndex.height,8,32,dataInfoAtIndex.width * 4,clrSpace,2,dataProvider,0,1,0);
CGColorSpaceRelease(clrSpace);
CGDataProviderRelease(dataProvider);
return imageRef;
}
CGImageRef ACSharedArtImageSourceCreateHIResImage(ACSharedArtImageSourceRef isrc)
{
if (ACSharedArtImageSourceGetType(isrc) != kSharedArtImageTypeHIRes || ACSharedArtImageSourceGetEntryCount(isrc) < 2)
return NULL;
return ACSharedArtImageSourceCreateImageAtIndex(isrc,1);
}
/* Since some parts of the ACSharedArtImageSource are actual PDFs in their full format, we cannot use
CGImage on certain data (mainly the 1st entry of PDF data). Instead call this method to retrieve
a CFDataRef to the bytes pointed to with the exact length specified by the source. You are
responsible for releasing this reference when you are done. */
CFDataRef ACSharedArtImageSourceCreateDataAtIndex(ACSharedArtImageSourceRef isrc, size_t index)
{
if (index >= ACSharedArtImageSourceGetEntryCount(isrc))
return NULL;
struct __ACSharedArtImageHeaderDataInfo dataInfoAtIndex = isrc->header->data_info[index];
return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,(const UInt8 *) (ACSharedArtGetBytePtr(isrc->owner) + dataInfoAtIndex.relativeOffset +
isrc->owner->header->dataOffset),dataInfoAtIndex.length,kCFAllocatorNull);
}
void ACSharedArtImageSourceWriteResourceToPathAtIndex(ACSharedArtImageSourceRef isrc, CFStringRef path, CFIndex index)
{
CFURLRef baseURLRef = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,path,kCFURLPOSIXPathStyle,true);
CFStringRef extension = __ACSharedArtImageSourceGetExtensionForWritingAtIndex(isrc, index);
CFURLRef urlRef = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault,extension,kCFURLPOSIXPathStyle,false,baseURLRef);
ACSharedArtImageType type = ACSharedArtImageSourceGetType(isrc);
if (type == kSharedArtImageTypePDF && index == 0)
{
/* Just write the pure data */
CFDataRef dataRef = ACSharedArtImageSourceCreateDataAtIndex(isrc, index);
ACWriteDataToURL(dataRef, urlRef);
CFRelease(dataRef);
}
else
{
CGImageRef imgRef = ACSharedArtImageSourceCreateImageAtIndex(isrc,index);
ACWriteImageToURLWithType(imgRef, urlRef, kUTTypePNG);
CGImageRelease(imgRef);
}
CFRelease(urlRef);
CFRelease(extension);
CFRelease(baseURLRef);
}
CFStringRef __ACSharedArtImageSourceGetExtensionForWritingAtIndex(ACSharedArtImageSourceRef isrc, CFIndex index)
{
/* Take care of the *special hires* case first */
ACSharedArtImageType type = ACSharedArtImageSourceGetType(isrc);
if (ACSharedArtImageSourceIsSpecialHIRes(isrc) || (type == kSharedArtImageTypeHIRes && index == 1))
return CFStringCreateWithFormat(NULL, NULL, HIRES_TEMPLATE,isrc->headerIndex);
if (type == kSharedArtImageTypePDF && index == 0)
return CFStringCreateWithFormat(NULL, NULL, PDF_TEMPLATE,isrc->headerIndex);
return CFStringCreateWithFormat(NULL, NULL, PNG_TEMPLATE,isrc->headerIndex);
}