TweetFollow Us on Twitter

Apr 99 Tips

Volume Number: 15 (1999)
Issue Number: 4
Column Tag: Tips & Tidbits

Apr 99 Tips

by Jeff Clites <online@mactech.com>

PixMap Rotation

CopyBits is one of the most powerful and ubiquitous of the Mac OS toolbox calls. It can scale, convert colors, and mask in a variety of ways. About the only thing it can't do is rotate an image. Similarly, we all know how to use DrawString to put text on the screen - but when we need to draw rotated text (say, for labeling a graph), we find no toolbox call up to the task. The routines below serve both needs.

RotatePixMap takes pointers to two PixMaps, and rotates the first into the second, rotating through a specified number of degrees (counter-clockwise). DrawRotatedString uses RotatePixMap to draw a string rotated to any angle, and then moves the graphics cursor accordingly. It also illustrates how to create a pair of pixel maps, draw into one, rotate into the other, and copy to the screen; a similar technique was used to rotate Clarus the dogcow in the figure below.

The code here only rotates pixel maps with 8-bit color depth or higher; it will return -1 if given a 1-bit image. It uses GWorlds, so requires at least System 7, but will work on both 68k and PowerPC machines. These functions form a valuable addition to the standard toolbox.

#include <Errors.h>
#include <fp.h>
#include "Rotate.h"

static void GetTrigs(float degrees, double_t *sinang, 
   double_t *cosang)
{
   // compute sine and cosine of the angle given in degrees;
   // check for special cases to avoid any rounding error
   if (degrees == 0) {
      *sinang = 0; *cosang = 1;
   } else if (degrees == 90 || degrees == -270) {
      *sinang = -1; *cosang = 0;
   } else if (degrees == 180 || degrees == -180) {
      *sinang = 0; *cosang = -1;
   } else if (degrees == 270 || degrees == -90) {
      *sinang = 1; *cosang = 0;
   } else {
      double_t radians = -degrees * pi / 180.0;
      *cosang = cos(radians);
      *sinang = sin(radians);
   }
}

OSErr RotatePixMap(PixMapPtr srcPm,
                                  PixMapPtr destPm,
   float degrees)
{
   double_t          cosang, sinang;
   short                x,y,x2,y2,i;
   char                *srcbyte, *destbyte;
   short                pixsize = srcPm->pixelSize / 8;
   unsigned char    blankByte = pixsize == 1 ? 0 : 255;

   short srcRowBytes = srcPm->rowBytes & 0x7FFF;
   short destRowBytes = destPm->rowBytes
                                           & 0x7FFF;

   short srcwidth = srcPm->bounds.right
                                           - srcPm->bounds.left,
      destwidth = destPm->bounds.right
                                           - destPm->bounds.left,
      srcheight = srcPm->bounds.bottom
                                           - srcPm->bounds.top,
      destheight = destPm->bounds.bottom
                                           - destPm->bounds.top;

   short srcCx = srcwidth/2,
                                           srcCy = srcheight/2;
   short destCx = destwidth/2,
                                           destCy = destheight/2;

   if (destPm->pixelSize/8
                                  != pixsize || pixsize < 1)
      return -1;   // requires 8 bit pixmap or higher
   
   GetTrigs(degrees, &sinang, &cosang);
   
   // loop over each element in dest, copying from source or          // setting to white
   for (y=0; y<destheight; y++) {
      destbyte = destPm->baseAddr +       y*destRowBytes;
      for (x=0; x<destwidth; x++) {
         x2 = srcCx + cosang*(x-destCx) +    sinang*(y-destCy);
         y2 = srcCy + cosang*(y-destCy) -    sinang*(x-destCx);
         if (x2 >= 0 && x2 < srcwidth
          && y2 >= 0 && y2 < srcheight) {
            srcbyte = srcPm->baseAddr +   y2*srcRowBytes
                  + x2*pixsize;
            for (i=0; i<pixsize; i++) {
               *destbyte++ = *srcbyte++;   // copy color
            }
         } else {
            for (i=0; i<pixsize; i++) {
               *destbyte++ = blankByte;   // fill in blank
            }
         }
      }
   }

   return noErr;
}


OSErr DrawRotatedString(Str255 s, float degrees)
{
   FontInfo   fi;
   short            cheight, cwidth, bufsize;
   Rect               srcR, destR, screenR;
   GWorldPtr      srcGW, destGW;
   PixMapHandle   srcPmH, destPmH;
   PixMapPtr      srcPm, destPm;
   CGrafPtr         origPort;
   GDHandle         origDevice;
   OSErr            err=noErr;
   double_t         cosang, sinang;

   // find the string size
   GetFontInfo( &fi );
   cheight = fi.ascent + fi.descent +   fi.leading;
   cwidth = StringWidth(s);
   
   // set buffer size (allow room for rotation)
   bufsize = (cheight > cwidth ?
                                        cheight*2 : cwidth*2);
   
   // create an offscreen GWorld in which to draw the string,
   // and another in which to draw the rotated version
   SetRect( &srcR, 0, 0, bufsize, cheight*2 );
   err = NewGWorld( &srcGW, 0, &srcR,
                                        NULL, NULL, 0 );
   if (err) return err;

   SetRect( &destR, 0, 0, bufsize, bufsize );
   err = NewGWorld( &destGW, 0, &destR,
                                        NULL, NULL, 0 );
   if (err) { DisposeGWorld( srcGW ); return err; }

   srcPmH = GetGWorldPixMap( srcGW );
   LockPixels( srcPmH );
   srcPm = *srcPmH;

   destPmH = GetGWorldPixMap( destGW );
   LockPixels( destPmH );
   destPm = *destPmH;

   // store original port, and draw string to source GWorld
   GetGWorld( &origPort, &origDevice );

   SetGWorld( srcGW, NULL );
   TextFont( origPort->txFont );
   TextSize( origPort->txSize );
   TextFace( origPort->txFace );
   EraseRect( &srcR );
   MoveTo( bufsize/2, cheight );
   DrawString( s );

   // rotate into the dest buffer
   RotatePixMap( srcPm, destPm, degrees );

   // copy to screen in OR mode, to avoid clobbering background
   SetGWorld( origPort, origDevice );
   SetRect( &screenR, 0, 0, bufsize, bufsize );
   OffsetRect( &screenR, 
                           origPort->pnLoc.h - bufsize/2,
         origPort->pnLoc.v - bufsize/2 );
   CopyBits((BitMap*)destPm,
                        (BitMap*)(*origPort->portPixMap),
         &destR, &screenR, srcOr, NULL );
   
   // release memory
   UnlockPixels( srcPmH );
   DisposeGWorld( srcGW );
   
   UnlockPixels( destPmH );
   DisposeGWorld( destGW );
   
   // finally, move the pen by the proper amount and direction
   GetTrigs(degrees, &sinang, &cosang);
   Move(cosang*cwidth + 0.5, sinang*cwidth+0.5);
   return err;
}


Figure 1. Clarus the dogcow is rotated through 30 degrees using RotatePixMap. DrawRotatedString is used to surround him with moofs.

Joseph J. Strout <joe@strout.net>

You can download a demo of this Tip from ftp://ftp.mactech.com/src.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Typinator 8.0 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more
Typinator Family Pack (5 licenses) 8.0 -...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more
Adobe After Effects CC 2018 16.1.2 - Cre...
After Effects CC 2018 is available as part of Adobe Creative Cloud for $52.99/month (or $20.99/month for a single app license). The new, more connected After Effects CC 2018 can make the impossible... Read more
Daylite 6.7 - Dynamic business organizat...
Daylite helps businesses organize themselves with tools such as shared calendars, contacts, tasks, projects, notes, and more. Enable easy collaboration with features such as task and project... Read more
Notion 1.0.6 - A unified workspace for m...
Notion is the unified workspace for modern teams. Notion Features: Integration with Slack Documents Wikis Tasks Note: This application contains in-app and/or external module purchases. Version 1.0... Read more
CorelDRAW 2019.2 - Graphic design softwa...
CorelDRAW - professional graphic design software for vector illustration, layout, and so much more. Get started quickly and easily with a wealth of intuitive tools, built-in learning materials,... Read more
Affinity Photo 1.7.1 - Digital editing f...
Affinity Photo - redefines the boundaries for professional photo editing software for the Mac. With a meticulous focus on workflow it offers sophisticated tools for enhancing, editing and retouching... Read more
GIMP 2.10.12 - Powerful, free image edit...
GIMP is a multi-platform photo manipulation tool. GIMP is an acronym for GNU Image Manipulation Program. The GIMP is suitable for a variety of image manipulation tasks, including photo retouching,... Read more
Spotify 1.1.9.383. - Stream music, creat...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
Posterino 3.5 - Create posters, collages...
Posterino offers enhanced customization and flexibility including a variety of new, stylish templates featuring grids of identical or odd-sized image boxes. You can customize the size and shape of... Read more

Latest Forum Discussions

See All

Dark Quest 2 guide - Tips and tricks for...
Dark Quest 2 is a fairly straightforward dungeon-crawler, and it also happens to have a bit of a grind to it. At a certain point in the game, you’ll almost certainly be going back to replay missions just to make your heroes stronger for the path... | Read more »
Marvel Super War Beta Impressions
Marvel Super War is the latest MOBA from Netease, but it’s not something you can just go and download on the App Store now. The game is in a closed beta, meaning you have to download it from a special linkhere and the developers are still ironing... | Read more »
Wild Bullets guide - Tips and tricks for...
Wild Bullets offers up fast and fun wild west action, but it has a good amount of strange mechanics to navigate. Between the game’s unique movement and all of its unlocks, there’s quite a bit to take in. With that said, we put in a good amount of... | Read more »
Superhero-themed runner Talking Tom Hero...
After a massively popular pre-registration period, Outfit7’s runner, Talking Tom Hero Dash, has now landed on iOS and Android. This latest game in the beloved Talking Tom and Friends franchise sees the Talking Tom Heroes team taking on a band of... | Read more »
Infectonator 3: Apocalypse guide - Tips...
When I first booted up Infectonator 3: Apocalypse, I was surprised by the sheer amount of stuff going on it. From crafting and leveling zombies to the intricacies of managing a wandering horde of braindead zombies, it can be overwhelming. | Read more »
A beginner’s guide to MU Origin 2
Webzen’s acclaimed MU Origin 2 recently launched on iOS and Android, shaking up the MMORPG genre in the process. It’s a huge game with a lot of different systems and modes to learn, so we’ve put together a handy beginner’s guide to give you a head... | Read more »
Q&A with the creator of Flappy Fight...
Earlier this month, a little game called Flappy Fighter hit the App Store and seemingly surprised everyone. What looked like a simple Flappy Bird send-up actually turned into the little mobile fighting game that could. | Read more »
MU Origin 2, Webzen’s highly anticipated...
Having successfully left its closed beta phase, MU Origin 2 is no longer available for pre-registration – because it’s now entered its full release. It’s a fully-fledged 3D MMORPG and the second spin-off based on the Webzen’s popular MU universe,... | Read more »
AFK Arena guide - Everything you need to...
Ok, so if you're like me, you've been playing (and sometimes waiting) your way through AFK Arena, only to learn there's a lot more to it than there appears on the surface. There's guilds, a PvP arena, and all sorts of other systems and game modes... | Read more »
Explore an epic fantasy world in MMORPG...
Webzen have just announced the official launch date for its stunning MMORPG ‘MU Origin 2’ which will arrive for iOS and Android on May 28th. It will be the second spinoff from the classic PC-based MU Online, and it looks to further refine the... | Read more »

Price Scanner via MacPrices.net

New Verizon special: 64GB iPhone Xr + 32GB 9....
Verizon is offering a 64GB iPhone Xr plus a 32GB 9.7″ iPad, combined, for $30 per month for new lines. The fine print: “$749.99 (iPhone XR 64GB) and $459.99 (iPad 9.7 32GB) device payment purchase... Read more
Apple’s new 2019 13″ 2.4GHz 4-Core MacBook Pr...
Amazon has the new 2019 13″ 2.4GHz 4-Core Touch Bar MacBook Pros on sale today for $150 off Apple’s MSRP with prices starting at $1649. Shipping is free. These are the same MacBook Pros sold by Apple... Read more
New 2019 21″ iMacs on sale for up to $100 off...
B&H Photo has new 21″ Apple iMacs on sale for up to $100 off MSRP with models available starting at $999. These are the same iMacs offered by Apple in their retail and online stores. Shipping is... Read more
Amazon is offering Apple’s new 2019 15″ MacBo...
Amazon has the new 2019 15″ 6-Core and 8-Core MacBook Pros on sale today for $200 off Apple’s MSRP. Shipping is free: – 2019 15″ 2.3GHz 8-Core MacBook Pro Space Gray or Silver: $2599.99 $200 off MSRP... Read more
Our exclusive MacBook Price Trackers show you...
Our Apple award-winning MacBook price trackers are the best place to look for the best sales and lowest prices on MacBooks, MacBook Airs, and MacBook Pros. Scan our price trackers for the latest... Read more
Sprint is offering iPhone 8 Plus pre-owned le...
Sprint is offering the 64GB iPhone 8 Plus, preowned, for $10 per month when combined with a Sprint 18 month Flex lease. Offer is valid from 6/14/19 to 6/30/19. Upgrade to a 256GB model for $12 per... Read more
Amazon is offering a 50% discount on Apple Sm...
Amazon has Apple Smart Keyboards for current-generation 10″ iPad Airs and previous-generation 10″ iPad Pros on sale today for $79.50 shipped. That’s a 50% discount over Apple’s regular MSRP of $159... Read more
Roundup of the best 13″ MacBook Air sales...
Amazon has new 2018 13″ MacBook Airs on sale for $100-$150 off Apple’s MSRP, with prices starting at $1099, each including free shipping. Be sure to select Amazon as the seller during checkout,... Read more
Sale! New 2019 15″ & 13″ MacBook Pros now...
B&H Photo has the new 2019 15″ and 13″ MacBook Pros now on sale for up to $200 off Apple’s MSRP. Overnight shipping is free to many addressed in the US. B&H’s prices are currently the lowest... Read more
New 2019 15″ 2.6GHz 6-Core MacBook Pro on sal...
Adorama has the new 2019 15″ 2.6GHz 6-Core Space Gray MacBook Pro on sale today for $2244 shipped. Their price is $155 off Apple’s MSRP, and Adorama charges sales tax for NY & NJ residents only... Read more

Jobs Board

Partner Champion, *Apple* Outbound - Insigh...
Partner Champion, Apple Outbound Tempe, AZ, USLiberty Lake, WA, USTampa, FL, USAustin, TX, US Requisition Number:73415 As an Apple Outbound Partner Champion at Read more
Best Buy *Apple* Computing Master - Best Bu...
**685645BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000165-Memphis-Store **Job Description:** **What does a Best Read more
Field Business Development Manager, *Apple*...
Field Business Development Manager, Apple Chicago, IL, USEden Prairie, MN, US Requisition Number:73320 As an Apple Business Development Manager at Insight, you Read more
Geek Squad *Apple* Master Consultation Agen...
**702908BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Job Category:** Services/Installation/Repair **Location Number:** 000360-Williston-Store Read more
*Apple* Mobile Master - Best Buy (United Sta...
**699587BR** **Job Title:** Apple Mobile Master **Job Category:** Store Associates **Location Number:** 000394-Western Hills-Store **Job Description:** **What does a Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.