TweetFollow Us on Twitter

Terminal Velocity

Volume Number: 21 (2005)
Issue Number: 2
Column Tag: Programming

QuickTime Toolkit

by Tim Monroe

Terminal Velocity

Developing Command-Line QuickTime Tools, Part II

In the previous article ("The Terminal" in MacTech December 2004), we looked at using command-line tools to accomplish various QuickTime-related tasks, such as building movies from a series of still images or applying visual effects to an existing movie. We focused on building tools on Mac OS X, either using Xcode or just directly compiling and linking with cc on the command line. In this article, I want to continue that investigation by stepping through the process of building a command-line tool on Windows. The fundamental ideas are the same as on the Macintosh, but when moving to a different platform, it's always useful to see a step-by-step walkthrough. Then, toward the middle of this article, we'll return to Mac OS X to look at a clever way to actually draw video data on the screen using a command-line tool.

DOS Command-Line Tools

For our Windows command-line tool, let's build a C-language version of the Tcl listComps script we considered in the previous article. Figure 1 shows the C version of listComps at work in a DOS console window. We are asking it to list all available graphics exporters (that is, components of type 'grex').


Figure 1: Output of listComps on Windows

Creating a Project

Launch the Visual C++ development environment. Select "New..." in the File menu to get a list of available project types. In the Projects pane, select "Win32 Console Application". Set the project name and select a more convenient location for the project files (Figure 2)


Figure 2: The new project dialog box

Because there are several flavors of console applications, we'll be prompted to select one, as in Figure 3. Choose "A "Hello, World!" application".


Figure 3: The console application wizard

At this point, the project window appears; the Workspace pane shows the files associated with the new project (Figure 4).


Figure 4: The listComps Workspace pane

Setting Project Paths

Our Windows command-line tool will not actually call any QuickTime-specific APIs, since it can do all its work using the Component Manager functions FindNextComponent and GetComponentInfo. Nevertheless, we need to link against the library qtmlclient.lib, because the QuickTime Media Layer (QTML) supplies the Component Manager implementation on Windows. So let's select the Settings menu item in the Project menu and choose the Link tab. In the "Object/library modules" text box, add qtmlclient.lib, as shown in Figure 5.


Figure 5: The Link tab

We also need to specify the path to the directory that contains the file qtmlclient.lib, since it's probably not in the default library paths. In the Category pop-up menu, select Input and add a full or relative path to that directory. As you can see in Figure 6, I've specified a relative path from the directory containing the listComps project file to the directory that contains the QTML libraries on my machine.


Figure 6: The Input pane of the Link tab

Handling Command-Line Options

As you know, we want to be able to specify one or more component types on the command line, to limit the displayed components to the specified type or types. In our Mac OS X tools, we used the system call getopt to process options specified on the command line. The getopt function is not part of the standard Windows APIs, but there are implementations available that work well on Windows. Indeed, some of the Microsoft Developer Network (MSDN) sample code includes the files getopt.c and getopt.h, which we can copy directly into our project. We can then call the getopt function as shown in Listing 1.

Listing 1: Handling command-line options

main
while ((myChar = getopt(argc, argv, "e:")) != -1) {
   switch (myChar) {
      case 'e':
         string2ostype(optarg, &myType);
         break;
   }
}	

argc -= optind;
argv += optind;

You may recall that in the previous article we provided a quick and dirty version of the string2ostype function. Let's take a moment to look at a better version. The principal flaw with the original version was that it assumed that all strings specified on the command line would be exactly four characters in length. While most publicly defined values of type OSType are indeed exactly four characters in length, not all are. Listing 2 provides a better implementation that handles strings of any length that is less than or equal to 4.

Listing 2: Converting a string into an OSType

string2ostype
void string2ostype (const char *inString, OSType *outType)
{
   OSType      type = 0;
   short       i;	

   for (i = 0; i < 4; i++) {
      type <<= 8;
      if (*inString) {
         type += (unsigned char)(*inString);
         inString++;
      }
   }

   *outType = type;
}

Note that it's perfectly legal for the string passed in to contain spaces, so our code can handle strings like "eat " (the component subtype of movie importers). The only restriction is that strings containing spaces need to be quoted on the command line, like this:

listComps -e "eat "

The listComps tool also needs to implement an ostype2string function, so that it can display the type, subtype, and manufacturer of any found component in a readable form. Listing 3 shows a version of ostype2string.

Listing 3: Converting an OSType into a string

ostype2string
static void ostype2string (OSType inType, char *outString)
{
   unsigned char   theChars[4];
   unsigned char *theString = (unsigned char *)outString;
   unsigned char *theCharPtr = theChars;
   int                       i;

   // extract four characters in big-endian order
   theChars[0] = 0xff & (inType >> 24);
   theChars[1] = 0xff & (inType >> 16);
   theChars[2] = 0xff & (inType >> 8);
   theChars[3] = 0xff & (inType);

   for (i = 0; i < 4; i++) {
      if((*theCharPtr >= ' ') && (*theCharPtr <= 126)) {
         *theString++ = *theCharPtr;
      } else {
         *theString++ = ' ';
      }

      theCharPtr++;
   }

   *theString = 0;
}

You'll notice that any unprintable characters (that is, characters with ASCII values less than 32 or greater than 126) are replaced by a space character. For our present purposes, that's quite acceptable. For other purposes, however, it might be better to encode unprintable characters in some way so that their values are easily discernible. This refinement is left as an exercise for the reader.

Finding Components

Looping through all installed components to find those with a specific component type is really easy. All we need to do is use the functions FindNextComponent and GetComponentInfo, as shown in Listing 4. Notice that we call InitializeQTML with a set of flags appropriate for command-line tools, and that we later call TerminateQTML.

Listing 4: Listing installed components

main
int main (int argc, char* argv[])
{
   char            myType[5];
   char            mySubType[5];
   char            myManu[5];
   char            myChar;
   OSType          myType = 0L;

   ComponentDescription findCD = {0, 0, 0, 0, 0};
   ComponentDescription infoCD = {0, 0, 0, 0, 0};
   Component comp = NULL;

   // process command-line options
   while ((myChar = getopt(argc, argv, "e:")) != -1) {
      switch (myChar) {
         case 'e':
            string2ostype(optarg, &myType);
            break;
      }
   }	
	
   argc -= optind;
   argv += optind;

	
#if !TARGET_OS_MAC
   InitializeQTML(kInitializeQTMLNoSoundFlag | 
                                    kInitializeQTMLUseGDIFlag);
#endif	

   findCD.componentType = myType;
   findCD.componentFlagsMask = cmpIsMissing;

   while (comp = FindNextComponent(comp, &findCD)) {
      GetComponentInfo(comp, &infoCD, NULL, NULL, NULL);

      ostype2string(infoCD.componentType, myType);
      ostype2string(infoCD.componentSubType, mySubType);
      ostype2string(infoCD.componentManufacturer, myManu);

      printf("  %s\t%s\t%s\n", myType, mySubType, myManu);
   }

#if !TARGET_OS_MAC
   TerminateQTML();
#endif	
   return 0;
}

This implementation does not support more than one -e option on the command line; removing that restriction is also left as an exercise for the reader.

MOVIE PLAYBACK IN THE TERMINAL

In the previous article, I mentioned that command-line tools are well-suited to handle tasks that do not require visual movie data to be displayed to the user. Command-line tools can play audio just fine, and (as we've seen) they can create and modify QuickTime movies in virtually any way imaginable. They just can't display any video data on the screen.

Or can they? Consider our standard penguin movie, the last frame of which is shown once again in Figure 7. If we are very clever, we can write a command-line tool that displays the movie in a Terminal window, as in Figure 8. As you can see, the image is composed of ASCII characters. All we need to do is draw an image like this, erase the Terminal window, draw another image, and so forth. So, if we can do this erasing and drawing fast enough, and if we are willing to live with images composed entirely of ASCII characters (or whatever else can be displayed in a Terminal window), we can indeed play QuickTime video using a command-line tool.


Figure 7: A movie playing in an application window


Figure 8: A movie playing in a Terminal window

How is this done? It's actually surprisingly simple. I'll step through the details in a moment, but in overview the process is this: open a QuickTime movie and set it to draw to an offscreen graphics world. Play the movie by calling MCIdle until the movie is done. Each time a frame is drawn into the offscreen graphics world, inspect each pixel that lies on an intersection of two lines in a w x h grid, where w and h are the width and height of the Terminal window. Convert the RGB value of that pixel to a relative lightness value (called the luminance of the pixel) and map that luminance value to one of these 23 characters: " .,:!-+=;iot76x0s&8%#@$". Draw the character at the appropriate location on the Terminal window. Voila: Terminal-based movie playback.

Opening and Running the Movie

The first part of this process is easy. We already know how to open a QuickTime movie file and load the movie from the file. Then we need to create an offscreen graphics world and set the movie to draw into it, as shown in Listing 5.

Listing 5: Setting up to draw

main
Rect            myBounds;
GWorldPtr       myGW = NULL;

GetMovieBox(myMovie, &myBounds);
QTNewGWorld(&myGW, k32ARGBPixelFormat, &myBounds, NULL, 
                            NULL, 0);
if (myGW != NULL) {
   LockPixels(GetGWorldPixMap(myGW));
   SetGWorld(myGW, NULL);
   myMC = NewMovieController(myMovie, &myBounds,
                             mcTopLeftMovie | mcNotVisible);
   SetMovieGWorld(myMovie, myGW, NULL);
   SetMovieActive(myMovie, true);
}

Notice that we create a new movie controller with the controller bar hidden.

Once this is all accomplished, we can start the movie playing, like this:

MCDoAction(myMC, mcActionPrerollAndPlay, (void *)fixed1);

And we can run the movie by continually calling MCIdle:

do {
   MCIdle(myMC);
} while (1);

Remember, though, that we want to do some work each time a frame is drawn into the offscreen graphics world, so we'll also install a movie drawing-completion procedure:

SetMovieDrawingCompleteProc(myMovie, 
                    movieDrawingCallWhenChanged, 
                    DrawCompleteProc, (long)myGW); 

This drawing-completion procedure DrawCompleteProc will be responsible for looking at the appropriate pixels in the offscreen graphics world, converting them into characters, and drawing the characters into the Terminal window. (For more information about movie drawing-completion procedures, see "Loaded" in MacTech, September 2002.)

Converting Pixels to Luminance Values

The pixels in the offscreen graphics world contain RGB data. What we want to do is convert an RGB value into a luminance value, which is a measure of the lightness of the RGB value. Figure 9 shows the luminance color space. (Exciting, huh?)


Figure 9: The luminance color space

The standard formula for converting an RGB value into a luminance value is this:

Y = (0.30 x R) + (0.59 x G) + (0.11 x B)
In our command-line tool, we'll approximate this value, for a given pixel color, with this code:
   R = (color & 0x00FF0000) >> 16;
   G = (color & 0x0000FF00) >> 8;
   B = (color & 0x000000FF) >> 0;
   Y = (R + (R << 2) + G + (G << 3) + (B + B)) >> 4;

The luminance values generated in this way will range from 0 to 255, where 0 is black and 255 is white.

Converting Luminance Values to Characters

In order to be able to draw in a Terminal window, we need to convert these luminance values into ASCII characters. The list of characters given earlier is ranked roughly in order of lightness, with characters to the left being lighter than those to the right:

 " .,:!-+=;iot76x0s&8%#@$". 

The code in Listing 6 loads an array with these characters.

Listing 6: Loading a conversion array

main
char convert[256];
char *table = "   .,:!-+=;iot76x0s&8%#@$";

for (i = 0; i < 256; ++i) {
   convert[i] = table[i * strlen(table) / 256];
}

For instance, luminance values in the range 195 to 204 are mapped to the ampersand "&". (Notice that the first three characters in the table string are the space character, so that any luminance value less than or equal to 30 is mapped to the space character.)

Drawing Characters

All that remains is to see how to traverse the offscreen graphics world to grab pixels and draw the associated character into the Terminal window. A couple of for loops will do the trick, as shown in Listing 7.

Listing 7: Drawing characters

DrawCompleteProc
static pascal OSErr DrawCompleteProc 
                        (Movie theMovie, long theRefCon)
{
#define WIDTH   ((float)(80))
#define HEIGHT   ((float)(24))

   int                y, x;
   GWorldPtr          myGW = (GWorldPtr)theRefCon;
   Rect               myBounds;
   Ptr                baseAddr;
   long               rowBytes;

   // get the information we need from the GWorld
   GetPixBounds(GetGWorldPixMap(myGW), &myBounds);
   baseAddr = GetPixBaseAddr(GetGWorldPixMap(myGW));
   rowBytes = GetPixRowBytes(GetGWorldPixMap(myGW));

   // go to home position
   printf("%c[0;0H", ESC);

   // for each row
   for (y = 0; y < HEIGHT; ++y) {
      long   *p;

      // for each column
      p = (long*)(baseAddr + rowBytes * 
               (long)(y * ((myBounds.bottom - myBounds.top) / 
               HEIGHT)));
      for (x = 0; x < WIDTH; ++x) {
         UInt32      color;
         long        Y, R, G, B;

         color = *(long *)((long)p + 4 * 
               (long)(x * (myBounds.right - myBounds.left) / 
               WIDTH));
         R = (color & 0x00FF0000) >> 16;
         G = (color & 0x0000FF00) >> 8;
         B = (color & 0x000000FF) >> 0;

         // convert to luminace
         Y = (R + (R << 2) + G + (G << 3) + (B + B)) >> 4;
	
         // draw it
         putchar(convert[255 - Y]);
      }

      // next line
      putchar('\n');
   }

   return noErr;
}

Notice that the cursor is moved to the home position on the Terminal window (that is, the location at the top-left of the window) at the beginning of the callback procedure with this line of code:

printf("%c[0;0H", ESC);

By default, the Terminal application emulates a terminal of type xterm-color, which supports a superset of the standard vt100 escape codes. To move the cursor to the home position, therefore, we can send the sequence of characters Esc-[-0-;-0-H, where "Escape" is the ASCII value of the Escape key:

#define ESC   27

Similarly, when our tool first starts up, we want to erase the screen; we can do that like this:

printf("%c[0J", ESC);

MOVIE PLAYBACK IN THE DOS CONSOLE

So, we've seen how to build a command-line tool for Windows and how to "draw" movies inside a Terminal window on Mac OS X. We might naturally wonder whether we can combine these two accomplishments to do the same sort of movie drawing in the DOS console window. Indeed this is possible, but moving this code from Mac OS X to Windows is not without complications. The main problem here is that the DOS console window does not support the vt100 escape codes that we rely upon to move the cursor around the window and to clear the window. Happily, Window provides a set of functions that so-called character-mode applications can use to control the cursor position and other characteristics of a console window. Once we move to those functions, it's straightforward to generate movie frames like the one shown in Figure 10.

Adjusting Header Files and Function Calls

First things first, however. We need to do a little work to make our code suitably cross-platform. The existing Mac OS X code includes only two header files:

#include <stdio.h>
#include <QuickTime/QuickTime.h>
We need to adjust that so that the appropriate files are included on each platform, like this: 
#include <stdio.h>
#if TARGET_OS_MAC
#include <QuickTime/QuickTime.h>
#else
#include <windows.h>
#include <QTML.h>
#include <Movies.h>
#include <Quickdraw.h>
#include <QDOffscreen.h>
#include <string.h>
#include <FixMath.h>
#endif


Figure 10: A movie playing in a DOS console window

If we try to compile and link our tool at this point, we'll discover that the GetPixBounds, GetPixBaseAddr, and GetPixRowBytes functions are not currently available on Windows. We can work around that limitation by directly accessing the fields of a PixMap structure, as shown in Listing 8.

Listing 8: Getting the offscreen graphics world information

DrawCompleteProc
#if TARGET_OS_MAC
GetPixBounds(GetGWorldPixMap(offWorld), &bounds);
baseAddr = GetPixBaseAddr(GetGWorldPixMap(offWorld));
rowBytes = GetPixRowBytes(GetGWorldPixMap(offWorld));
#else
bounds = (**GetGWorldPixMap(offWorld)).bounds;
baseAddr = (**GetGWorldPixMap(offWorld)).baseAddr;
rowBytes = (**GetGWorldPixMap(offWorld)).rowBytes & 0x3fff;
#endif

Note the addition of the value 0x3fff to the value of the rowBytes field. It turns out that the two high-order bits of that field are used for other purposes, so we need to mask them off if we read it directly.

Finally, of course, we need to make sure to call InitializeQTML before we call EnterMovies and then call TerminateQTML once we are done drawing movie frames.

Controlling the Cursor

As I mentioned earlier, the DOS console window does not support the vt100 escape sequences that we use to clear the window and position the cursor when running in a Terminal window on Mac OS X. Fortunately, we can make use of a set of console functions supported by Windows for managing input and output in character-mode applications -- that is, an application that reads from the standard input and writes to the standard output or to the standard error. For present purposes, we need to be concerned only with writing characters to the standard output, which we can access using a HANDLE value:

HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

We can, for instance, move the cursor to a specified position by calling the SetConsoleCursorPosition function like this:

SetConsoleCursorPosition(hStdOut, coord);

The coord parameter is a value of type COORD that specifies the desired location of the cursor.

Listing 9 defines a function that we can call from either Windows code or Mac OS X code to move the cursor to a screen location.

Listing 9: Setting the position of the cursor

MoveCursor
void MoveCursor (int x, int y)
{
#ifdef TARGET_OS_WIN32
   COORD coord;

   coord.X = x;
   coord.Y = y;
   SetConsoleCursorPosition(hStdOut, coord);
#else
   fprintf(stdout, "%c[%i;%iH", ESC, y, x);
#endif
}

And Listing 10 defines a function that we can call to clear the console screen. On Windows, it simply fills the entire console screen with space characters.

Listing 10: Clearing the screen

ClearScreen
void ClearScreen (void)
{
#ifdef TARGET_OS_WIN32
   COORD coord = {0, 0};
   DWORD count;
   CONSOLE_SCREEN_BUFFER_INFO csbi;

   GetConsoleScreenBufferInfo(hStdOut, &csbi);
   FillConsoleOutputCharacter(hStdOut, ' ', 
                      csbi.dwSize.X * csbi.dwSize.Y, coord, &count);

   SetConsoleCursorPosition(hStdOut, coord);
#else
   fprintf(stdout, "%c[2J", ESC);
#endif
}

Once we revise the existing code to use MoveCursor and ClearScreen, we're done.

CONCLUSION

Command-line tools are powerful, easy to write, and can provide several advantages over GUI-based applications, even when working with multimedia technologies like QuickTime. In this article and the previous one, we've learned how to build QuickTime command-line tools on both Mac OS X and on Windows. We've also taken a look at a very clever way to display the visual output of a movie inside a Terminal window or a DOS console window.

REFERENCES

The ASCIIMoviePlayer command-line tool for drawing movies using ASCII characters was written by Tom Dowdy and is available at http://developer.apple.com/samplecode/QuickTime/idxMovieBasics-date.html. An enhanced version of this project (which, among other things, adds support for color characters) can be found at http://quickascii.sourceforge.net. The Windows adaptation is my own contribution to this crazy but intriguing tool.

Another useful collection of command-line tools for QuickTime processing is qt_tools by David Van Brink; the tools and their complete source code are available at http://www.omino.com/~poly/software/qt_tools.


Tim Monroe is a member of the QuickTime engineering team at Apple. You can contact him at monroe@mactech.com. The views expressed here are not necessarily shared by his employer.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

TunnelBear 3.0.1 - Subscription-based pr...
TunnelBear is a subscription-based virtual private network (VPN) service and companion app, enabling you to browse the internet privately and securely. Features Browse privately - Secure your data... Read more
ExpanDrive 5.4.0 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
Opera 40.0.2308.62 - High-performance We...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more
Apple iOS 10.0.2 - The latest version of...
iOS 10 is the biggest release of iOS ever. A massive update to Messages brings the power of the App Store to your conversations and makes messaging more personal than ever. Find your route with... Read more
Herald 7.0 - Notification plugin for Mai...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), 4.0.8 (for OS X 10.9), 5.0.2 (for OS X 10.10), and 6.0.3 (for OS X 10.11) are no longer supported by the developer. Herald is a... Read more
Postbox 5.0.2 - Powerful and flexible em...
Postbox is a new email application that helps you organize your work life and get stuff done. It has all the elegance and simplicity of Apple Mail, but with more power and flexibility to manage even... Read more
Yummy FTP Pro 1.11.10 - $29.99
Yummy FTP Pro is an advanced Mac file transfer app which provides a full-featured professional toolkit combined with blazing speeds and impeccable reliability, so whether you want to transfer a few... Read more
Tidy Up 4.1.17 - $29.99
Tidy Up is a full-featured duplicate finder and disk-tidiness utility. Features With Tidy Up you can search for duplicate files and packages by the owner application, content, type, creator,... Read more
Logitech Control Center 3.9.5 - Keyboard...
Logitech Control Center (LCC) is designed to support OS X and allows you to take full advantage of your Logitech keyboard, mouse, or trackball. With the LCC you can: Browse the Internet using... Read more
Macgo Blu-ray Player 2.16.17 - Blu-ray p...
Macgo Blu-ray Player can bring you the most unforgettable Blu-ray experience on your Mac. Overview Macgo Mac Blu-ray Player can satisfy just about every need you could possibly have in a Blu-ray... Read more

How to build and care for your team in D...
Before you hit the trail and become a dog sledding legend, there’s actually a fair bit of prep work to be done. In Dog Sled Saga, you’re not only racing, you’re also building and caring for a team of furry friends. There’s a lot to consider—... | Read more »
How to win every race in Dog Sled Saga
If I had to guess, I’d say Dog Sled Saga is the most adorable racing game on the App Store right now. It’s a dog sled racing sim full of adorable, loyal puppies. Just look at those fluffy little tails wagging. Behind that cute, pixelated facade is... | Read more »
Let the war games commence in Gunship Ba...
Buzz Lightyear famously said, “This isn’t flying, this is falling – with style!” In the case of Gunship Battle: Second War, though, this really is flying - with style! The flight simulator app from Joycity puts you in control of 20 faithfully... | Read more »
How to get a high score in Fired Up
Fired Up is Noodlecake Games’ high score chasing, firefighting adventure. You take control of a wayward firefighter who propels himself up the side of a highrise with blasts of water. Sound silly? It is. It’s also pretty difficult. You can’t... | Read more »
NBA 2K17 (Games)
NBA 2K17 1.0 Device: iOS iPhone Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: Following the record-breaking launch of NBA 2K16, the NBA 2K franchise continues to stake its claim as the most authentic sports video... | Read more »
Dog Sled Saga (Games)
Dog Sled Saga 1.0.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.1 (iTunes) Description: A game by Dan + Lisa As a rookie musher, foster a dogsledding team whose skills will grow if they're treated right. Week by... | Read more »
60 Seconds! Atomic Adventure (Games)
60 Seconds! Atomic Adventure 1.2 Device: iOS Universal Category: Games Price: $2.99, Version: 1.2 (iTunes) Description: 60 Seconds! is a dark comedy atomic adventure of scavenge and survival. Collect supplies and rescue your family... | Read more »
Tons of Bullets! (Games)
Tons of Bullets! 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Tons of BulletsA retro 2D pixel platformer infused with tons of bullets and tons of features!Fight as Kenji the Ninja and... | Read more »
Sorcery! 4 (Games)
Sorcery! 4 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: *** PLEASE NOTE: Sorcery! 4 requires a minimum of iPad 3 or iPhone 4 *** An epic adventure through a cursed citadel of monsters,... | Read more »
Building the perfect Animation Throwdown...
Animation Throwdown is a casual card game full of plenty of inside jokes from some of your favorite cartoons. It’s accessible as far as card games go, but that’s not to say that it hands your victories to you easily. There’s quite a bit that goes... | Read more »

Price Scanner via MacPrices.net

Duplicate Sweeper Free On Mac App Store For O...
To celebrate the launch of Apple’s latest macOS Sierra, Stafford, United Kingdom based Wide Angle Software has announced that its duplicate file finder software, Duplicate Sweeper, is now available... Read more
13-inch Retina MacBook Pros on sale for up to...
B&H Photo has 13″ Retina Apple MacBook Pros on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY tax only: - 13″ 2.7GHz/128GB Retina MacBook Pro: $1174.99 $125 off MSRP - 13... Read more
Evidence Surfaces Pointing To New A10X Chip F...
Citing a job description for a Project Lead position at Apple’s Austin, Texas engineering labs, Motley Fool’s Ashraf Eassa deduces that development is progressing well on Apple’s next-generation in-... Read more
Check Print’R for macOS Allows Anyone to Easi...
Delaware-based Match Software has announced the release and immediate availability of Check Print’R 3.21, an important update to their easy-to-use check printing application for macOS. Check Print’R... Read more
Apple refurbished 11-inch MacBook Airs availa...
Apple has Certified Refurbished 11″ MacBook Airs (the latest models), available for up to $170 off the cost of new models. An Apple one-year warranty is included with each MacBook, and shipping is... Read more
Apple refurbished 15-inch Retina MacBook Pros...
Apple has Certified Refurbished 2015 15″ Retina MacBook Pros available for up to $380 off the cost of new models. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2... Read more
Major Version 5 Release Of Free myTuner Radio...
AppGeneration Software has announced the release of myTuner Radio 5.0.1, an important update to their live radio app for iOS and Android platforms. With myTuner Radio, you can listen to more than 30,... Read more
TheAppStore Searches And Filters iOS And macO...
Boston based InchWest has announced the official launch of TheAppStore, a free web based service that lets users search iOS and Mac apps on the web without iTunes or the App store. TheAppStore... Read more
2TB Time Capsule on sale for $199, save $100
Amazon has 2TB Apple Time Capsules on sale for $199 including free shipping. Their price is $100 off MSRP. Choose Amazon as the seller when making your purchase, rather than a third party seller. Read more
12-inch 1.2GHz Rose Gold Retina MacBook on sa...
Amazon.com has the 2016 12″ 1.2GHz Rose Gold Retina MacBook on sale for $1254.02 including free shipping. Their price is $345 off MSRP, and it’s the lowest price available for this model from any... Read more

Jobs Board

Senior *Apple* Administrator - Pratt Instit...
POSITION SUMMARY: Directs the coordination and standardization of campus-wide Apple systems, including planning, analysis and implementation of Apple -related Read more
Restaurant Manager (Neighborhood Captain) - A...
…in every aspect of daily operation. WHY YOU'LL LIKE IT: You'll be the Big Apple . You'll solve problems. You'll get to show your ability to handle the stress and Read more
*Apple* Retail - Multiple Positions- Napervi...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
US- *Apple* Store Leader Program - Apple (Un...
…Summary Learn and grow as you explore the art of leadership at the Apple Store. You'll master our retail business inside and out through training, hands-on Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.