Monday, August 22, 2011

Thai Provincial Slogan

วันนี้ได้เลิก Submit Thai Provincial Slogan ไปยัง App Store สำหรับ Thai Provincial Slogan เป็นเเอ๊พสำหรับทายคำขวัญจังหวัดของไทย
ที่ใช้เล่นคลายเครียด พร้อมได้ความรู้ เกี่ยวคำขวัญจังหวัดเพิ่มขึ้นอีกด้วย เพื่อนคนใหนมี iPhone ก็ลองโหลดเล่นได้นะครับ



Monday, February 21, 2011

งานเลี้ยง IT#2 Alumni Party 2nd

รูปภาพส่วนหนึ่งของเลี้ยง IT#2 Alumni Party 2nd เมื่อวันที่ 19 กุมภาพันธ์ 2011 ที่ผ่านมา
ถ่ายโดยกี้ มีสองอัลบั้มนะครับ



อัลบั้มสอง

Friday, August 27, 2010

Easy way lazyload image on UITableViewCell

This is sample article lazyload image on UITableViewCell. The libary for use this article
http://allseeing-i.com/ASIHTTPRequest/ and the sample code from Apple
ThumbImageView.h

#import "ASIHTTPRequest.h"

@protocol ThumbImageViewDelegate;




@interface ThumbImageView : UIImageView {
id delegate;
NSString *imageName;
CGSize imageSize;
CGRect home;
BOOL dragging;
CGPoint touchLocation; // Location of touch in own coordinates (stays constant during dragging).
}

@property (nonatomic, assign) id delegate;
@property (nonatomic, retain) NSString *imageName;
@property (nonatomic, assign) CGSize imageSize;
@property (nonatomic, assign) CGRect home;
@property (nonatomic, assign) CGPoint touchLocation;

- (void)goHome;
- (void)moveByOffset:(CGPoint)offset;
- (id)initWithImageAtUrl:(NSURL*)theUrl;

@end



@protocol ThumbImageViewDelegate

@optional
- (void)thumbImageViewWasTapped:(ThumbImageView *)tiv;
- (void)thumbImageViewStartedTracking:(ThumbImageView *)tiv;
- (void)thumbImageViewMoved:(ThumbImageView *)tiv;
- (void)thumbImageViewStoppedTracking:(ThumbImageView *)tiv;

@end


ThumbImageView.m
#import "ThumbImageView.h"
#import "MoMagIO.h"

#define DRAG_THRESHOLD 10
#define ACTIVITYVIEW_TAG 123

float distanceBetweenPoints(CGPoint a, CGPoint b);

@interface ThumbImageView(PrivateMethods)

-(void)addLoadingCircle;
-(void)removeLoadingCircle;
-(void)downloadImageWithURL:(NSURL*)theUrl;

@end


@implementation ThumbImageView


@synthesize delegate;
@synthesize imageName;
@synthesize imageSize;
@synthesize home;
@synthesize touchLocation;

- (id)initWithImageAtUrl:(NSURL*)theUrl{

self = [super init];
if (self) {
[self setUserInteractionEnabled:YES];
[self setExclusiveTouch:YES];
self.image = nil;
// Add loading circle
[self addLoadingCircle];
// Asyncronous download image
[self downloadImageWithURL:theUrl];
}
return self;
}

-(void)addLoadingCircle{

UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 24, 24)];
indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
indicatorView.center = CGPointMake((152/2),(195/2));
indicatorView.tag = ACTIVITYVIEW_TAG;
[self addSubview:[indicatorView autorelease]];
[indicatorView startAnimating];
}

-(void)removeLoadingCircle{

UIActivityIndicatorView *indicatorView = (UIActivityIndicatorView*)[self viewWithTag:ACTIVITYVIEW_TAG];
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
}
-(void)downloadImageWithURL:(NSURL*)theUrl{
NSLog(@"Url for download %@",theUrl);
NSString *pathToSave = [[MoMagIO getCacheDirPath] stringByAppendingPathComponent:[[theUrl path] lastPathComponent]];
//
if(imageName != pathToSave){
[imageName release];
imageName = [pathToSave retain];
}
NSFileManager *fm = [NSFileManager defaultManager];
if([fm fileExistsAtPath:self.imageName]){
UIImage *img = [[UIImage alloc] initWithContentsOfFile:imageName];
if(img){
self.image = img;
[self setNeedsDisplay];
}
[img release];
[self removeLoadingCircle];
}else {

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:theUrl];
[request setDelegate:self];
request.didFailSelector = @selector(downloadDidFailed:);
request.didFinishSelector = @selector(downloadDidCompleted:);
request.downloadDestinationPath = imageName;
[request startAsynchronous];
}
}
-(void)downloadDidFailed:(ASIHTTPRequest *)request{
#ifdef DEBUG
NSLog(@"ThumbImageView:-(void)downloadDidFailed:(ASIHTTPRequest *)request %@",[request error]);
#endif
NSBundle *bundle = [NSBundle mainBundle];
NSString *root = [[bundle resourcePath] stringByAppendingPathComponent:@"cover_preload.jpg"];
UIImage *img = [[UIImage alloc] initWithContentsOfFile:root];
if(img){
self.image = img;
[self setNeedsDisplay];
}
[img release];
[self removeLoadingCircle];
}
-(void)downloadDidCompleted:(ASIHTTPRequest *)request{
UIImage *img = [[UIImage alloc] initWithContentsOfFile:imageName];
if(img){
self.image = img;
[self setNeedsDisplay];
}
[img release];

[self removeLoadingCircle];
}

- (id)initWithImage:(UIImage *)image {
self = [super initWithImage:image];
if (self) {
[self setUserInteractionEnabled:YES];
[self setExclusiveTouch:YES];
}
return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// store the location of the starting touch so we can decide when we've moved far enough to drag
touchLocation = [[touches anyObject] locationInView:self];
if ([delegate respondsToSelector:@selector(thumbImageViewStartedTracking:)])
[delegate thumbImageViewStartedTracking:self];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// we want to establish a minimum distance that the touch has to move before it counts as dragging,
// so that the slight movement involved in a tap doesn't cause the frame to move.
/**CGPoint newTouchLocation = [[touches anyObject] locationInView:self];
if (dragging) {
float deltaX = newTouchLocation.x - touchLocation.x;
float deltaY = newTouchLocation.y - touchLocation.y;
[self moveByOffset:CGPointMake(deltaX, deltaY)];
}
else if (distanceBetweenPoints(touchLocation, newTouchLocation) > DRAG_THRESHOLD) {
touchLocation = newTouchLocation;
dragging = YES;
}**/
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (dragging) {
[self goHome];
dragging = NO;
} else if ([[touches anyObject] tapCount] == 1) {
if ([delegate respondsToSelector:@selector(thumbImageViewWasTapped:)])
[delegate thumbImageViewWasTapped:self];
}
if ([delegate respondsToSelector:@selector(thumbImageViewStoppedTracking:)])
[delegate thumbImageViewStoppedTracking:self];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self goHome];
dragging = NO;
if ([delegate respondsToSelector:@selector(thumbImageViewStoppedTracking:)])
[delegate thumbImageViewStoppedTracking:self];
}

- (void)goHome {
float distanceFromHome = distanceBetweenPoints([self frame].origin, [self home].origin); // distance is in pixels
float animationDuration = 0.1 + distanceFromHome * 0.001;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
[self setFrame:[self home]];
[UIView commitAnimations];
}
- (void)moveByOffset:(CGPoint)offset {
CGRect frame = [self frame];
frame.origin.x += offset.x;
frame.origin.y += offset.y;
[self setFrame:frame];
if ([delegate respondsToSelector:@selector(thumbImageViewMoved:)])
[delegate thumbImageViewMoved:self];
}

@end

float distanceBetweenPoints(CGPoint a, CGPoint b) {
float deltaX = a.x - b.x;
float deltaY = a.y - b.y;
return sqrtf( (deltaX * deltaX) + (deltaY * deltaY) );
}

Then use it
// Left photo
ThumbImageView *thumbViewLeft = [[[ThumbImageView alloc] initWithImageAtUrl:url] autorelease];
thumbViewLeft.userInteractionEnabled = YES;
thumbViewLeft.exclusiveTouch = NO;
thumbViewLeft.layer.borderWidth = 1.0f;
thumbViewLeft.layer.borderColor = [[UIColor lightGrayColor] CGColor];
[thumbViewLeft setDelegate:self];
CGRect frame = [thumbViewLeft frame];
frame.origin.y = IMAGE_PADDING;
frame.origin.x = xPosition;
frame.size = CGSizeMake(imageWidth,IMAGE_HEIGHT);
[thumbViewLeft setFrame:frame];
[thumbViewLeft setHome:frame];
thumbViewLeft.tag = LEFT_IMAGE;
//image =[[UIImage alloc] initWithContentsOfFile:[root stringByAppendingPathComponent:@"cover_preload.jpg"]];
//[thumbViewLeft setImage:[ImagePopulate image:image fitInSize:thumbViewLeft.frame.size]];
//[image release];
[cell.contentView addSubview:thumbViewLeft];
xPosition += (frame.size.width + IMAGE_PADDING);


Happy with programming

Wednesday, August 18, 2010

การ embed youtube ใน UIWebView

โดยปรกติแล้วการเล่นวีดีโอผ่าน youtube ส่วนมากจะเป็น 3rd party ที่เวลาเล่นแล้ว
จำเป็นจะต้องดีดออกจาก app แต่ถ้าอยากให้เล่นใน app ก็สามารถทำได้ครับ


- (void)embedYouTube:(NSString *)urlString frame:(CGRect)frame {

NSString *embedHTML = @"starthtml starthead\ \ endhead startbody style=\"margin:0\">\
\
endbody endhtml";
NSString *html = [NSString stringWithFormat:embedHTML, urlString,
frame.size.width, frame.size.height];

if (!webView) {
webView = [[UIWebView alloc] initWithFrame:frame];
[self.view addSubview:webView];
}

[webView loadHTMLString:html baseURL:nil];

}


หลังจากนั้นแค่เรียก


[self embedYouTube:self.url frame:CGRectMake(20, 20, 280, 300)];


more information
http://apiblog.youtube.com/2009/02/youtube-apis-iphone-cool-mobile-apps.html
http://iphoneincubator.com/blog/audio-video/how-to-play-youtube-videos-within-an-application

Wednesday, August 11, 2010

UIScrollView zooming centered UIImageView

การซูมใน UIScrollView ถ้าซูมรูปเดียวคงไม่มีปัญหาอะไร เพราะมี method ให้เลือกใช้งานดังนี้

float newScale = [imageScrollView zoomScale] * maxZoomLevel;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:tapPoint];
[imageScrollView zoomToRect:zoomRect animated:YES];


แต่เปิด View ขึ้นมาแล้วให้รูปซูมขึ้นมาเลย แล้วก็ให้อยู่ center ด้วยนั้นสามารถทำได้ดังนี้ครับ

CGFloat tempx = view.center.x-160;
CGFloat tempy = view.center.y-160;
myScrollViewOffset = CGPointMake(tempx,tempy);


เเหล่งข้อมูล
http://stackoverflow.com/questions/638299/uiscrollview-with-centered-uiimageview-like-photos-app
http://stackoverflow.com/questions/1316451/center-content-of-uiscrollview-when-smaller
http://discussions.apple.com/thread.jspa?messageID=8322675

Monday, August 9, 2010

iPhone storekit - Handler cancel event by user

เมื่อเราพัฒนาเเอพพลิเคชั่นที่จำเป็นต้องใ่ช้ In-App purchase จำเป็นทำการ implement SKPaymentTransactionObserver
สำหรับการทำ Transaction ในการ purchase item ต่างๆ และเมื่อ storekit ขึ้นหน้าจอให้ confirm การ purchase จะมีสอง
ปุ่มให้เลือกคือ Cancel และ Buy จำการ cancel Transactionstate ที่ได้จะเป็น SKPaymentTransactionStateFailed ซึ่งเรา
สามารถที่จะทำการตรวจสอบว่า transaction state นั้นการจากการ fail หรือ cancel โดย user โดยเช็คได้ดังนี้

transaction.error.code != SKErrorPaymentCancelled


โ่ค้ดเเบบสมบูรณ์


- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:

[self completeTransaction:transaction];

break;

case SKPaymentTransactionStateFailed:

[self failedTransaction:transaction];

break;

case SKPaymentTransactionStateRestored:

[self restoreTransaction:transaction];

default:

break;
}
}
}

- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
// Optionally, display an error here.
if([self.delegate respondsToSelector:@selector(failedTransaction:)])
[self.delegate failedTransaction:transaction];
}else {
if([self.delegate respondsToSelector:@selector(canceledTransaction:)])
[self.delegate canceledTransaction:transaction];

}

[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
if([self.delegate respondsToSelector:@selector(completeTransaction:)])
[self.delegate completeTransaction:transaction];

[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
if([self.delegate respondsToSelector:@selector(restoreTransaction:)])
[self.delegate restoreTransaction:transaction];

[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

Thursday, July 29, 2010

การ encrypt/decrypt รูป

การ encrypt/decrypt ก็คงเป็นการเข้ารหัสข้อมูลที่สำคัญ ที่ไม่ต้องการจะเปิดเผยให้ใครรู้
ซึ่งในระหว่างการส่งข้อมูลในแต่ละ tier นั้นอาจจะใช้โปรเเกรมพวก sniffer ดักเอาก็ได้ เพื่อ
ความปลอดภัย เราโปรเเกรมเมอร์จึงต้องเข้ารหัสข้อมูลแล้วก็ใส่รหัสผ่านของเราไว้สำหรับถอดรหัสด้วย

ที่นี้การเ้ข้ารหัสนั้นไม่ว่าภาษาใหนก็ทำได้และมีอัลกอลิทึมให้ใช้กันอย่างหลากหลาย ซึ่งการเข้ารหัส
และถอดรหัสด้วยภาษาเดียวกันอาจจะทำได้ง่ายกว่า การเข้ารหัสด้วยภาษาหนึ่งแล้วไปถอดรหัสอีกภาษาหนึ่ง
ซึ่งในกรณีซึ่งเป็นระบบเเบ็คเอ็นต้องเข้ารหัสรูปบน asp.net(c#) แล้วไปถอดบน iphone ใ่ช้เวลา
ลองผิดลองถูกเกือบสองวันในที่สุดก็ทำได้ครับ

ส่วนสำคัญอยู่ตรงนี้ครับ

byte[] images = File.ReadAllBytes(@"C:\Wallpaper\encrypt.jpg");

string x = Convert.ToBase64String(images);
string result = DecryptString(x, "digix");
byte[] data = Convert.FromBase64String(result);
FileStream fsout = new FileStream(@"C:\Wallpaper\decrypt.jpg", FileMode.CreateNew);
fsout.Write(data, 0, data.Length);
fsout.Flush();
fsout.Close();


เเหล่งข้อมูลที่ใช้ในการศึกษา
http://stackoverflow.com/questions/1373032/c-howto-convert-image-to-binary
http://stackoverflow.com/questions/885237/writing-an-image-to-a-text-file-as-binary-data-c
โค้ดการเข้ารหัส string จาก http://dotmac.rationalmind.net/2009/02/aes-interoperability-between-net-and-iphone/

///
/// Encrpyts the sourceString, returns this result as an Aes encrpyted, BASE64 encoded string
///

/// a plain, Framework string (ASCII, null terminated)
/// The pass phrase.
///
/// returns an Aes encrypted, BASE64 encoded string
///

public static string EncryptString(string plainSourceStringToEncrypt, string passPhrase)
{
//Set up the encryption objects
using (AesCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passPhrase)))
{
byte[] sourceBytes = Encoding.ASCII.GetBytes(plainSourceStringToEncrypt);
ICryptoTransform ictE = acsp.CreateEncryptor();

//Set up stream to contain the encryption
MemoryStream msS = new MemoryStream();

//Perform the encrpytion, storing output into the stream
CryptoStream csS = new CryptoStream(msS, ictE, CryptoStreamMode.Write);
csS.Write(sourceBytes, 0, sourceBytes.Length);
csS.FlushFinalBlock();

//sourceBytes are now encrypted as an array of secure bytes
byte[] encryptedBytes = msS.ToArray(); //.ToArray() is important, don't mess with the buffer

//return the encrypted bytes as a BASE64 encoded string
return Convert.ToBase64String(encryptedBytes);
}
}


///
/// Decrypts a BASE64 encoded string of encrypted data, returns a plain string
///

/// an Aes encrypted AND base64 encoded string
/// The passphrase.
/// returns a plain string
public static string DecryptString(string base64StringToDecrypt, string passphrase)
{
//Set up the encryption objects
using (AesCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passphrase)))
{
byte[] RawBytes = Convert.FromBase64String(base64StringToDecrypt);
ICryptoTransform ictD = acsp.CreateDecryptor();

//RawBytes now contains original byte array, still in Encrypted state

//Decrypt into stream
MemoryStream msD = new MemoryStream(RawBytes, 0, RawBytes.Length);
CryptoStream csD = new CryptoStream(msD, ictD, CryptoStreamMode.Read);
//csD now contains original byte array, fully decrypted

//return the content of msD as a regular string
return (new StreamReader(csD)).ReadToEnd();
}
}

private static AesCryptoServiceProvider GetProvider(byte[] key)
{
AesCryptoServiceProvider result = new AesCryptoServiceProvider();
result.BlockSize = 128;
result.KeySize = 128;
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.PKCS7;

result.GenerateIV();
result.IV = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

byte[] RealKey = GetKey(key, result);
result.Key = RealKey;
// result.IV = RealKey;
return result;
}

private static byte[] GetKey(byte[] suggestedKey, SymmetricAlgorithm p)
{
byte[] kRaw = suggestedKey;
List kList = new List();

for (int i = 0; i < p.LegalKeySizes[0].MinSize; i += 8)
{
kList.Add(kRaw[(i / 8) % kRaw.Length]);
}
byte[] k = kList.ToArray();
return k;
}