Tumgik
#Can't improve if there's no starting line! Gotta start somewhere!!
dairy-farmer · 2 months
Note
You remember that new story a while back? About the device that can deliver an orgasm at the push of a button?
I remember.
It's connected to the spine! Gotta hijack the right nerves etc. And the box implant is kinda bulky. Buuuuut~ CONSIDER! :3c
DC technology! Bat paranoia! Tim Robin getting captured one too many times! And driving Bruce to a damn near mental break down! Bruce is shaking, days old stubble, bags that a Racoon would envy under his eyes. The WORKS. Tim has worked too damn hard, pulling this trainwreck together, just to be the REASON he falls apart.
He consents to a tracker.
Bruce falls to his knees and... and hugs him. Is so GRATEFUL. Shaking like a leaf and clinging like he might disappear. Had been braced like he thought Tim would snarl and fight him.
Tim just hugs him back. Pretend not to notice the wet, seeping into his shoulder.
And it totally helps! Batman feels more in control. Knows where he is. Is calmer. It even saves his life a few times. But? Technology gets better and fights get harder. He gets thrown into a wall. Crunch!
Immediate emergency surgery to get the old tracker out. In pieces. Tim nearly gets poisoned too. But NOT having the tracker in? Bruce's anxiety shoots through the roof. He locks himself in his lab. Comes out looking unhinged. Better tracker. Limited bio feedback.
Sure. Okay. Whatever helps, Bruce.
But then? Alien bullshit. They go to deep space. Out of range. Bruce FREAKS. It starts becoming A Thing. Better range. Harder to break. Smaller. Smarter. More compatible. On and on and on. And? Bruce has started leaning on him more.
Tim GETS the Mission. The need to plan for plans within plans. The odd hours and late nights. He's seen Bruce at his WORST. Is his partner.
Is... starting to notice boys.
Develop NEEDS he didn't have before.
Things that Bruce can't control or follow him in. Or at least, is not SUPPOSED too. The anxiety is unbearable. Every punk a vessel for STDs and supervilliany. Plotting to stab Tim or get him pregnant and blackmail him. Alien face eating parasites. League plants. Alternate reality future assassins!
He can't bear it.
But he can't ignore that it perfectly VALID for Tim to have NEEDS.
But... but Tim is HIS. He NEEDS Tim. These distractions are unacceptable and frankly? A problem to be fixed. And really, he KNOWS why Tim is (in his own awkward, charming way) searching out these boys. The potential to "fool around". Feel good. Orgasm.
There was a device patented recently by Wayne Medical. He can vastly improve it with alien tech. Make it unhackable.
Tim doesn't need those boys. Tim has him. The mission. And besides, this is BETTER. Cleaner. Tim likes clean! And THIS way, he can have... can HELP, Tim without crossing that line. It's not like he's TOUCHING anything, like this. So it's better.
This time he put both devices in, instead of just the tracker. It takes a bit longer to heal, since one connects to several nerves. But that just means No Dates and more time with Bruce. Which is nice. Waits for Tim to heal up.
He fingers the innocuous little black clicker. Makes sure to watch on the security feed. Don't want to catch him somewhere precarious, he justifies. And as Tim enters his room, closes the door, he let's his thumb rest on the button. Click.
Watches as Tim jolts, cries out at the new sensation, his legs shaking and then giving out beneath him. Leaving him to ride out the aftershocks on the floor, utterly confused. Bruce drinks in every sound and expression. Clicks again, just to be sure.
Again Tim buckles, a plaintive whine wretched out of him. Brain unable to tell him WHERE on his body the pleasure is coming from, only that it is happening. Legs pressing together, trying to rock and tease, ANY stimulus so things might make sense.
Adorable.
He really does want to tease him. Make him feel so good, he's left brainless and drooling. Bruce decides he was right. This IS cleaner. Better. No disgusting, handsy boys panting and grunting, as they rutt against Tim like animals desperate for their own release. Not a care in the world for Tim's pleasure or duties. Just Bruce.
And he can take care of his Robin. Watch over him. He presses the button again, just to watch his boy spasm in pleasure. It's not WRONG if he doesn't TOUCH Tim. He's just helping. Providing!
And that's what he'll tell himself. Every time Robin gets a reward for doing a good job. Click. Or gets a good grade in class. Click. Or comes to spend time with Bruce instead of those icky, icky DATES. Click.
It's not conditioning! It's REWARDS.
Tim LOVES spending time with him! (Click.) And, of course, he realizes that needs evolve. Not everything can be solved by his clicker. So that's what toys are for. Harnesses and fucking machines. Intimidating at first (Click.) but Tim is very brave and has many needs. They help.
And if Bruce supervises? To make sure he doesn't get hurt? It's purely out of concern! They discuss cases. The days events. Why Tim does NOT need to EVER date and is happy he has such a good Dad. A good partner.
He LOVES his partner, doesn't he, Tim? (Click.)
And if Bruce doesn't need to know, that Tim could have removed both devices AGES ago? That's his business. Tim is out here living his best Wet Dream Life. Mind your business.
-🐼🐼🐼
bruce is the pinnacle of a paranoid obsessive 👀👀👀 and evolving his obsession with knowing where tim is to getting him off fits.
51 notes · View notes
maelstrom-of-emotions · 9 months
Text
BakuDeku fic idea
Okay, so I had this idea, and it's been nagging me for like, forever, so, naturally I gotta talk about it.
So, maybe, years later, after they've gotten married and all, Katsuki is organizing Deku's desk because for all that the damn nerd is a genius, he's terrible at organizing things.
And then he comes across Deku's notebook collection, the notebooks that Katsuki would swear up and down were practically an extension of Izuku's soul.
He opens them, having seen them occasionally when Deku would get nostalgic and turn the paces, tracing the intricate lines with a sense of wistfulness, or when he would get right into Katsuki's face saying ‘I figured out where I saw that quirk Kachaan! It was here,’ but he's never flipped through them, despite having Izuku's consent to do so.
And so for the first time, he flips through them, starting from the first, of course, because Katsuki is many things, but he's no madman.
The first one is all bright and wide-eyed, filled with sketches of All Might and other top heroes, and Katsuki can't help the fond smile that spreads on his face as he sees the small doodles of himself dotting the margins of the notebook. It was like staring at a damn kindergarten art project. Deku's admiration for them practically oozed off the pages.
The leading notebooks that came after that were filled with scribbles, points and additions, edits and mentions, but it was all still pretty wholesome (and so Katsuki may have taken a photo of a particularly adorable sketch of a chibi him, with the words 'Lil' Victory upon it, so he can make it into a custom keychain, sue him.)
And then, out of nowhere, they get intense. The sketches were detailed, showing fights, strategies, and damn, even the villains. And the proud smile that grows on his face is entirely deserved, because, that was his nerd, alright. It was like seeing inside the mind of a madman but in a good way. Deku was getting serious, that adorable little nerd.
Somewhere along the way, Deku had begun to record the injuries caused by the quirks. The pages were stained with reds and purples, like some kind of twisted canvas. Bakugou winced, remembering the pain that had carved itself into Deku's skin. The scars on Deku's body had a story, and they were all right there, etched in ink.
(He hates the fact that he had been the cause of most of those scars. Hates the thought of Deku, staring at the scars on his body and copying them on paper, having been familiar with them for so long, that he doesn't even need to double-check. Hates the way that it brings tears to his eyes.)
The notebooks after that were a whole new world. he sketches were practically alive, the movements fluid and precise. It was like watching a damn animated movie. This nerd was on the edge of genius.
The points on quirks had improved too. Notes on how they worked, weaknesses, and strategies to counter them. It was like Deku had cracked the code to every damn hero he'd ever faced. Bakugou couldn't decide if he was impressed or annoyed. Probably both.
That notebook was the culmination of everything Deku had ever learned. The battles were fierce, the strategies ruthless. This was Deku at his damn peak.
He's just about to put them back, telling himself that the tears in his eyes were due to the dust when he sees the last notebook. It's the newest notebook, the cover bright and glossy.
He opens it and expects another one of Deku's meticulous quirk analyses, but this...this was something else entirely.
Page after page was filled with details about their friends, their likes and dislikes, little facts that even Bakugou didn't know. It was like Deku had become some kind of damn detective, gathering every scrap of information he could find.
And then he turned a page and was greeted by an explosion of orange and black, and there it was. His name, his figure, drawn in causal clothes, with little notes written in beautiful handwriting.
The details hit him like a damn sledgehammer. There's an arrow pointing to his middle finger 'wears a ring on this one.' An arrow to his clothes with the words 'prefers soft clothes (best hoodies to steal),' there's one pointing to his neck followed by 'wears a locket with parent's photos' and on, and on, they go. His eyes start to water at 'rich laugh' and 'bright grin.'
He pauses at the one written in red ink with the words 'softest heart' written right next to it.
This damn nerd, he knew him better than anyone else. Knew the quirks and intricacies that made up Bakugou Katsuki.
He couldn't help the small smile that tugged at the corner of his lips. Maybe, just maybe, Deku wasn't so damn bad at understanding people after all.
And if Izuku finds himself bombarded with bowls of Katsudon, well, that's nobody's business but his own. Even if the nerd cries when he sees the keychain.
105 notes · View notes
cherryrainn · 4 months
Note
How would Striker react if the human asked if they were pathetic because of her fuck ups on the job as they kind of had sucky aim with a gun and has a hard time following instructions because of their auditory processing disorder? Striker is an antihero with redeemable qualities.
https://m.youtube.com/shorts/0U0TpIdg538
ENCOURAGEMENT .
Tumblr media Tumblr media
; pairing ; striker x human! reader
; note ; aww this is sweet! thank you for your ask
; warnings ; self doubt
Tumblr media
striker eyed you with his sharp yellow gaze. the weight of your recent mistakes on the job bore down on you, and you couldn't help but wonder what the relentless imp thought of your performance.
finally mustering the courage, you broke the silence. "hey, striker, am i just pathetic? i mean, with the whole job thing, my aim sucks, and i have a hard time following instructions because of my disorder."
striker's expression shifted, a mixture of surprise and contemplation dancing across his serpentine face. it wasn't often that someone confronted him with their vulnerabilities, and the raw honesty caught him off guard. after a moment, he leaned back, crossing his arms as he regarded you with a more thoughtful expression than his usual arrogant demeanor.
"pathetic? nah,, you're just inexperienced. we all start somewhere," he replied, his voice gruffer than usual. "besides, not everyone's got perfect aim from the get-go. takes time and practice. as for the whole instructions thing, we're hardly the masters of clarity, so i get it."
you couldn't help but feel a sense of relief at his unexpected understanding. striker's acknowledgment that everyone has a learning curve and that your struggles weren't necessarily a sign of inherent weakness surprised you. it was a side of him that went beyond the usual arrogance and violence.
"but," he continued, a sly grin forming, "if you're looking to improve, you better start getting your act together. no room for mistakes in our line of work. you gotta be quick on the draw and follow orders, even if they sound like gibberish. can't afford to be dead weight."
despite his gruff tone, there was an underlying hint of encouragement. it seemed that striker was offering a challenge rather than dismissing your capabilities.
22 notes · View notes
sysig · 2 years
Text
Me to me: It’s important to identify crutch words so I can branch out and try to describe things more exactly, rather than relying on the same handful over and over again
Me, in return: HnnnnNNGNNGNGG bu t the floo oo o oooo owww ww
4 notes · View notes
antirepurp · 2 years
Text
thinking abt a naruto fic i listened a guy read once where the author was painfully straightforward with their insistence on naruto acting dumb bc it was expected of him to the point they had him say so word for word, and worrying that im doing the same shit with my take on jotaro
3 notes · View notes
hopeamarsu · 2 years
Note
Happy New Year! Thank you for the immense joy your writing brought me this year! 💜
To honor the tradition of looking back on the year, here are some 2021 Writing Reflections I'd love for you answer! 
1) What is the one thing you're most proud of with your writing this year?
2) What is your favorite line you've written this year?
3) How has your writing improved this year?
4) How do you hope to improve your writing next year?
5) Do you have any specific writing goals for '22?
Happy New Year Sunny! 💜 I'm so happy our paths crossed here this year, bringing me so much joy, and I am looking forward to next year!
Oh, these are hard questions but I can't wait to dig in:
1) What is the one thing you're most proud of with your writing this year?
Is it going to sound silly if I say that I am proud of myself for writing chaptered fics? Like those ones where you sort of plan for it, because I am proud of myself for that. 
I planned and finished two chaptered fics this year and I have started on writing a third so that’s exciting. I’ve tried this before and failed tremendously so to be able to hold down the plot, plan the world and write down the words feels like a huge accomplishment to myself.  
2) What is your favorite line you've written this year?
The Diletto series is one of my favorites I’ve done this year and the ending to Pero’s fic, Porcelain dildo, remains a favorite of mine (and makes me a little feral, if I’m honest):
You nod quickly, wetting you lips. “Will it fit though? It looks so big,” Your voice is breathless as you try to fit your fist around the bulbous end, rubbing the smooth surface in your hand. A groan leaves his lips with the image.
“It’ll fit mi cielo. After all, I fit and this is no bigger than me. I made sure of it.”
3) How has your writing improved this year?
I think I’ve gotten more versatile when I write. 
It’s easier to describe things and I’ve learned a lot about being more inclusive in writing. There’s definitely a lot more I can still improve on them, but I feel like I’ve gotten a good baseline for myself.
4) How do you hope to improve your writing next year?
Ooh, that’s a tough question. 
I’d like to tackle a few new characters, maybe delve deeper into an AU, really build that world from the ground up. 
Also... I’d like to be more confident. I still have lots of those moments where I think I’m not good enough, everything I do is garbage and I want to throw the proverbial journal out the window and hide from the world. I guess not all of it goes away ever and that’s good because it allows us to improve and be better, but yeah. Being a tiny bit more confident in myself wouldn’t hurt.
5) Do you have any specific writing goals for '22?
I don’t know yet. 
Oh, maybe one! 
I started a Robin Hood AU for Din this year and abandoned it somewhere in the middle. I’d like to go back and rework it so it a) works, b) flows and c) feels in-character for Din. I really love the premise and the story, I just got stuck and couldn’t find my way out. 
Unfortunately that means I’ll need to rewatch the Mandalorian season 1 and 2 again. It’s a tough job but someone’s gotta do it right? :D
Thank you so much for asking these, they really picked my brain 💜Sending you love and hugs for the final day and for a wonderful 2022 ahead! 
3 notes · View notes
Note
I find it interesting that you say Jungkook isn't the most popular member and mention 2013 because I'm fairly new to the fandom (about 6 months) and I still can't figure out why he's always brought up as the "most popular member" not only that but also someone who "gets everything handed to them on a silver platter while the others suffer" I've only seen him get so much hate and mostly armys themselves love to mock him. a lot (that I've seen so this is biased) jungkook stans go on with (cont)
the whole "I hate jungkook" or "he's so stupid" and the classic "he's such a fuckboy/he's so arrogant and cocky" and for the longest time I thought I was being too sensitive? I can't even tell anymore what's supposed to be "real hate" or "love hate" it's all the same and I understand being aggressive about your life but with jungkook it goes TOO far. with the other members it's always "he's so soft and precious I love him" but it's rare to find jungkook stans who say that when everyone is too busy hating him to be funny/get likes/rts/whatever! and you're right about not being able to praise jungkook because you're going to get so many comments like "uhh but he's always the main/in the centre/gets the most likes/most popular can you focus on the other members and not make everything about him" boy can't even get appreciated and praised for what he's good at now without triggering anyone? I don't care about any of that, if he does something I'm proud of you bet I'm going to praise him. also, just my two cents but I think the whole "jungkook solo stans" is a bit overrated, Im not denying that they exist but at this point they're nearly not as prevalent as armys who mock jungkook, or start petitions to kick him out of bts for "stealing lines" that's another thing I never found funny, those jokes about jungkook "stealing" lines and being so possessive over his lines that he'd fight anyone if they got even a single line more than him? this kind of got a bit off topic, so I apologize for the rant but, I meant to say that in my humble onion, I feel that jin is one of the most popular members in the group. you don't even have to be a jin stan but everyone loves him so much!!!! he's not as "underappreciated" as people make him out to be (and I mean fandom-wise, not the whole drama about line distribution) he's really popular with everyone so don't give me that "jin deserves more attention/love than jungkook" you can say that without dragging jungkook's name into everything and pitting members against each other? Yikes! but good luck for your exam!! ❤️
get handed on a silver platter... who tf is making that bullshit claim?? he works his ass off. he’s always trying to improve. in every damn album somewhere in his extra long thanks to letter he mentions how he’s trying to become better as if he isn't already amazing enough. he is learning english and japanese for the fans, helped choreograph some moves, is learning how to produce which he’s taking seriously yoongi even said jungkook has been asking him A LOT of question and namjoon jokingly complained that jungkook only shares the songs he writes with hobi. he had his lil 12/13 yr old ass sent to america without his family to train in dancing...i’d cry if i was sent halfway across the world to work n i don't even like my parents... he does NOT have things handed to him. he works extremely hard and is still working hard trying to overcome his shyness as he worries about the mask he wears when he first meets ppl as though he hasn't had to work hard already just to settle his anxiety when it came to performing and simply just singing to his members??
jungkook? a fuckboy? arrogant? that’s literal bullshit. that’s how u know a fan hasn't bothered learning about the group/jungkook at all if they think that. jungkook is amazing at putting up a mask of confidence, telling himself he’s gonna do fine, even when he doesn't HAVE the confidence, so that he can put on a great show. he is a born performer meant to be on stage n if u mistake his confident stage persona as a fuckboy personality?? that’s on u honestly n ur missing out on a sweet baby boy who loves his fans and members like they’re his family.
honestly jungkook ‘stans’ or ‘stans in denial’ who just shit on him n call him names n always say they hate him...they aren't funny or cool just ignore them it’s annoying as shit i’ve blocked blogs like that, i simply don't tolerate it.
I've never seen a ‘jungkook solo stan’ in my life i barely know/follow anyone who even stans JUST jungkook xdfgchvj what even is that. also,,, his role,,in the fucking group,, is the center,, that’s why he stands in the middle for just about every video and award show...and why he dances in the middle often.... being the center is as much his job as being the main vocal/lead dancer.
no member deserves more love/appreciation over another it’s just that...do ppl realize when they yell at me ‘you gotta love n appreciate ALL the members!!1!’ that jungkook is supposed to be included in that or..
im so gonna fail my exam but whatever
1 note · View note
sffc-xyz · 5 years
Text
Writing a Custom Camera Plugin for PhoneGap
Originally posted on January 3, 2014.
PhoneGap (the brand name of Apache Cordova) is a great tool for writing cross platform mobile applications. With JavaScript and rendering engines getting faster by the minute, we're quickly approaching the time when many apps can be written exclusively on the web platform without needing to dive into Objective-C and Java for iOS and Android.
Like all great things in life, though, PhoneGap has its limitations. For example, the abstraction away from Cocoa Touch means that the UI of your application is not automatically updated with new versions of iOS. But perhaps the most clearly defined limitation is the integration with native components. PhoneGap does a good job of abstracting things like contacts and the accelerometer, but it struggles with native components that require more than just an API.
In this blog post, I will dive into one of these native components: the camera. I will explain the limitations behind PhoneGap's out-of-the-box implementation of the camera, the steps you need to take to implement a custom camera overlay in iOS, and some tips and tricks along the way.
This tutorial applies to PhoneGap 3+. The plugin specification changed with the introduction of PhoneGap 3.0, so you will need a different tutorial if you intend to support older versions of PhoneGap.
I assume that you are competent in JavaScript and Objective-C, and that you are developing on a Mac with Xcode installed. Since the iOS simulator does not have a camera at the time of writing, you will also need a physical iOS device for testing. If at any time you get lost or your code doesn't work, you can refer to a working copy of CustomCamera on GitHub.
Let's get started!
The Default PhoneGap Camera
The default PhoneGap camera plugin has a clean JavaScript interface. From a developer's point of view, capturing a photo is as easy as one command:
$ phonegap local plugin add org.apache.cordova.camera
…followed by a few lines of code:
navigator.camera.getPicture(function(imagePath){ document.getElementById("photoImg").setAttribute("src", imagePath); }, function(){ alert("Photo cancelled"); }, { destinationType: navigator.camera.DestinationType.FILE_URI });
However, from the end user's point of view, things are not quite as slick. On iOS, a modal opens with the same camera overlay as the native UI. They can choose an image from their preexisting photo albums, or they can snap a new one. They are then brought to a screen where they can preview the photo and choose to retake it. Finally, when they submit the image, the modal closes and the JavaScript callback is evaluated.
This is fine for an app where the camera is not a core feature, but for apps where the user spends a significant amount of time taking photos, the default PhoneGap camera might not give a good user experience (UX).
Writing the PhoneGap Plugin
We can make a custom user experience by writing a PhoneGap plugin. The folks at Apache have improved the plugin API and its documentation substantially in the past few months, but there is still a definite learning curve.
I'm going to do my best to walk you through the process of creating a camera plugin for iOS.
Step 1: Create an empty PhoneGap project
The first thing we need to do is to create a new empty PhoneGap project and add iOS support. If you have the PhoneGap Command Line Interface installed, you just need to run:
# NOTE: Change com.example.custom-camera to something else unique to your organization. $ phonegap create custom_camera com.example.custom-camera CustomCamera $ cd custom_camera $ phonegap local build ios
The last line creates the iOS project directory at custom_camera/platforms/ios.
Step 2: Write the JavaScript bindings
It will make our lives easier if we write the JavaScript bindings for our plugin right up front. Make a new JavaScript file at custom_camera/www/js/custom_camera.js. Put in the following code:
var CustomCamera = { getPicture: function(success, failure){ cordova.exec(success, failure, "CustomCamera", "openCamera", []); } };
cordova.exec is an automagic function that lets us call an Objective-C method from JavaScript. In this case, it will create an instance of CustomCamera and call openCamera on that instance. We will write the CustomCamera class in Objective-C in the next step.
Notice how we made our API very close to PhoneGap's camera API. This is optional. At the end of the day everything boils down to cordova.exec.
Let's also create a button that we can tap to run the above function. Modify custom_camera/www/index.html and add the following inside the div.app tag:
<button id="openCustomCameraBtn">Open Custom Camera</button> <img id="photoImg" style="position: fixed; top: 0; width: 50%; left: 25%;" /> <script src="js/custom_camera.js"></script> <script> document.getElementById("openCustomCameraBtn").addEventListener("click", function(){ CustomCamera.getPicture(function(imagePath){ document.getElementById("photoImg").setAttribute("src", imagePath); }, function(){ alert("Photo cancelled"); }); }, false); </script>
Finally, don't forget to tell PhoneGap to copy the new files into our iOS project directory.
$ phonegap local build ios
Step 3: Set up the Xcode Project
If you run the above app on your iOS device, you will get an error telling you that the CustomCamera class is not defined. This is where we get to start diving into the Objective-C.
Open up the Xcode project located at custom_camera/platforms/ios/CustomCamera.xcodeproj. Press ⌘N, make a new Objective-C class for Cocoa Touch, name the class CustomCamera, and (this is important!) inherit from CDVPlugin. Save it in the Classes folder and the Classes group.
In the previous step, we told our JavaScript to call the openCamera method on an instance the CustomCamera class. We need to declare this method. Make your interface in CustomCamera.h look like this:
// Note that Xcode gets this line wrong. You need to change "Cordova.h" to "CDV.h" as shown below. #import <Cordova/CDV.h> // Import the CustomCameraViewController class #import "CustomCameraViewController.h" @interface CustomCamera : CDVPlugin // Cordova command method -(void) openCamera:(CDVInvokedUrlCommand*)command; // Create and override some properties and methods (these will be explained later) -(void) capturedImageWithPath:(NSString*)imagePath; @property (strong, nonatomic) CustomCameraViewController* overlay; @property (strong, nonatomic) CDVInvokedUrlCommand* latestCommand; @property (readwrite, assign) BOOL hasPendingOperation; @end
And wait, what the heck is CustomCameraViewController? It's the class that will handle the UI side of the plugin. Cordova will instantiate an instance of CustomCamera, which in turn will instantiate an instance of CustomCameraViewController as we will see later.
Press ⌘N again, make another new Objective-C class for Cocoa Touch, name it CustomCameraViewController, but this time inherit from UIViewController. I recommend creating a XIB file. Save it in the Classes folder.
The interface in CustomCameraViewController.h should look something like this:
#import <UIKit/UIKit.h> // We can't import the CustomCamera class because it would make a circular reference, so "fake" the existence of the class like this: @class CustomCamera; @interface CustomCameraViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> // Action method -(IBAction) takePhotoButtonPressed:(id)sender forEvent:(UIEvent*)event; // Declare some properties (to be explained soon) @property (strong, nonatomic) CustomCamera* plugin; @property (strong, nonatomic) UIImagePickerController* picker; @end
Now we need to make the button that, when tapped, calls the takePhotoButtonPressed method. To do this, open the XIB file with CustomCameraViewController.h still open, make a button on the screen, and Control-Drag the button from the XIB file onto the method in the header file.
Gotta say it's a decent GUI that Apple put together!
We also need to add code to custom_camera/platforms/ios/config.xml in order to make PhoneGap see our plugin. Add the following lines somewhere inside the widget tag:
<feature name="CustomCamera"> <param name="ios-package" value="CustomCamera" /> </feature>
With the header files and XIB out of the way, we need to dive into the guts of the Objective-C.
Step 4: Write the hard core Objective-C
The primary API for interacting with the camera in iOS is the UIImagePickerController. We will be instantiating an instance of UIImagePickerController, configuring it to fill the whole screen, and opening it as a modal in front of the web view. When UIPickerController tells us that an image has been captured, we will save it as a JPEG file, tell JavaScript the file name, and close the camera modal. While the details of UIImagePickerController are beyond the scope of this blog post, it should be relatively straightforward to follow along with the code.
Let's start by writing the implementation for our CustomCameraViewController class, in CustomCameraViewController.m. Please read along with the comments.
#import "CustomCamera.h" #import "CustomCameraViewController.h" @implementation CustomCameraViewController // Entry point method - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Instantiate the UIImagePickerController instance self.picker = [[UIImagePickerController alloc] init]; // Configure the UIImagePickerController instance self.picker.sourceType = UIImagePickerControllerSourceTypeCamera; self.picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; self.picker.cameraDevice = UIImagePickerControllerCameraDeviceRear; self.picker.showsCameraControls = NO; // Make us the delegate for the UIImagePickerController self.picker.delegate = self; // Set the frames to be full screen CGRect screenFrame = [[UIScreen mainScreen] bounds]; self.view.frame = screenFrame; self.picker.view.frame = screenFrame; // Set this VC's view as the overlay view for the UIImagePickerController self.picker.cameraOverlayView = self.view; } return self; } // Action method. This is like an event callback in JavaScript. -(IBAction) takePhotoButtonPressed:(id)sender forEvent:(UIEvent*)event { // Call the takePicture method on the UIImagePickerController to capture the image. [self.picker takePicture]; } // Delegate method. UIImagePickerController will call this method as soon as the image captured above is ready to be processed. This is also like an event callback in JavaScript. -(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { // Get a reference to the captured image UIImage* image = [info objectForKey:UIImagePickerControllerOriginalImage]; // Get a file path to save the JPEG NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* documentsDirectory = [paths objectAtIndex:0]; NSString* filename = @"test.jpg"; NSString* imagePath = [documentsDirectory stringByAppendingPathComponent:filename]; // Get the image data (blocking; around 1 second) NSData* imageData = UIImageJPEGRepresentation(image, 0.5); // Write the data to the file [imageData writeToFile:imagePath atomically:YES]; // Tell the plugin class that we're finished processing the image [self.plugin capturedImageWithPath:imagePath]; } @end
Now let's write the implementation for the CustomCamera class, in CustomCamera.m.
#import "CustomCamera.h" @implementation CustomCamera // Cordova command method -(void) openCamera:(CDVInvokedUrlCommand *)command { // Set the hasPendingOperation field to prevent the webview from crashing self.hasPendingOperation = YES; // Save the CDVInvokedUrlCommand as a property. We will need it later. self.latestCommand = command; // Make the overlay view controller. self.overlay = [[CustomCameraViewController alloc] initWithNibName:@"CustomCameraViewController" bundle:nil]; self.overlay.plugin = self; // Display the view. This will "slide up" a modal view from the bottom of the screen. [self.viewController presentViewController:self.overlay.picker animated:YES completion:nil]; } // Method called by the overlay when the image is ready to be sent back to the web view -(void) capturedImageWithPath:(NSString*)imagePath { [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:imagePath] callbackId:self.latestCommand.callbackId]; // Unset the self.hasPendingOperation property self.hasPendingOperation = NO; // Hide the picker view [self.viewController dismissModalViewControllerAnimated:YES]; } @end
Of special note is the hasPendingOperation property on the CDVPlugin. This is an undocumented property that, when true, prevents the web view from being released from memory (garbage collected) while the camera view is open. If the web view were to be released from memory, bad things would happen: the app would essentially restart when the camera view closed, and the image data would never reach JavaScript.
Step 5: Test drive
Phew, that was a lot of Objective-C! But does it work?
Hook up your iOS device to your computer. If you haven't yet set up a provisioning profile, do so now. (For more information on connecting your device to Xcode, ask Google.) Build and run the app on your device from within Xcode. Tap the button to open the camera, then tap the button to snap the photo. The camera overlay should close, and you should see your image within the WebView!
The UI could obviously use some improvement, but the guts of the plugin are all there now.
Bundling the PhoneGap Plugin
In a crunch, you could stop right here and write the rest of your PhoneGap code inside your CustomCamera project. But the better practice is to give our plugin some metadata that we can use to include it in whichever project we want with a click PhoneGap command.
Step 6: Write plugin.xml
The metadata for PhoneGap plugins is stored in plugin.xml at the root of the project directory. Make custom_camera/plugin.xml with the following markup. More detail can be found in the PhoneGap docs.
<?xml version="1.0" encoding="UTF-8"?> <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:rim="http://www.blackberry.com/ns/widgets" id="com.example.custom-camera" version="0.0.1"> <name>Shopeel Camera</name> <description>PhoneGap plugin to support a custom camera overlay</description> <author>Shane Carr and others</author> <info> This plugin was written with the tutorial found at: http://codrspace.com/vote539/writing-a-custom-camera-plugin-for-phonegap/ </info> <js-module src="www/js/custom_camera.js" name="CustomCamera"> <clobbers target="navigator.CustomCamera" /> </js-module> <engines> <engine name="cordova" version=">=3.1.0" /> </engines> <platform name="ios"> <!-- config file --> <config-file target="config.xml" parent="/*"> <feature name="CustomCamera"> <param name="ios-package" value="CustomCamera" /> </feature> </config-file> <!-- core CustomCamera header and source files --> <header-file src="platforms/ios/CustomCamera/Classes/CustomCamera.h" /> <header-file src="platforms/ios/CustomCamera/Classes/CustomCameraViewController.h" /> <source-file src="platforms/ios/CustomCamera/Classes/CustomCamera.m" /> <source-file src="platforms/ios/CustomCamera/Classes/CustomCameraViewController.m" /> <resource-file src="platforms/ios/CustomCamera/Classes/CustomCameraViewController.xib" /> </platform> </plugin>
Customize plugin.xml with your plugin details, file names, and so on.
Step 7: Specify the JavaScript binding
PhoneGap plugins treat the JavaScript file we made like a module. This means that custom_camera.js will be evaluated in a sandbox, and we need to specifically expose properties in order for us to use them.
Take note of the following lines in plugin.xml:
<js-module src="www/js/custom_camera.js" name="CustomCamera"> <clobbers target="navigator.CustomCamera" /> </js-module>
What this means in English is "include custom_camera.js and bind its module.exports to navigator.CustomCamera". If you've used Node.JS, you are probably familiar with module.exports. All we need to do is to add the following line to the bottom of custom_camera.js:
module.exports = CustomCamera;
Now, in applications in which we include our plugin, we can open the custom camera view with navigator.CustomCamera.getPicture().
Step 8: Deploy the plugin
We are finally ready to include our plugin in our real PhoneGap project!
Installing the default PhoneGap camera was as easy as:
$ phonegap local plugin add org.apache.cordova.camera
Guess what: our own custom camera plugin ain't much harder to install!
$ phonegap local plugin add /path/to/custom_camera
You can also give phonegap local plugin add a path to your Git repo.
$ phonegap local plugin add https://github.com/vote539/custom-camera.git
Conclusion
We now have a very basic, working PhoneGap plugin for iOS!
The next steps would include:
Add support for Android, Blackberry, Windows Phone, and all other targeted platforms. You would first need to add said platform to your PhoneGap project, then you would need to refer to the documentation for PhoneGap and your desired platform about how to implement a camera. Don't forget to modify plugin.xml once you're ready!
Package your plugin for the community. This might be as easy as plugman publish /path/to/custom_camera. Before you do this, make sure that you use a real reverse URL identifier for your plugin, rather than com.example.xyz.
If this tutorial helped you, let me know by posting a comment below!
0 notes