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

DiskCatalogMaker 8.4.2 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
Posterino 3.11.1 - Create posters, colla...
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
Eye Candy 7.2.3.182 - 30 professional Ph...
Eye Candy renders realistic effects that are difficult or impossible to achieve in Photoshop alone, such as Fire, Chrome, and the new Lightning. Effects like Animal Fur, Smoke, and Reptile Skin are... Read more
Iridient Developer 3.6.1 - Powerful imag...
Iridient Developer (was RAW Developer) is a powerful image-conversion application designed specifically for OS X. Iridient Developer gives advanced photographers total control over every aspect of... Read more
CrossOver 21.1.0 - Run Windows apps on y...
CrossOver can get your Windows productivity applications and PC games up and running on your Mac quickly and easily. CrossOver runs the Windows software that you need on Mac at home, in the office,... Read more
Google Chrome 96.0.4664.55 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Bartender 4.1.21 - Organize your menu-ba...
Bartender lets you organize your menu-bar apps by hiding them, rearranging them, or moving them to Bartender's Bar. You can display the full menu bar, set options to have menu-bar items show in the... Read more
CleanMyMac X 4.9.3 - Delete files that w...
CleanMyMac makes space for the things you love. Sporting a range of ingenious new features, CleanMyMac lets you safely and intelligently scan and clean your entire system, delete large, unused files... Read more
ffWorks 2.6.4 - Convert multimedia files...
ffWorks, focused on simplicity, brings a fresh approach to the use of FFmpeg, allowing you to create ultra-high-quality movies without the need to write a single line of code on the command-line.... Read more
Thunderbird 91.3.2 - Email client from M...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more

Latest Forum Discussions

See All

The ACA NeoGeo Series Debuts on iOS and...
The Hamster-produced excellent ACA NeoGeo series of releases on Nintendo Switch, PS4, and Xbox platforms has been bringing many classics to modern platforms with a few conveniences for a while now. Today, SNK announced (via @gosokkyu) that the ACA... | Read more »
Scoot or Die, Dude – ‘Touchgrind Scooter...
Just about one year ago developer Illusion Labs announced Touchgrind Scooter, a new entry in their popular Touchgrind series that had already featured skateboarding and BMX biking. This new game would follow a similar formula featuring large levels... | Read more »
‘Rocket League Sideswipe’ Now Available...
After many years of players hoping that developer Psyonix would bring Rocket League to mobile, and MANY knock-offs and clones released on mobile since, they finally announced the official mobile entry in the series this past March with a spin-off... | Read more »
SwitchArcade Round-Up: Reviews Featuring...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for November 29th, 2021. In today’s article, we’ve got a trio of reviews for you to check out. Pokemon Brilliant Diamond and Shining Pearl leads the pack, with Date Night Bowling and... | Read more »
Best iPhone Game Updates: ‘Real Racing 3...
Hello everyone, and welcome to the week! It’s time once again for our look back at the noteworthy updates of the last seven days. With December just around the corner, we’re starting to see more winter updates roll in. There aren’t a whole ton of... | Read more »
5 futuristic games like PUBG New State
The biggest flex of PUBG New State is its futuristic background. The new battle royale game is set in 2051. It has a new map, Troi, and also has a future version of Erangel. The weapon customization, drones, and other new features make it a new-... | Read more »
TouchArcade Game of the Week: ‘Jump Jerb...
I love games that don’t mess around. No frills or fluff, just “Here’s what I am and here’s what you get." That’s the vibe I get from Jump Jerboa from self-described “mostly solo" developer Chinykian. This is a minimalist one-button platformer that... | Read more »
SwitchArcade Round-Up: ‘Date Night Bowli...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for November 26th, 2021. In today’s article, we look at the rest of the releases for the week. There are a couple of good games in today’s batch, and we’ve got summaries of the whole lot... | Read more »
Musical 2D Platformer ‘One Hand Clapping...
Bad Dream Games’ One Hand Clapping was originally a project demo at the University of Southern California and it has evolved into a full game that blends music with 2D platforming. It was previously revealed for PC and consoles and it is also now... | Read more »
Best Black Friday 2021 iPhone and iPad G...
Just like last year, many retailers have been discounting and price matching games and hardware well before Black Friday. The App Store has some great deals on iOS games that are available right now and more that will likely start showing up in the... | Read more »

Price Scanner via MacPrices.net

13″ M1 MacBook Pro with 512GB SSD on Cyber Mo...
Amazon has the Space Gray 13″ M1 MacBook Pro with a 512GB SSD on Cyber Monday 2021 sale for $250 off MSRP shipped: – 2020 13″ MacBook Pro Space Gray M1 CPU/512GB SSD: $1249.99 $250 off MSRP Their $... Read more
Cyber Monday 2021 Sale: $10 off HomePod minis...
Staples’ online store has HomePod minis on sale for $10 (10%) off MSRP as part of their Cyber Monday 2021 sale. Prices for online orders only, in-store prices may vary. Order online and choose free... Read more
B&H has M1 Mac minis on sale for up to $1...
B&H Photo has Apple’s Mac minis with M1 Apple Silicon CPUs in stock today and on sale for $70-$150 off MSRP, starting at $629, for Cyber Monday 2021. Free 1-2 shipping is free to many US... Read more
This is the best Cyber Monday 2021 deal on Ap...
B&H Photo is offering a $200 discount on Apple’s new 14″ M1 Pro MacBook Pro as part of their Cyber Monday 2021 sale. Their sale price applies to the configuration below, and it’s in stock today... Read more
Apple AirPods are on sale for up to $70 off M...
Amazon has launched their Cyber Monday 2021 Apple AirPods sale. Models are available for up to $70 off Apple’s MSRP with prices starting at only $99. Shipping is free, and all models are in stock... Read more
Cyber Monday Deal: 13″ M1 Silver MacBook Airs...
Apple resellers are offering the M1-powered 13″ 256GB Silver MacBook Air for $130 off Apple’s MSRP, only $869, as part of their Cyber Monday 2021 sales: 8-Core M1 Silicon CPU, 7-Core GPU. MSRP: $999... Read more
Cyber Monday Clearance Deal: 21″ iMac for onl...
Amazon has recently-discontinued 2020 21″ 2.3GHz Intel-based dual-core i5 iMacs (8GB RAM/256GB SSD) on clearance sale for only $799 shipped as part of their Cyber Monday 2021 sale. Their price is $... Read more
Cyber Monday Sale: 16″ M1 Pro MacBook Pro in...
Apple resellers are reporting stock of the new 16″ MacBook Pro with an Apple M1 Pro CPU today and are discounting one model $100 off MSRP: – 16″ Space Gray 10-core MacBook Pro (M1 Pro/16GB RAM/512GB... Read more
Black Friday Sale: Get an 11″ M1 2TB WiFi iPa...
Amazon has the 11″ M1 2TB WiFi iPad Pro, in Space Gray, on sale for $1648.99 shipped as part of their Black Friday/Cyber Monday 2021 sale. Amazon’s price is $250 off MSRP, and it’s the lowest price... Read more
The best Black Friday/Cyber Monday 2021 deal...
Apple has a full line of 2020 13″ M1 MacBook Airs available and in stock today, Certified Refurbished, starting at only $849 and up to $190 off original MSRP. These are the best deals on 13″ MacBook... Read more

Jobs Board

*Apple* Engineering Specialist - General Dyn...
…innovative IT Service Delivery solutions to SEC. Currently, we are seeking an Apple Engineering Specialist in Washington, DC Candidates must be US Citizens (without Read more
*Apple* / Macintosh / ADM Systems Administra...
…Administration **Duties and Responsibilities** + Configure and maintain the client's Apple Device Management (ADM) solution. The current solution is JAMF supporting Read more
Sephora Beauty Advisor - *Apple* Blossom Ma...
Sephora Beauty Advisor - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Systems Engineer, *Apple* - Cisco (United S...
…beginning on your first day? If so, we hope you'll keep reading! The Apple Sales Engineering team is looking for a pre-sales engineer with an Enterprise Networking Read more
Mac / *Apple* / Jamf Endpoint Engineer - Ci...
…deploy applications and settings to company managed devices. + Align Jamf and Apple technology with business processes to enhance efficiency. + Work closely with Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.