Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://Cenon-3.67.tar.bz2:2121020/Cenon/GraphicObjects.subproj/VImage.m  downloads

/* VImage.m
 *
 * Copyright (C) 1996-2004 by vhf interservice GmbH
 * Author:   Georg Fleischmann
 *
 * created:  1998-03-22
 * modified: 2004-10-06
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the vhf Public License as
 * published by vhf interservice GmbH. Among other things, the
 * License requires that the copyright notices and this notice
 * be preserved on all copies.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the vhf Public License for more details.
 *
 * You should have received a copy of the vhf Public License along
 * with this program; see the file LICENSE. If not, write to vhf.
 *
 * vhf interservice GmbH, Im Marxle 3, 72119 Altingen, Germany
 * eMail: info@vhf.de
 * http://www.vhf.de
 */

#include <AppKit/AppKit.h>
#include "VImage.h"
#include "PathContour.h"
#include "../App.h"
#include "../DocView.h"
#include "../DocWindow.h"
#include "../Inspectors.h"
#include "../messages.h"

static int currentGraphicIdentifier = 1;

@interface VImage(PrivateMethods)
- (void)setParameter;
@end

@implementation VImage

/* Locking focus on an NSImage forces it to draw and thus verifies
 * whether there are any PostScript or TIFF errors in the source of
 * the image. lockFocus returns YES only if there are no errors.
 */
static BOOL checkImage(NSImage *anImage)
{
    if ([anImage isValid])
    { 
	[anImage lockFocus];
	[anImage unlockFocus];
	return YES;
    }
    return NO;
}

#if 0	// not used yet, and not many of the methods available for GNUstep, yet
//#if defined(GNUSTEP_BASE_VERSION) || defined(__APPLE__)

static NSBitmapImageFileType fileTypeFromVImageType(VImageFileType fileType)
{
    switch (fileType)
    {
        case VImageTIFF_None:
        case VImageTIFF_LZW:
        case VImageTIFF_PackBits: return NSTIFFFileType;
        case VImageBMP:           return NSBMPFileType;
        case VImageGIF:           return NSGIFFileType;
        case VImageJPEG:          return NSJPEGFileType;
        case VImagePNG:           return NSPNGFileType;
    }
    return NSTIFFFileType;
}
static NSDictionary *propertiesForFileType(VImageFileType fileType, float compressionFactor)
{   NSMutableDictionary	*dict = [NSMutableDictionary dictionary];

    switch (fileType)
    {
        case VImageTIFF_None:
            [dict setObject:[NSNumber numberWithInt:NSTIFFCompressionNone] forKey:NSImageCompressionMethod];
            break;
        case VImageTIFF_LZW:
            [dict setObject:[NSNumber numberWithInt:NSTIFFCompressionLZW] forKey:NSImageCompressionMethod];
            break;
        case VImageTIFF_PackBits:
            [dict setObject:[NSNumber numberWithInt:NSTIFFCompressionPackBits] forKey:NSImageCompressionMethod];
            break;
        case VImageBMP:
            break;
        case VImageGIF:
            break;
        case VImageJPEG:
            [dict setObject:[NSNumber numberWithFloat:compressionFactor] forKey:NSImageCompressionFactor];
            break;
        case VImagePNG:
            break;
    }
    return dict;
}
#endif

static NSString *fileExtensionFromFileType(VImageFileType fileType)
{
    switch (fileType)
    {
        case VImageTIFF_None:
        case VImageTIFF_LZW:
        case VImageTIFF_PackBits: return @"tiff";
        case VImageBMP:           return @"bmp";
        case VImageGIF:           return @"gif";
        case VImageJPEG:          return @"jpg";
        case VImagePNG:           return @"png";
        //default:                  return @"tiff";
    }
    return nil;
}
static NSTIFFCompression tiffCompressionFromVImageType(VImageFileType fileType)
{
    switch (fileType)
    {
        case VImageTIFF_LZW:      return NSTIFFCompressionLZW;
        case VImageTIFF_PackBits: return NSTIFFCompressionPackBits;
        default:                  return NSTIFFCompressionNone;
    }
    return NSTIFFCompressionNone;
}
static VImageFileType fileTypeForTIFFCompression(NSTIFFCompression tiffCompression)
{
    switch (tiffCompression)
    {
        case NSTIFFCompressionLZW:      return VImageTIFF_LZW;
        case NSTIFFCompressionPackBits: return VImageTIFF_PackBits;
        default:                        return VImageTIFF_None;
    }
    return VImageTIFF_None;
}

/* This sets the class version so that we can compatibly read old objects out of an archive.
 */
+ (void)initialize
{
    [VImage setVersion:4];
    return;
}

/* return accepted file type for platform */
+ (BOOL)isAcceptedFileType:(VImageFileType)type
{
    switch (type)
    {
#if defined(GNUSTEP_BASE_VERSION)
        case VImageTIFF_LZW:      return NO;
        default:                  return YES;
#elif defined(__APPLE__)
        default:                  return YES;
#else
        case VImageTIFF_None:
        case VImageTIFF_LZW:
        case VImageTIFF_PackBits: return YES;
        default:                  return NO;
#endif
    }
    return YES;
}

/* initialize
 */
- init
{
    identifier = currentGraphicIdentifier++;
    [self setParameter];
    return [super init];
}

- (NSString*)title		{ return @"Image"; }

/*
 * Creates a new NSImage and sets it to be scalable and to retain
 * its data (which means that when we archive it, it will actually
 * write the TIFF or PostScript data into the stream).
 */
- (id)initWithPasteboard:(NSPasteboard *)pboard;
{
    [self init];

    if (pboard)
    {
	image = [NSImage allocWithZone:(NSZone *)[self zone]];
	if ((image = [image initWithPasteboard:pboard]))
        {
	    [image setDataRetained:YES];
	    if (checkImage(image))
            {
		originalSize = [image size];
		[image setScalesWhenResized:YES];
		size = originalSize;
		return self;
	    }
	}
    }
    [self release];
    return nil;
}

/*
 * Creates an NSImage by reading data from an .eps or .tiff file.
 */
- (id)initWithFile:(NSString *)file
{
    return [self initWithRepresentations:[NSImageRep imageRepsWithContentsOfFile:file]];
}

/*
 * Creates an NSImage from existing representation
 */
- (id)initWithRepresentations:(NSArray*)reps
{
    [self init];

    image = [[NSImage allocWithZone:(NSZone *)[self zone]] init];
    [image addRepresentations:reps];
    [image setDataRetained:YES];
    if (checkImage(image))
    {
	originalSize = [image size];
	[image setScalesWhenResized:YES];
	size = originalSize;
	return self;
    }
    [self release];
    return nil;
}

- copy
{   VImage *nImage = [[VImage allocWithZone:[self zone]] init];

    [nImage setImage:[image copy]];
    [nImage setSize:size];
    [nImage setOrigin:origin];
    //[nImage setParameter]; // init call it
    [nImage setThumbnail:thumbnail];
    [nImage setFileType:fileType];
    [nImage setCompressionFactor:compressionFactor];
    if (clipPath)
        [nImage join:clipPath];
    return nImage;
}

- (void)setImage:(NSImage*)nImage
{
    if ( image )
        [image release];
#ifdef USE_VHF_CLIPPING
    [clipImage release]; clipImage = nil;
#endif
    image = [nImage retain];
    originalSize = [image size];
    dirty = YES;
}
- (NSImage*)image	{ return image; }

/*
 * created: 1995-09-25
 * purpose: initializes all the stuff needed after a -read:
 */
- (void)setParameter
{
    selectedKnob = -1;
    reliefType = RELIEF_LINEAR;
    clipPath = nil;
    thumbnail = NO;
    imageFile = [[NSString stringWithFormat:@"Image%d.tiff", identifier] retain];
    sourcePath = nil;
    fileType = VImageTIFF_LZW;
    compressionFactor = 0.1;
    compressionDirty = NO;
}

- (float)naturalAspectRatio
{
    if (!originalSize.height)
        return 0.0;
    return originalSize.width / originalSize.height;
}

- (void)setSize:(NSSize)newSize		{ size = newSize; dirty = YES; }
- (NSSize)size				{ return size; }
- (NSSize)originalSize			{ return originalSize; }

- (void)setOrigin:(NSPoint)newOrigin	{ origin = newOrigin; dirty = YES; }
- (NSPoint)origin			{ return origin; }

- (void)setRelief:(BOOL)flag		{ relief = flag; dirty = YES; }
- (BOOL)relief				{ return relief; }
- (void)setReliefType:(int)type		{ reliefType = type; dirty = YES; }
- (int)reliefType			{ return reliefType; }

- (NSString*)setName:(NSString*)str
{
    if (![[str pathExtension] isEqual:@"tiff"])
        str = [NSString stringWithFormat:@"%@.tiff", str];
    [imageFile release];
    imageFile = [[NSString stringWithFormat:@"%@", str] retain];
    return imageFile;
}

- (NSString*)name			{ return imageFile; }

- (NSImage*)thumbnailImage
{   int			i;
    NSArray		*imageReps;
    NSBitmapImageRep	*bmImageRep = nil;

    /* get bitmap of image */
    imageReps = [image representations];
    for (i=0; i<(int)[imageReps count]; i++)
    {   id	bitmapRep = [imageReps objectAtIndex:i];

        if ( [bitmapRep isKindOfClass:[NSBitmapImageRep class]] )
        {   bmImageRep = bitmapRep;
            break;
        }
    }
    if (bmImageRep)
    {   int		y, x, bps, bppixel, bpr, ha, pl, bypplane, spp, oRows, rows, bitspr, columns;
        long			abypplane, lx, ly, abpr, oColumns;
        unsigned char		*data[5], *aplanes[5];
        float			xf, yf;
        NSString		*csname;
        NSImage			*aImage;
        NSBitmapImageRep	*abitmap;

        /* analyse bitmap (mash planar 234 components) */
        bypplane = [bmImageRep bytesPerPlane];
        bpr = [bmImageRep bytesPerRow];
        bitspr = bpr * 8;
        bppixel = [bmImageRep bitsPerPixel];
        bps = [bmImageRep bitsPerSample];
        spp = [bmImageRep samplesPerPixel];
        ha = [bmImageRep hasAlpha];
        pl = [bmImageRep isPlanar];
        csname = [bmImageRep colorSpaceName];
        if ( !pl )
            data[0] = [bmImageRep bitmapData];
        else
            [bmImageRep getBitmapDataPlanes:data];

        oRows = [bmImageRep pixelsHigh];
        oColumns = [bmImageRep pixelsWide];
        columns = floor(size.width); // rect.size.width
        rows = floor(size.height);

        aImage = [[NSImage allocWithZone:(NSZone *)[self zone]] initWithSize:NSMakeSize(columns, rows)];
        /* create image with 1, 2, 3 or 4 planes -> W (1), WA (2), RGB (3) or RGBA (4) */
        abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                          pixelsWide:columns
                                                          pixelsHigh:rows
                                                       bitsPerSample:bps
                                                     samplesPerPixel:(spp <= 4) ? spp : 4
                                                            hasAlpha:ha isPlanar:YES
                                                      colorSpaceName:((spp == 1) ? NSCalibratedWhiteColorSpace
                                                                                 : csname)
                                                         bytesPerRow:(columns*bps)/8
                                                        bitsPerPixel:bps];
        [abitmap getBitmapDataPlanes:aplanes];
        abpr = [abitmap bytesPerRow];
        abypplane = [abitmap bytesPerPlane];

        xf = ((float)oColumns/columns); // imageSize.   -2
        yf = ((float)oRows/rows);
        // ly = 0
        for (y=0, ly=((int)yf/2.0); y<rows && ly < oRows; y++,
             ly+=((yf*y)-((int)(yf*y))>=(yf*(y-1))-((int)(yf*(y-1))))?((int)yf):((int)yf+1))
        {   long	by = abypplane - (y * abpr) - abpr; // part height
            long	lby = bypplane - (ly * bpr) - bpr; // original heigt
            // lx = 0
            for (x=0, lx=((int)xf/2.0); x<abpr && lx < bpr; x++,
                 lx+=((xf*x)-((int)(xf*x))>=(xf*(x-1))-((int)(xf*(x-1))))?((int)xf):((int)xf+1))
            {
                *((aplanes[0]+by+x)) = (pl) ? *((data[0]+lby+lx)) : *((data[0]+lby+lx*spp)); // r || c
                if (spp > 2) // g b || m y
                {   *((aplanes[1]+by+x)) = (pl) ? *((data[1]+lby+lx)) : *((data[0]+lby+lx*spp+1));
                    *((aplanes[2]+by+x)) = (pl) ? *((data[2]+lby+lx)) : *((data[0]+lby+lx*spp+2));
                    if (!ha && spp > 3) // k
                        *((aplanes[3]+by+x)) = (pl) ? *((data[3]+lby+lx)) : *((data[0]+lby+lx*spp+3));
                }
                if (ha)
                    *((aplanes[(spp == 4) ? 3:1]+by+x)) =
                        (pl) ? *((data[((spp == 4) ? 3:1)]+lby+lx)) : *((data[0]+lby+lx*spp+((spp == 4) ? 3:1)));
            }
        }
        [aImage addRepresentation:abitmap];
        [abitmap release];
        [aImage setDataRetained:YES];
        if (checkImage(aImage))
            [aImage setScalesWhenResized:YES];
        else
        {   [aImage release];
            return nil;
        }
        return aImage;
    }
    return nil;
}
- (void)setThumbnail:(BOOL)flag
{   NSString	*filename = [[[[[self class] currentView] document] filename]
                             stringByAppendingPathComponent:[imageFile lastPathComponent]];

#ifdef USE_VHF_CLIPPING
    [clipImage release]; clipImage = nil;
#endif

    thumbnail = flag;
    dirty = YES;
    /* if YES create thumbnail */
    if (thumbnail)
    {
        if ((thumbImage = [self thumbnailImage]))
        {
            originalSize = [thumbImage size];
            if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
            {   /* file allready saved -> release */
                [image release];
                image = nil;
            }
        }
        else
            thumbnail = NO;
    }
    else if (!image) // load image from file
    {	NSArray	*reps = nil;

        if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
            reps = [NSImageRep imageRepsWithContentsOfFile:filename];
        else if ([[NSFileManager defaultManager] fileExistsAtPath:sourcePath])
            reps = [NSImageRep imageRepsWithContentsOfFile:sourcePath];
        if (reps)
        {
            image = [[NSImage allocWithZone:(NSZone *)[self zone]] init];
            [image addRepresentations:reps];
            [image setDataRetained:YES];
            if (checkImage(image))
            {
                originalSize = [image size];
                [image setScalesWhenResized:YES];
            }
            else
            {   [image release];
                image = nil;
            }
        }
    }
    if (!thumbnail && thumbImage)
    {   [thumbImage release];
        thumbImage = nil;
    }
}
- (BOOL)thumbnail			{ return thumbnail; }

- (void)setFileType:(VImageFileType)type	{ fileType = type; compressionDirty = YES; }
- (VImageFileType)fileType;			{ return fileType; }
- (void)setCompressionFactor:(float)f;	{ compressionFactor = f; compressionDirty = YES; }
- (float)compressionFactor;		{ return compressionFactor; }

- (id)clipPath				{ return clipPath; }

/*
 * subclassed methods
 */

/* returns the selected knob or -1
 */
- (int)selectedKnobIndex
{
    return selectedKnob;
}

/* set the selection of the plane
 */
- (void)setSelected:(BOOL)flag
{
    if (!flag)
        selectedKnob = -1;
    return [super setSelected:flag];
}

- (void)scale:(float)x :(float)y withCenter:(NSPoint)cp
{
    if (clipPath)
        [clipPath scale:x :y withCenter:cp];
    origin.x = ScaleValue(origin.x, cp.x, x);
    origin.y = ScaleValue(origin.y, cp.y, y);
    size.width *= x;
    size.height *= y;
    dirty = YES;
}

- (void)join:obj
{
    if (clipPath)
        [clipPath release];
    if ([obj isMemberOfClass:[VRectangle class]] && [obj radius])
        clipPath = [[obj pathRepresentation] retain];
    else
        clipPath = [obj retain];
}

/* dissolve ourself to ulist
 */
- (void)splitTo:ulist
{
    [clipPath setSelected:YES];
    [clipPath setDirty:YES];
    [ulist addObject:clipPath];
    [self setSelected:YES];
    [self setDirty:YES];
    [clipPath release]; clipPath = nil;
#ifdef USE_VHF_CLIPPING
    [clipImage release]; clipImage = nil;
#endif
    [ulist addObject:self];
}

/* antialiasing for OpenStep and GNUstep
 * 8 bits per sample only
 */
#ifndef __APPLE__
void antialiasColorFromBits(unsigned char **data, int byteY, int px, int bps, int spp, BOOL p, NSString *colorSpaceName, int bits, int bpr, long *rgba)
{   long	x, y, cr=0, cg=0, cb=0, ca=0;

    if (p)
    {   int	add;

        for (y=0; y<bits; y++)
        {
            for (x=0; x<bits; x++)
            {
                add = byteY+px+x-y*bpr;
                cr += *(data[0]+add); // x*bsp/8 -> (x*(8/8))
                if (spp > 2) // rgb
                {   cg += *(data[1]+add);
                    cb += *(data[2]+add);
                    if (spp > 3) // rgba || cmyk
                        ca += *(data[3]+add);
                }
                if (spp == 2) // bwa
                    ca += *(data[1]+add);
            }
        }
    }
    else // meshed
    {   int	add;

        for (y=0; y<bits; y++)
        {
            for (x=0; x<bits; x++)
            {
                add = byteY+px+x*spp-y*bpr;
                cr += *((data[0]+add)); // spp+bsp/8 -> (spp*(8/8))
                if (spp > 2) // rgb
                {
                    cg += *((data[0]+add+1));
                    cb += *((data[0]+add+2));
                    if (spp > 3) // rgba || cmyk
                        ca += *((data[0]+add+3));
                }
                if (spp == 2) // bwa
                    ca += *((data[0]+add+1));
            }
        }
    }
    // middle color of all bits*bits pixels
    rgba[0] = (float)cr/(float)(bits*bits);
    rgba[1] = (float)cg/(float)(bits*bits);
    rgba[2] = (float)cb/(float)(bits*bits);
    rgba[3] = (float)ca/(float)(bits*bits);
}

- (BOOL)compositeAntialiased:(float)scale toPoint:(NSPoint)p
{   NSPoint		imageScale;
    int			i;
    float		sumScale = 1.0, pW, pH;
    NSArray		*imageReps;
    NSBitmapImageRep	*bmImageRep = nil;

    /* get bitmap of image */
    imageReps = [image representations];
    for (i=0; i<(int)[imageReps count]; i++)
    {   id	bitmapRep = [imageReps objectAtIndex:i];

        if ( [bitmapRep isKindOfClass:[NSBitmapImageRep class]] )
        {   bmImageRep = bitmapRep;
            break;
        }
    }
    if (bmImageRep)
    {   pW = [bmImageRep pixelsWide];
        pH = [bmImageRep pixelsHigh];
    }
    else
        return NO;
    /* antialiase image ? */
    imageScale.x = size.width / pW; // originalSize.width;
    imageScale.y = size.height / pH; // originalSize.height;
    sumScale = 1 / (imageScale.x * scale);
    if ( Diff(imageScale.x, imageScale.y) < TOLERANCE && (sumScale-floor(sumScale)) < TOLERANCE &&
         sumScale >= 2 && sumScale <= 20 )
    {   int			bits = sumScale;
        int			y, x, bps, bppixel, bpr, ha, pl, bypplane, spp, oRows, rows, bitspr, columns;
        long			abypplane, lx, ly, rgba[4];
        unsigned char		*data[5], *aplanes[5];
        NSString		*csname;
        NSImage			*aImage;
        NSBitmapImageRep	*abitmap;

        /* analyse bitmap (mash planar 2,3,4 components) */
        bypplane = [bmImageRep bytesPerPlane];
        bpr = [bmImageRep bytesPerRow];
        bitspr = bpr * 8;
        bppixel = [bmImageRep bitsPerPixel];
        bps = [bmImageRep bitsPerSample];
        if (bps != 8)
            return NO;
        spp = [bmImageRep samplesPerPixel];
        ha = [bmImageRep hasAlpha];
        pl = [bmImageRep isPlanar];
        csname = [bmImageRep colorSpaceName];
        if ( !pl )
            data[0] = [bmImageRep bitmapData];
        else
            [bmImageRep getBitmapDataPlanes:data];

        /* antialias bitmap with factor bits */
        oRows = bypplane / bpr;	// rows (original height)
        rows = oRows / bits;	// rows of antialiased image
        columns = (pl) ? (bpr / bits) : ((bpr/spp) / bits);
        bitspr -= ((pl)?(bits*bps):(bits*spp*bps))/2;

        aImage = [[NSImage allocWithZone:(NSZone *)[self zone]] initWithSize:NSMakeSize(columns, rows)];
        /* create image with 1, 2, 3 or 4 planes -> W (1), WA (2), RGB (3) or RGBA (4) */
        abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                          pixelsWide:columns
                                                          pixelsHigh:rows
                                                       bitsPerSample:8
                                                     samplesPerPixel:(spp <= 4) ? spp : 4
                                                            hasAlpha:ha isPlanar:YES
                                                      colorSpaceName:(spp == 1) ? NSCalibratedWhiteColorSpace
                                                                                : csname
                                                         bytesPerRow:columns
                                                        bitsPerPixel:8];
        [abitmap getBitmapDataPlanes:aplanes];
        abypplane = rows*columns;

        for (y=0, ly=0; y<oRows && ly < rows; y+=bits, ly++)
        {   long	byteY = bypplane - (y * bpr) - bpr; // up is down
            long	by = abypplane - (ly * columns) - columns; // anitaliased height

            for (x=0, lx=0; x<bitspr && lx<columns; x+=(pl)?(bits*bps):(bits*spp*bps), lx++)
            {
                antialiasColorFromBits(data, byteY, x/8, bps, spp, pl, csname, bits, bpr, rgba);
                *(aplanes[0]+by+lx) = rgba[0];
                if (spp > 2)
                {
                    *(aplanes[1]+by+lx) = rgba[1];
                    *(aplanes[2]+by+lx) = rgba[2];
                    if (!ha && spp > 3)
                        *(aplanes[3]+by+lx) = rgba[3];
                }
                if (ha)
                    *(aplanes[(spp == 4) ? 3 : 1]+by+lx) = rgba[3];
            }
        }
        [aImage addRepresentation:abitmap];
        [aImage compositeToPoint:p operation:NSCompositeSourceOver];
        [aImage release];
        [abitmap release];
        return YES;
    }
    return NO;
}
#endif	// OpenStep + GNUstep

- (BOOL)compositeInRect:(NSRect)rect toPoint:(NSPoint)p withScale:(float)scale
{   int			i;
    NSArray		*imageReps;
    NSBitmapImageRep	*bmImageRep = nil;

    if (!rect.size.width || !rect.size.height)
        return NO;

    /* get bitmap of image */
    imageReps = [((thumbImage && VHFIsDrawingToScreen())?thumbImage:image) representations];
    for (i=0; i<(int)[imageReps count]; i++)
    {   id	bitmapRep = [imageReps objectAtIndex:i];

        if ( [bitmapRep isKindOfClass:[NSBitmapImageRep class]] )
        {   bmImageRep = bitmapRep;
            break;
        }
    }
    if (bmImageRep)
    {   int			y, x, bps, bppixel, bpr, ha, pl, bypplane, spp, oRows, rows, bitspr, columns;
        long			abypplane, lx, ly, abpr, oColumns;
        unsigned char		*data[5], *aplanes[5];
        float			xf, yf;
        NSString		*csname;
        NSImage			*aImage;
        NSBitmapImageRep	*abitmap;
        NSSize			imageSize = [((thumbImage && VHFIsDrawingToScreen())?thumbImage:image) size];

        /* analyse bitmap (mash planar 234 components) */
        bypplane = [bmImageRep bytesPerPlane];
        bpr = [bmImageRep bytesPerRow];
        bitspr = bpr * 8;
        bppixel = [bmImageRep bitsPerPixel];
        bps = [bmImageRep bitsPerSample];
        spp = [bmImageRep samplesPerPixel];
        ha = [bmImageRep hasAlpha];
        pl = [bmImageRep isPlanar];
        csname = [bmImageRep colorSpaceName];
        if ( !pl )
            data[0] = [bmImageRep bitmapData];
        else
            [bmImageRep getBitmapDataPlanes:data];

        oRows = [bmImageRep pixelsHigh];
        oColumns = [bmImageRep pixelsWide];
        columns = floor(rect.size.width);
        rows = floor(rect.size.height);

        aImage = [[NSImage allocWithZone:(NSZone *)[self zone]] initWithSize:NSMakeSize(columns, rows)];
        /* create image with 1, 2, 3 or 4 planes -> W (1), WA (2), RGB (3) or RGBA (4) */
        abitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                          pixelsWide:columns
                                                          pixelsHigh:rows
                                                       bitsPerSample:bps
                                                     samplesPerPixel:(spp <= 4) ? spp : 4
                                                            hasAlpha:ha isPlanar:YES
                                                      colorSpaceName:((spp == 1) ? NSCalibratedWhiteColorSpace :
                                                                                   csname)
                                                         bytesPerRow:(((columns*bps)/8.0 > 0.0) ?
                                                                      ((columns*bps)/8.0+1) : ((columns*bps)/8.0))
                                                        bitsPerPixel:bps];
        [abitmap getBitmapDataPlanes:aplanes];
        abpr = [abitmap bytesPerRow];
        abypplane = [abitmap bytesPerPlane];
        xf = ((float)oColumns/imageSize.width);
        yf = ((float)oRows/imageSize.height);

        ly = floor(oRows * ((rect.origin.y-origin.y)*scale/imageSize.height));
        for (y=0; y<rows && ly < oRows; y++,
             ly+=((yf*y)-((int)(yf*y))>=(yf*(y-1))-((int)(yf*(y-1))))?((int)yf):((int)yf+1))
        {   long	by = abypplane - (y * abpr) - abpr; // part height
            long	lby = bypplane - (ly * bpr) - bpr; // original heigt

            lx = floor(((pl) ? (bpr) : (bpr/spp)) * ((rect.origin.x-origin.x)*scale/imageSize.width));
            for (x=0; x<abpr && lx < bpr; x++,
                 lx += ((xf*x)-((int)(xf*x))>=(xf*(x-1))-((int)(xf*(x-1)))) ? ((int)xf) : ((int)xf+1))
            {
                *((aplanes[0]+by+x)) = (pl) ? *((data[0]+lby+lx)) : *((data[0]+lby+lx*spp));
                if (spp>2)
                {   *((aplanes[1]+by+x)) = (pl) ? *((data[1]+lby+lx)) : *((data[0]+lby+lx*spp+1));
                    *((aplanes[2]+by+x)) = (pl) ? *((data[2]+lby+lx)) : *((data[0]+lby+lx*spp+2));
                    if (!ha && spp > 3)
                        *((aplanes[3]+by+x)) = (pl) ? *((data[3]+lby+lx)) : *((data[0]+lby+lx*spp+3));
                }
                if (ha)
                    *((aplanes[(spp == 4) ? 3:1]+by+x)) =
                        (pl) ? *((data[((spp == 4) ? 3:1)]+lby+lx)) : *((data[0]+lby+lx*spp+((spp == 4) ? 3:1)));
            }
        }
        [aImage addRepresentation:abitmap];
        [aImage compositeToPoint:rect.origin operation:NSCompositeSourceOver]; // rect.origin
        [aImage release];
        [abitmap release];
        return YES;
    }
    return NO;
}

/* clip image from clip path
 * this is a workaround for GNUstep (X11), not having a complex clipping
 * we create an alpha image with the clipping path having inside alpha = 1.0
 * We return no autoreleased image here !!!
 */
#ifdef USE_VHF_CLIPPING
#define MAX_SIDESTEPS 20	// maximum number of side-steps before giving up
- (NSImage*)clipImage:(NSImage*)anImage withPath:(VGraphic*)cPath scale:(float)scale
{   int			i, cnt;
    NSArray		*imageReps;
    NSBitmapImageRep	*aBitmap = nil, *cBitmap;
    NSImage		*cImage;
    NSString		*csname = nil;
    int			spp, w, h, alphaIx;
    float		y, yMin, yMax;
    NSRect		bRect;
    VLine		*line = [VLine line];
    NSPoint		*pts, p0, p1;
    unsigned char	*planes[5], *aPlanes[5];

    /* get bitmap of image */
    imageReps = [anImage representations];
    for (i=0; i<(int)[imageReps count]; i++)
    {   id	bitmapRep = [imageReps objectAtIndex:i];

        if ( [bitmapRep isKindOfClass:[NSBitmapImageRep class]] )
        {   aBitmap = bitmapRep;
            break;
        }
    }

    /* analyse bitmap (mash planar 2,3,4 components) */
    if ([aBitmap bitsPerSample] != 8)
    {   NSLog(@"VImage, clipImage: unsupported bits per sample %d", [aBitmap bitsPerSample]);
        return nil;
    }
    spp = [aBitmap samplesPerPixel];
    if ([aBitmap hasAlpha])
        spp--; // we dont wont two alpha planes !
    w = [aBitmap pixelsWide];
    h = [aBitmap pixelsHigh];
    csname = [aBitmap colorSpaceName];

    cImage = [[NSImage allocWithZone:(NSZone *)[self zone]] initWithSize:NSMakeSize(w, h)];
    [cImage setScalesWhenResized:YES];
    [cImage setDataRetained:YES];
    /* create image with 1, 2, 3 or 4 planes -> W (1), WA (2), RGB (3) or RGBA (4) */
    cBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                      pixelsWide:w pixelsHigh:h
                                                   bitsPerSample:8
                                                 samplesPerPixel:(spp == 1) ? 2 : ((spp == 3) ? 4 : 5)
                                                        hasAlpha:YES
                                                        isPlanar:YES
                                                  colorSpaceName:(spp == 1) ? NSDeviceWhiteColorSpace
                                                                            : csname
                                                     bytesPerRow:w
                                                    bitsPerPixel:8];
    //[cBitmap setSize:NSMakeSize(w, h)];
    [cImage addRepresentation:cBitmap];
    [cBitmap release];
    [cBitmap getBitmapDataPlanes:planes];

    /* copy planes of source image to RGB or CMYK or White plane of prepared image rep */
    [aBitmap getBitmapDataPlanes:aPlanes];
    alphaIx = (spp > 2) ? ((spp > 3) ? 4 : 3) : 1;
    for (i=0; i<w*h; i++)
    {
        if ([aBitmap isPlanar])
        {
            *((planes[0]+i)) = *(aPlanes[0]+i);
            if (spp > 2)
            {   *(planes[1]+i) = *(aPlanes[1]+i);
                *(planes[2]+i) = *(aPlanes[2]+i);
                if (spp > 3)
                    *(planes[3]+i) = *(aPlanes[3]+i);
            }
            *(planes[alphaIx]+i) = 0;	// all transparent
        }
        else
        {
            *(planes[0]+i) = *(aPlanes[0]+(i*spp));
            if (spp > 2)
            {   *(planes[1]+i) = *(aPlanes[0]+(i*spp)+1);
                *(planes[2]+i) = *(aPlanes[0]+(i*spp)+2);
                if (spp > 3)
                    *(planes[3]+i) = *(aPlanes[0]+(i*spp)+3);
            }
            *((planes[alphaIx]+i)) = 0;	// all transparent
        }
    }

    /* intersect clip path line by line and set pixel ranges of alpha channel accordingly */
    [cPath scale:w/size.width :h/size.height withCenter:origin];
    bRect = [cPath coordBounds];
    yMin = bRect.origin.y + 0.5;
    yMax = bRect.origin.y + bRect.size.height + 0.5;
    p0.x = bRect.origin.x - 2000.0; p1.x = bRect.origin.x+bRect.size.width + 2000.0;
    for ( y=yMin; y<yMax; y++ )
    {
        for (i=0; i<MAX_SIDESTEPS; i++)	// we need to find a position where we don't hit an edge
        {
            p0.y = p1.y = y + (float)i*(0.5*TOLERANCE);
            [line setVertices:p0 :p1];
            if ( !(cnt = [cPath getIntersections:&pts with:line]) )
                break;
            if ( cnt <= 1 )		// unpossible = tolerance problem in intersection methods
            {	free(pts); pts = NULL;
                continue;
            }
            if ( Even(cnt) &&		// when cnt is even we are probably ok
                 (![cPath isKindOfClass:[VPath class]] ||		// arc or rectangle
                  ![(VPath*)cPath pointArrayHitsCorner:pts :cnt]) )	// make sure we hit no edge
                break;
            if (i < MAX_SIDESTEPS-1)	// try again with side step
            {	free(pts); pts = 0; }
        }
        if ( i >= MAX_SIDESTEPS )
            NSLog(@"VImage (-clipImage:): troubles with extreme path!");
        sortPointArray(pts, cnt, p0);	// sort points from left to right
        if ( cnt <= 1 || !Even(cnt) )	// we hit an edge or other mischief
        {   free(pts); pts = 0;
            continue;
        }

        /* set alpha plane (use 'x/1000db planes[3]' in gdb to examine results) */
        for (i=0; i<cnt-1; i++)
        {   int	j, x0, x1, yi;

            if ( !Even(i) )	// outside of clip path
                continue;
            x0 = Max(pts[i].x   - origin.x, 0.0);
            x1 = Min(pts[i+1].x - origin.x, w);
            yi = h - (int)(y-origin.y);
            if (yi > h || yi < 0)
                break;
            for (j=x0; j<x1; j++)
                *(planes[alphaIx] + yi*w + j) = 255;
        }
    }
    [cPath scale:1.0/(w/size.width) :1.0/(h/size.height) withCenter:origin];
    //[cImage setSize:NSMakeSize(floor(size.width*scale), floor(size.height*scale))];

    return cImage;
}
#endif

- (NSImage*)separateImageWithColor:(NSColor*)sepColor
{   int			i;
    NSArray		*imageReps;
    NSBitmapImageRep	*bmImageRep = nil;

    /* get bitmap of image */
    imageReps = [image representations];
    for (i=0; i<(int)[imageReps count]; i++)
    {   id	bitmapRep = [imageReps objectAtIndex:i];

        if ( [bitmapRep isKindOfClass:[NSBitmapImageRep class]] )
        {   bmImageRep = bitmapRep;
            break;
        }
    }
    if (bmImageRep)
    {   int			y, x, bps, bppixel, bpr, ha, pl, bypplane, spp, rows, bitspr, columns;
        long			sbypplane, sbpr;
        unsigned char		*data[5], *splanes[5];
        NSImage			*sepImage;
        NSBitmapImageRep	*sepbitmap;

        /* analyse bitmap (mash planar 234 components) */
        bypplane = [bmImageRep bytesPerPlane];                             // [bmImageRep colorSpaceName]
        bpr = [bmImageRep bytesPerRow];
        bitspr = bpr * 8;
        bppixel = [bmImageRep bitsPerPixel];
        bps = [bmImageRep bitsPerSample];
        spp = [bmImageRep samplesPerPixel];

        /* draw only in black || rgb never draw in black */
        /* draw white rectangle */
        if ((bps != 8) || ((spp == 1 || spp == 2) && [sepColor blackComponent] == 0.0))
        {
            if (bps != 8)
                NSLog(@"VImage, separateImageWithColor: unsupported bits per sample %d", bps);
            return nil;
        }

        ha = [bmImageRep hasAlpha];
        pl = [bmImageRep isPlanar];
        if ( !pl )
            data[0] = [bmImageRep bitmapData];
        else
            [bmImageRep getBitmapDataPlanes:data];

        rows = [bmImageRep pixelsHigh];
        columns = [bmImageRep pixelsWide];

        sepImage = [[NSImage allocWithZone:(NSZone *)[self zone]] initWithSize:NSMakeSize(columns, rows)];
	[sepImage setScalesWhenResized:YES];
        [sepImage setDataRetained:YES];
        /* create image with 1 planes -> W (1) component */
        sepbitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
                                                          pixelsWide:columns
                                                          pixelsHigh:rows
                                                       bitsPerSample:bps
                                                     samplesPerPixel:1
                                                            hasAlpha:NO isPlanar:YES
                                                      colorSpaceName:NSCalibratedWhiteColorSpace
                                                         bytesPerRow:(columns*bps)/8.0
                                                        bitsPerPixel:bps];
        [sepbitmap getBitmapDataPlanes:splanes];
        sbpr = [sepbitmap bytesPerRow];
        sbypplane = [sepbitmap bytesPerPlane];

        for (y=0; y<rows; y++)
        {   long	by = sbypplane - (y * sbpr) - sbpr; // sepImage height
            long	lby = bypplane - (y * bpr) - bpr; // original heigt

            for (x=0; x < sbpr; x++)
            {   long	c = 0, m = 0, y = 0, k = 0;

                if ([bmImageRep colorSpaceName] == NSCalibratedRGBColorSpace)
                {
                    c = 255 - ((pl) ? *((data[0]+lby+x)) : *((data[0]+lby+x*spp)));
                    m = 255 - ((pl) ? *((data[1]+lby+x)) : *((data[0]+lby+x*spp+1)));
                    y = 255 - ((pl) ? *((data[2]+lby+x)) : *((data[0]+lby+x*spp+2)));

                    if (c >= 253 && m >= 253 && y >= 253)
                    {   /* realy black */
                        c = 127;
                        m = y = 0;
                        k = 255;
                    }
                    else if (Min(c, Min(m, y)) > 1)
                    {   long	min = Min(c, Min(m, y));

                        k = min;
                        c -= min;
                        m -= min;
                        y -= min;
                   }
                }
                if (spp <= 2 && [sepColor blackComponent])
                    *((splanes[0]+by+x)) = (pl) ? *((data[0]+lby+x)) : *((data[0]+lby+x*spp)); // w 255-k
                else if ([bmImageRep colorSpaceName] == NSDeviceCMYKColorSpace && [sepColor blackComponent])
                    *((splanes[0]+by+x)) = 255 - ((pl) ? *((data[3]+lby+x)) : *((data[0]+lby+x*spp+3))); // 255-k
                else if ([sepColor blackComponent])
                    *((splanes[0]+by+x)) = 255 - k;
                else if ([bmImageRep colorSpaceName] == NSDeviceCMYKColorSpace && [sepColor cyanComponent])
                    *((splanes[0]+by+x)) = 255 - ((pl) ? *((data[0]+lby+x)) : *((data[0]+lby+x*spp))); // 255-c
                else if ([sepColor cyanComponent])
                    *((splanes[0]+by+x)) = 255 - c; // was r
                else if ([bmImageRep colorSpaceName] == NSDeviceCMYKColorSpace && [sepColor magentaComponent])
                    *((splanes[0]+by+x)) = 255 - ((pl) ? *((data[1]+lby+x)) : *((data[0]+lby+x*spp+1))); // 255-m
                else if ([sepColor magentaComponent])
                    *((splanes[0]+by+x)) = 255 - m; // was g
                else if ([bmImageRep colorSpaceName] == NSDeviceCMYKColorSpace && [sepColor yellowComponent])
                    *((splanes[0]+by+x)) = 255 - ((pl) ? *((data[2]+lby+x)) : *((data[0]+lby+x*spp+2))); // 255-y
                else if ([sepColor yellowComponent])
                    *((splanes[0]+by+x)) = 255 - y; // was b
            }
        }

        [sepImage addRepresentation:sepbitmap];
        [sepbitmap release];

        return sepImage;
    }
    return nil;
}

/*
 * draws the image
 */
- (void)drawWithPrincipal:principal
{   NSPoint		p;
    NSSize		currentSize;
    NSRect		bounds;
    float		scale = [principal scaleFactor];
    NSBezierPath	*bPath;
    NSRect		rect, visibleRect = [principal visibleRect];
    BOOL		releaseImage = NO;
    NSImage		*sepImage = nil; // color separated image

    if (size.width < 1.0 || size.height < 1.0)
        return;

    bounds.origin = origin;
    bounds.size = size;
    bounds.size.width *= scale;
    bounds.size.height *= scale;

    [super drawWithPrincipal:principal];	// set color

    if (image || thumbImage)
    {
        if (!VHFIsDrawingToScreen() && !image)
        {
            /* load image */
            if ([[NSFileManager defaultManager] fileExistsAtPath:sourcePath])
            {   image = [[NSImage allocWithZone:(NSZone *)[self zone]] init];
                [image addRepresentations:[NSImageRep imageRepsWithContentsOfFile:sourcePath]];
                [image setDataRetained:YES];
                [image setScalesWhenResized:YES];
                releaseImage = YES;
            }
            else
                return;
        }
        p = origin;
        currentSize = [((thumbImage && VHFIsDrawingToScreen())?thumbImage:image) size];
        if (currentSize.width != bounds.size.width || currentSize.height != bounds.size.height)
        {
            if ([((thumbImage && VHFIsDrawingToScreen())?thumbImage:image) scalesWhenResized])
                [((thumbImage && VHFIsDrawingToScreen())?thumbImage:image) setSize:bounds.size];
            else
            {
                p.x = origin.x + floor((bounds.size.width - currentSize.width) / 2.0 + 0.5);
                p.y = origin.y + floor((bounds.size.height - currentSize.height) / 2.0 + 0.5);
            }
        }

        /* Color separation
         */
        if (!VHFIsDrawingToScreen() && [principal separationColor])
        {
            if (!(sepImage = [self separateImageWithColor:[principal separationColor]]))
            {
                /* draw white clipPath */
                if (clipPath)
                {   NSColor	*oldFillColor = nil;
                    int		oldFill = [clipPath filled];
                    float	oldWidth = [clipPath width];

                    [clipPath setWidth:0.0];
                    [clipPath setFilled:1];
                    if (oldFill)
                        oldFillColor = [[clipPath fillColor] retain];
                    [clipPath setFillColor:[NSColor whiteColor]];
                    [clipPath drawWithPrincipal:principal]; // draw the white clipPath
                    [clipPath setFilled:oldFill];
                    [clipPath setWidth:oldWidth];
                    if (oldFill)
                    {   [clipPath setFillColor:oldFillColor];
                        [oldFillColor release];
                    }
                }
                else /* draw a white Rectangle */
                {   [[NSColor whiteColor] set];
                    NSRectFill(bounds);
                }
                if (releaseImage)
                {   [image release];
                    image = nil;
                }
                return;
            }
            currentSize = [sepImage size];
            if (currentSize.width != bounds.size.width || currentSize.height != bounds.size.height)
                [sepImage setSize:bounds.size];
        }

        /* clip and composite image
         */
        if (clipPath) // clip with clipPath gsave
        {
#ifdef USE_VHF_CLIPPING
            /* GNUstep (X11) doesn't support complex clipping
             * so we clip our image ourself
             * FIXME: We should do the complex clip only, if we have a complex path (?)
             */
            if (VHFIsDrawingToScreen())
            {
                if (sepImage /*&& !VHFIsDrawingToScreen() && [principal separationColor]*/)
                {   NSImage	*sepClipImage=nil;

                    if ( (sepClipImage = [self clipImage:sepImage withPath:clipPath scale:scale]) )
                    {   [sepClipImage setSize:NSMakeSize(floor(size.width*scale), floor(size.height*scale))];
                        [sepClipImage compositeToPoint:p operation:NSCompositeSourceOver];
                        [sepClipImage release];
                    }
                    [sepImage release];
                    return;
                }
                if ( clipImage ||
                     (clipImage = [self clipImage:((thumbImage) ? thumbImage : image)
                                         withPath:clipPath scale:scale]) )
                {
                    [clipImage setSize:NSMakeSize(floor(size.width*scale), floor(size.height*scale))];
                    [clipImage compositeToPoint:p operation:NSCompositeSourceOver];
                    return;
                }
            }
#endif
            bPath = [NSBezierPath bezierPath];
            PSgsave();
            [bPath setLineWidth:0.0];
            [bPath setLineCapStyle:NSRoundLineCapStyle];
            [bPath setLineJoinStyle:NSRoundLineJoinStyle];
            if ([clipPath isMemberOfClass:[VPath class]])
            {   int	i, cnt = [[clipPath list] count];
                NSPoint	currentPoint = NSMakePoint(LARGENEG_COORD, LARGENEG_COORD);

                for (i=0; i<cnt; i++)
                    currentPoint = [[[clipPath list] objectAtIndex:i] appendToBezierPath:bPath
                                                                            currentPoint:currentPoint];
            }
            else
            {   NSPoint	currentPoint = NSMakePoint(LARGENEG_COORD, LARGENEG_COORD);

                currentPoint = [clipPath appendToBezierPath:bPath currentPoint:currentPoint];
            }
            [bPath setWindingRule:NSEvenOddWindingRule];
            [bPath addClip];
        }
        /* ???
         if ([[image bestRepresentationForDevice:nil] isOpaque])
        {
            [[NSColor whiteColor] set];
            NSRectFill(bounds);
        }*/

        /* display or print
         */
#ifndef __APPLE__	// Apple has antialiasing
        if (!thumbnail && VHFIsDrawingToScreen() && [self compositeAntialiased:scale toPoint:p])
            return;
#endif
        if ([principal cache] && !sepImage) // not for colorseparation
        {   NSImage	*img = (thumbImage && VHFIsDrawingToScreen()) ? thumbImage : image;

            PSgsave();	// needed for GNUstep
            [img compositeToPoint:p operation:NSCompositeSourceOver];
            PSgrestore();
        }
        /* Color separation
         */
        else if ( (sepImage /*&& !VHFIsDrawingToScreen() && [principal separationColor]*/) ||
                  (bounds.size.width < 10000.0 && bounds.size.height < 10000.0)) // 10000 86000000
        {
            bounds.size = size; // important
#ifdef __APPLE__	// Apple works
            rect = bounds;
#else			// workaround for OpenStep
            rect = NSIntersectionRect(bounds, visibleRect);
#endif
            if (rect.size.width && rect.size.height)
            {   NSPoint	pOld = p;

                p = rect.origin;
                rect.origin.x = (rect.origin.x - pOld.x)*scale;
                rect.origin.y = (rect.origin.y - pOld.y)*scale;
                rect.size.width  *= scale; // important
                rect.size.height *= scale;

                if (sepImage /*&& !VHFIsDrawingToScreen() && [principal separationColor]*/)
                {   [sepImage compositeToPoint:p fromRect:rect operation:NSCompositeSourceOver];
                    [sepImage release];
                }
                else
                    [((thumbImage && VHFIsDrawingToScreen()) ? thumbImage : image)
                     compositeToPoint:p fromRect:rect operation:NSCompositeSourceOver];
            }
        }
        /* display huge images with work around
         * openstep doesnt work good if we draw more than 10 000 000 pixels
         * we draw here only the visible part
         */
        else
        {
            bounds.size = size; // important
#ifdef __APPLE__	// Apple works
            rect = bounds;
#else			// workaround for OpenStep
            rect = NSIntersectionRect(bounds, visibleRect);
#endif
            if (rect.size.width && rect.size.height)
            {   rect.size.width *= scale; // important
                rect.size.height *= scale;
                [self compositeInRect:rect toPoint:p withScale:scale];
            }
        }

        /* release print image */
        if (releaseImage)
        {   [image release];
            image = nil;
        }
        //if (dontCache && VHFIsDrawingToScreen())
        //    [image recache];
        if (clipPath)
            PSgrestore();
    }
}

/*
 * Returns the bounds.  The flag variable determines whether the
 * knobs should be factored in. They may need to be for drawing but
 * might not if needed for constraining reasons.
 */
- (NSRect)coordBounds
{   NSPoint	ll, ur;
    NSRect	bRect;

    ll.x = origin.x + ((size.width<0.0) ? size.width : 0.0);
    ll.y = origin.y + ((size.height<0.0) ? size.height : 0.0);
    ur.x = origin.x + ((size.width>0.0) ? size.width : 0.0);
    ur.y = origin.y + ((size.height>0.0) ? size.height : 0.0);

    bRect.origin = ll;
    bRect.size.width  = MAX(ur.x - ll.x, 0.1);
    bRect.size.height = MAX(ur.y - ll.y, 0.1);

    return bRect;
}

/*
 * Returns the bounds with the given rotation.
 */
- (NSRect)boundsAtAngle:(float)angle withCenter:(NSPoint)cp
{   NSPoint	p, ll, ur;
    NSRect	bRect;

    p = origin;
    vhfRotatePointAroundCenter(&p, cp, -angle);
    ll = ur = p;

    p.x = origin.x + size.width;
    vhfRotatePointAroundCenter(&p, cp, -angle);
    ll.x = Min(ll.x, p.x); ll.y = Min(ll.y, p.y);
    ur.x = Min(ur.x, p.x); ll.y = Min(ur.y, p.y);

    p.y = origin.y + size.height;
    vhfRotatePointAroundCenter(&p, cp, -angle);
    ll.x = Min(ll.x, p.x); ll.y = Min(ll.y, p.y);
    ur.x = Min(ur.x, p.x); ll.y = Min(ur.y, p.y);

    p = origin;
    p.y = origin.y + size.height;
    vhfRotatePointAroundCenter(&p, cp, -angle);
    ll.x = Min(ll.x, p.x); ll.y = Min(ll.y, p.y);
    ur.x = Min(ur.x, p.x); ll.y = Min(ur.y, p.y);

    bRect.origin = ll;
    bRect.size.width  = Max(ur.x - bRect.origin.x, 1.0);
    bRect.size.height = Max(ur.y - bRect.origin.y, 1.0);
    return bRect;
}

/*
 * Depending on the pt_num passed in, return the rectangle
 * that should be used for scrolling purposes. When the rectangle
 * passes out of the visible rectangle then the screen should
 * scroll. If the first and last points are selected, then the second
 * and third points are included in the rectangle. If the second and
 * third points are selected, then they are used by themselves.
 */
- (NSRect)scrollRect:(int)pt_num inView:(id)aView
{   float	knobsize;
    NSRect	aRect;

    if (pt_num == -1)
        aRect = [self bounds];
    else
    {	NSPoint	p;

        p = [self pointWithNum:pt_num];
        aRect.origin.x = p.x;
        aRect.origin.y = p.y;
        aRect.size.width = 0;
        aRect.size.height = 0;
    }

    knobsize = -[VGraphic maxKnobSizeWithScale:[aView scaleFactor]]/2.0;
    aRect = NSInsetRect(aRect , knobsize , knobsize);
    return aRect;
}

/* 
 * This method constains the point to the bounds of the view passed
 * in. Like the method above, the constaining is dependent on the
 * control point that has been selected.
 */
- (void)constrainPoint:(NSPoint *)aPt andNumber:(int)pt_num toView:(DocView*)aView
{   NSPoint	viewMax;
    NSRect	viewRect;

    viewRect = [aView bounds];
    viewMax.x = viewRect.origin.x + viewRect.size.width;
    viewMax.y = viewRect.origin.y + viewRect.size.height;

    viewMax.x -= MARGIN;
    viewMax.y -= MARGIN;
    viewRect.origin.x += MARGIN;
    viewRect.origin.y += MARGIN;

    aPt->x = MAX(viewRect.origin.x, aPt->x);
    aPt->y = MAX(viewRect.origin.y, aPt->y);

    aPt->x = MIN(viewMax.x, aPt->x);
    aPt->y = MIN(viewMax.y, aPt->y);
}

/*
 * created:   25.09.95
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions