Skip to content

Commit 2068157

Browse files
committed
Fixed a bug with the transparency not being preserved when converting between UIImage and the RGBA format.
Added some test code using c++ (changed app delegate to use .mm instead of m for obj-c++ support) Wrapped image code in a function to add it to the window to support multiple images Added a GraphicsCommon file, which contains C++ code to convert from RGBA8 to a 4 float structure. Added a transparent image to test
1 parent 3db8b51 commit 2068157

7 files changed

+298
-15
lines changed

GraphicsCommon.h

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//
2+
// GraphicsCommon.h
3+
// ImageConversion
4+
//
5+
// Created by Paul Solt on 8/24/11.
6+
// Copyright 2011 Paul Solt. All rights reserved.
7+
//
8+
9+
//#import <Foundation/Foundation.h>
10+
//
11+
//@interface GraphicsCommon : NSObject
12+
//
13+
//
14+
//@end
15+
16+
#include <iostream>
17+
#include <sstream>
18+
19+
static const int NUMBER_COLORS = 4;
20+
21+
/** The Color3D structure is used for storing the Red, Green, Blue, and Alpha components. */
22+
struct Color3D {
23+
24+
Color3D() : red(0.0f), green(0.0f), blue(0.0f), alpha(1.0f) {}
25+
26+
float red;
27+
float green;
28+
float blue;
29+
float alpha;
30+
}; // Color3D;
31+
32+
/** Prints out a Color3D structure */
33+
static std::ostream &operator<<(std::ostream &os, const Color3D &c) {
34+
os << "Color: (" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ")";
35+
return os;
36+
}
37+
38+
static std::string toString(const Color3D &c) {
39+
std::ostringstream os;
40+
os << "Color: (" << c.red << ", " << c.green << ", " << c.blue << ", " << c.alpha << ")";
41+
std::string str(os.str());
42+
return str;
43+
}
44+
45+
/** Converts a single color value from floating point space (0.0-1.0) to unsigned char (RGBA8) format.
46+
Red,green,blue,alpha in 0.0-1.0 space
47+
color will be in range 0-255
48+
Requires 4 component (RGBA) (unsigned char *) to be already allocated
49+
*/
50+
static inline void color3dToRGBA8(Color3D *colorIn, unsigned char *colorOut) {
51+
52+
// Clamp the negative colors to black, it's undefined behavior otherwise.
53+
Color3D newColor = *colorIn;
54+
if(newColor.red < 0) {
55+
newColor.red = 0;
56+
}
57+
if(newColor.green < 0) {
58+
newColor.green = 0;
59+
}
60+
if(newColor.blue < 0) {
61+
newColor.blue = 0;
62+
}
63+
64+
colorOut[0] = static_cast<unsigned char>(newColor.red * 255);
65+
colorOut[1] = static_cast<unsigned char>(newColor.green * 255);
66+
colorOut[2] = static_cast<unsigned char>(newColor.blue * 255);
67+
colorOut[3] = static_cast<unsigned char>(newColor.alpha * 255);
68+
}
69+
70+
static inline void RGBA8ToColor3d(unsigned char *colorIn, Color3D *colorOut) {
71+
colorOut->red = static_cast<float>(colorIn[0]) / 255.0f;
72+
colorOut->green = static_cast<float>(colorIn[1]) / 255.0f;
73+
colorOut->blue = static_cast<float>(colorIn[2]) / 255.0f;
74+
colorOut->alpha = static_cast<float>(colorIn[3]) / 255.0f;
75+
}
76+
77+
/** Converts a single color value from the colors Red, Green, Blue, Alpha in RGBA8 format to floating
78+
point format in (0.0-1.0) range.
79+
Requires the memory to be allocated for the colorOut parameter.
80+
@param red - the red component
81+
@param green - the green component
82+
@param blue - the blue component
83+
@param alpha - the alpha component
84+
@param colorOut - the floating point Color3D structure to store the conversion
85+
*/
86+
static inline void RGBA8ToColor3d(unsigned char red, unsigned char green, unsigned char blue,
87+
unsigned char alpha, Color3D *colorOut) {
88+
colorOut->red = static_cast<float>(red) / 255.0f;
89+
colorOut->green = static_cast<float>(green) / 255.0f;
90+
colorOut->blue = static_cast<float>(blue) / 255.0f;
91+
colorOut->alpha = static_cast<float>(alpha) / 255.0f;
92+
}
93+
94+
/** Converts a Color3D image to RGBA8 (unsigned char *) given the image dimensions. The function
95+
assumes the number of bytes per pixel color is 4. The memory should be allocated before calling this
96+
method. It simply copies data from one type to the other. ImageOut should be width*height*4
97+
@param imageIn - the image that should be converted
98+
@param imageOut - the image that should be used for output
99+
@param width - the number of pixels wide
100+
@param height - the number of pixels high.
101+
*/
102+
static inline void ConvertImageColor3dToRGBA8(Color3D *imageIn, unsigned char *imageOut, int width, int height) {
103+
int length = width * height;
104+
105+
// Need to increment unsigned char pointer by the number of colors each loop
106+
for(int i = 0, j = 0; i < length; ++i, j+=NUMBER_COLORS) {
107+
color3dToRGBA8(&imageIn[i], &imageOut[j]);
108+
}
109+
110+
}
111+
112+
static inline void ConvertImageRGBA8ToColor3d(unsigned char *imageIn, Color3D *imageOut, int width, int height) {
113+
int length = width * height;
114+
115+
// Need to increment unsigned char pointer by the number of colors each loop
116+
for(int i = 0, j = 0; i < length; ++i, j+=NUMBER_COLORS) {
117+
RGBA8ToColor3d(&imageIn[j], &imageOut[i]);
118+
}
119+
}

GraphicsCommon.m

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// GraphicsCommon.m
3+
// ImageConversion
4+
//
5+
// Created by Paul Solt on 8/24/11.
6+
// Copyright 2011 Paul Solt. All rights reserved.
7+
//
8+
9+
#import "GraphicsCommon.h"
10+
11+
@implementation GraphicsCommon
12+
13+
- (id)init
14+
{
15+
self = [super init];
16+
if (self) {
17+
// Initialization code here.
18+
}
19+
20+
return self;
21+
}
22+
23+
24+
25+
26+
@end

ImageConversion.xcodeproj/project.pbxproj

+15-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 45;
6+
objectVersion = 46;
77
objects = {
88

99
/* Begin PBXBuildFile section */
@@ -12,12 +12,13 @@
1212
1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
1313
2860E328111B887F00E27156 /* AppDelegate_iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 2860E326111B887F00E27156 /* AppDelegate_iPhone.m */; };
1414
2860E329111B887F00E27156 /* MainWindow_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2860E327111B887F00E27156 /* MainWindow_iPhone.xib */; };
15-
2860E32E111B888700E27156 /* AppDelegate_iPad.m in Sources */ = {isa = PBXBuildFile; fileRef = 2860E32C111B888700E27156 /* AppDelegate_iPad.m */; };
15+
2860E32E111B888700E27156 /* AppDelegate_iPad.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2860E32C111B888700E27156 /* AppDelegate_iPad.mm */; };
1616
2860E32F111B888700E27156 /* MainWindow_iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2860E32D111B888700E27156 /* MainWindow_iPad.xib */; };
1717
288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; };
1818
BD12AFAF134E31C40052742A /* MITLicense.txt in Resources */ = {isa = PBXBuildFile; fileRef = BD12AFAE134E31C40052742A /* MITLicense.txt */; };
1919
BD3F462C124A7A5D00959DE5 /* ImageHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = BD3F462B124A7A5D00959DE5 /* ImageHelper.m */; };
2020
BD3F4650124A852600959DE5 /* Icon4.png in Resources */ = {isa = PBXBuildFile; fileRef = BD3F464F124A852600959DE5 /* Icon4.png */; };
21+
BD93538F14054F72009660CC /* ShareArrow.png in Resources */ = {isa = PBXBuildFile; fileRef = BD93538E14054F72009660CC /* ShareArrow.png */; };
2122
/* End PBXBuildFile section */
2223

2324
/* Begin PBXFileReference section */
@@ -28,7 +29,7 @@
2829
2860E326111B887F00E27156 /* AppDelegate_iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate_iPhone.m; sourceTree = "<group>"; };
2930
2860E327111B887F00E27156 /* MainWindow_iPhone.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow_iPhone.xib; sourceTree = "<group>"; };
3031
2860E32B111B888700E27156 /* AppDelegate_iPad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate_iPad.h; sourceTree = "<group>"; };
31-
2860E32C111B888700E27156 /* AppDelegate_iPad.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate_iPad.m; sourceTree = "<group>"; };
32+
2860E32C111B888700E27156 /* AppDelegate_iPad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate_iPad.mm; sourceTree = "<group>"; };
3233
2860E32D111B888700E27156 /* MainWindow_iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow_iPad.xib; sourceTree = "<group>"; };
3334
288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
3435
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Shared/main.m; sourceTree = "<group>"; };
@@ -38,6 +39,8 @@
3839
BD3F462A124A7A5D00959DE5 /* ImageHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageHelper.h; sourceTree = "<group>"; };
3940
BD3F462B124A7A5D00959DE5 /* ImageHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageHelper.m; sourceTree = "<group>"; };
4041
BD3F464F124A852600959DE5 /* Icon4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon4.png; sourceTree = "<group>"; };
42+
BD93538E14054F72009660CC /* ShareArrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ShareArrow.png; sourceTree = "<group>"; };
43+
BD9353BB140554F7009660CC /* GraphicsCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphicsCommon.h; sourceTree = "<group>"; };
4144
/* End PBXFileReference section */
4245

4346
/* Begin PBXFrameworksBuildPhase section */
@@ -75,9 +78,10 @@
7578
2860E32A111B888700E27156 /* iPad */ = {
7679
isa = PBXGroup;
7780
children = (
81+
BD93538E14054F72009660CC /* ShareArrow.png */,
7882
BD3F464F124A852600959DE5 /* Icon4.png */,
7983
2860E32B111B888700E27156 /* AppDelegate_iPad.h */,
80-
2860E32C111B888700E27156 /* AppDelegate_iPad.m */,
84+
2860E32C111B888700E27156 /* AppDelegate_iPad.mm */,
8185
2860E32D111B888700E27156 /* MainWindow_iPad.xib */,
8286
);
8387
path = iPad;
@@ -89,6 +93,7 @@
8993
8D1107310486CEB800E47090 /* ImageConversion-Info.plist */,
9094
BD3F462A124A7A5D00959DE5 /* ImageHelper.h */,
9195
BD3F462B124A7A5D00959DE5 /* ImageHelper.m */,
96+
BD9353BB140554F7009660CC /* GraphicsCommon.h */,
9297
);
9398
name = Shared;
9499
sourceTree = "<group>";
@@ -152,10 +157,11 @@
152157
29B97313FDCFA39411CA2CEA /* Project object */ = {
153158
isa = PBXProject;
154159
attributes = {
160+
LastUpgradeCheck = 0410;
155161
ORGANIZATIONNAME = "Paul Solt";
156162
};
157163
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ImageConversion" */;
158-
compatibilityVersion = "Xcode 3.1";
164+
compatibilityVersion = "Xcode 3.2";
159165
developmentRegion = English;
160166
hasScannedForEncodings = 1;
161167
knownRegions = (
@@ -182,6 +188,7 @@
182188
2860E32F111B888700E27156 /* MainWindow_iPad.xib in Resources */,
183189
BD3F4650124A852600959DE5 /* Icon4.png in Resources */,
184190
BD12AFAF134E31C40052742A /* MITLicense.txt in Resources */,
191+
BD93538F14054F72009660CC /* ShareArrow.png in Resources */,
185192
);
186193
runOnlyForDeploymentPostprocessing = 0;
187194
};
@@ -194,7 +201,7 @@
194201
files = (
195202
1D60589B0D05DD56006BFB54 /* main.m in Sources */,
196203
2860E328111B887F00E27156 /* AppDelegate_iPhone.m in Sources */,
197-
2860E32E111B888700E27156 /* AppDelegate_iPad.m in Sources */,
204+
2860E32E111B888700E27156 /* AppDelegate_iPad.mm in Sources */,
198205
BD3F462C124A7A5D00959DE5 /* ImageHelper.m in Sources */,
199206
);
200207
runOnlyForDeploymentPostprocessing = 0;
@@ -211,7 +218,7 @@
211218
GCC_OPTIMIZATION_LEVEL = 0;
212219
GCC_PRECOMPILE_PREFIX_HEADER = YES;
213220
GCC_PREFIX_HEADER = ImageConversion_Prefix.pch;
214-
GCC_VERSION = 4.2;
221+
GCC_VERSION = com.apple.compilers.llvmgcc42;
215222
INFOPLIST_FILE = "ImageConversion-Info.plist";
216223
IPHONEOS_DEPLOYMENT_TARGET = 3.2;
217224
PRODUCT_NAME = ImageConversion;
@@ -225,7 +232,7 @@
225232
COPY_PHASE_STRIP = YES;
226233
GCC_PRECOMPILE_PREFIX_HEADER = YES;
227234
GCC_PREFIX_HEADER = ImageConversion_Prefix.pch;
228-
GCC_VERSION = 4.2;
235+
GCC_VERSION = com.apple.compilers.llvmgcc42;
229236
INFOPLIST_FILE = "ImageConversion-Info.plist";
230237
IPHONEOS_DEPLOYMENT_TARGET = 3.2;
231238
PRODUCT_NAME = ImageConversion;
@@ -242,7 +249,6 @@
242249
GCC_WARN_ABOUT_RETURN_TYPE = YES;
243250
GCC_WARN_UNUSED_VARIABLE = YES;
244251
IPHONEOS_DEPLOYMENT_TARGET = 3.2;
245-
PREBINDING = NO;
246252
SDKROOT = iphoneos;
247253
TARGETED_DEVICE_FAMILY = "1,2";
248254
};
@@ -259,7 +265,6 @@
259265
GCC_WARN_UNUSED_VARIABLE = YES;
260266
IPHONEOS_DEPLOYMENT_TARGET = 3.2;
261267
OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
262-
PREBINDING = NO;
263268
PROVISIONING_PROFILE = "";
264269
SDKROOT = iphoneos;
265270
TARGETED_DEVICE_FAMILY = "1,2";

ImageHelper.m

+3-5
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,13 @@ + (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image {
109109
}
110110

111111
//Create bitmap context
112-
113112
context = CGBitmapContextCreate(bitmapData,
114113
width,
115114
height,
116115
bitsPerComponent,
117116
bytesPerRow,
118117
colorSpace,
119-
kCGImageAlphaPremultipliedLast); // RGBA
118+
kCGImageAlphaPremultipliedLast); // RGBA
120119

121120
if(!context) {
122121
free(bitmapData);
@@ -145,8 +144,7 @@ + (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer
145144
CGDataProviderRelease(provider);
146145
return nil;
147146
}
148-
149-
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
147+
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
150148
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
151149

152150
CGImageRef iref = CGImageCreate(width,
@@ -177,7 +175,7 @@ + (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer
177175
bitsPerComponent,
178176
bytesPerRow,
179177
colorSpaceRef,
180-
kCGImageAlphaPremultipliedLast);
178+
bitmapInfo);
181179

182180
if(context == NULL) {
183181
NSLog(@"Error context not created");

iPad/AppDelegate_iPad.h

+4
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,9 @@
1414

1515
@property (nonatomic, retain) IBOutlet UIWindow *window;
1616

17+
18+
// Adds an image to an imageview on the window
19+
- (void)addImage:(NSString *)theFilename atPosition:(CGPoint)thePosition;
20+
1721
@end
1822

0 commit comments

Comments
 (0)