/* This file is part of pathtotext, a Filter plugin for Adobe Illustrator Copyright (C) 2005-9 Toby Thain, toby@telegraphics.com.au This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include // Hack required because FSSpec is defined among AI headers as well. // Prevent the conflict with our type. #define FSSpec AI_FSSpec #include "aipluginmain.h" #include "common.h" // must come before aipluginmain.h #undef FSSpec #include "str.h" #include "choosefile.h" #include "file_compat.h" #include "version.h" AIBlockSuite *sBlock; AIMatchingArtSuite *sMatch; AIFixedMathSuite *sMath; #ifdef kAIRealMathSuite AIRealMathSuite *sRealMath; #endif AIArtSuite *sArt; AIPathSuite *sPath; AIPathStyleSuite *sPathStyle; AIMdMemorySuite *sMdMemory; ADMBasicSuite *sADMBasic; FILEREF outfile; NavReplyRecord reply; /* prototypes, to keep the compiler happy */ int pf(const char *fmt, ...); int pp(pt *p,const char *note); AIErr acquire_suites( SPMessageData *m ) { AIErr e; (e = acq_suite(m,kAIBlockSuite,kAIBlockVersion,(ppsuite)&sBlock) ) || (e = acq_suite(m,kAIMatchingArtSuite,kAIMatchingArtVersion,(ppsuite)&sMatch) ) || (e = acq_suite(m,kAIFixedMathSuite,kAIFixedMathVersion,(ppsuite)&sMath) ) #ifdef kAIRealMathSuite || (e = acq_suite(m,kAIRealMathSuite,kAIRealMathVersion,(ppsuite)&sRealMath) ) #endif || (e = acq_suite(m,kAIPathSuite,kAIPathVersion,(ppsuite)&sPath) ) || (e = acq_suite(m,kAIPathStyleSuite,kAIPathStyleVersion,(ppsuite)&sPathStyle) ) || (e = acq_suite(m,kAIArtSuite,kAIArtVersion,(ppsuite)&sArt) ) || (e = acq_suite(m,kAIMdMemorySuite,kAIMdMemoryVersion,(ppsuite)&sMdMemory) ) || (e = acq_suite(m,kADMBasicSuite,kADMBasicSuiteVersion,(ppsuite)&sADMBasic) ) ; return e; } AIErr release_suites( SPMessageData *m ) { m->basic->ReleaseSuite(kAIBlockSuite,kAIBlockVersion); m->basic->ReleaseSuite(kAIMatchingArtSuite,kAIMatchingArtVersion); m->basic->ReleaseSuite(kAIFixedMathSuite,kAIFixedMathVersion); #ifdef kAIRealMathSuite m->basic->ReleaseSuite(kAIRealMathSuite,kAIRealMathVersion); #endif m->basic->ReleaseSuite(kAIPathSuite,kAIPathVersion); m->basic->ReleaseSuite(kAIPathStyleSuite,kAIPathStyleVersion); m->basic->ReleaseSuite(kAIArtSuite,kAIArtVersion); m->basic->ReleaseSuite(kAIMdMemorySuite,kAIMdMemoryVersion); m->basic->ReleaseSuite(kADMBasicSuite,kADMBasicSuiteVersion); return kNoErr; } AIErr plugin_startup(SPInterfaceMessage *im){ AIErr e; PlatformAddFilterData fd; AIFilterHandle fh; AIFilterSuite *sfilter; Str255 cat,title; if( !(e = acq_suite(&im->d,kAIFilterSuite,kAIFilterVersion,(ppsuite)&sfilter) ) ){ // gcc (mingw32) doesn't support "\p" Pascal string constants // but these two fields are Pascal-style strings (first byte is length). // Interestingly, pointing to a string constant such as "\014Telegraphics" // does *not* work on Windows - some runtime quirk? fd.category = myc2pstrcpy(cat,"Telegraphics"); fd.title = myc2pstrcpy(title,"Path to text"); if( e = sfilter->AddFilter( im->d.self,"telegraphics-pathtotext",&fd,0,&fh) ) dbg("plugin_startup: AddFilter failed"); im->d.basic->ReleaseSuite(kAIFilterSuite,kAIFilterVersion); } return e; } AIErr plugin_shutdown(SPInterfaceMessage *im){ return kNoErr; } AIErr plugin_about(SPInterfaceMessage *im){ AIErr e; ADMBasicSuite *admbasic; if( !(e = acq_suite(&im->d,kADMBasicSuite,kADMBasicSuiteVersion,(ppsuite)&admbasic) ) ){ admbasic->MessageAlert("pathtotext " VERSION_STR "\n" "Copyright (C) 2005-9 Toby Thain \n" "http://www.telegraphics.com.au/"); im->d.basic->ReleaseSuite(kADMBasicSuite,kADMBasicSuiteVersion); } return e; } int pf(const char *fmt, ...){ char s[0x100]; va_list v; long count; va_start(v,fmt); count = vsprintf(s,fmt,v); va_end(v); return FSWRITE(outfile,&count,s); } int pp(pt *p,const char *note){ return pf("%14.4f\t%14.4f\t%s\015\012",FLT(p->h),FLT(p->v),note); } AIErr do_art(SPMessageData *m,AIArtHandle path){ short n; AIErr e = kNoErr; AIPathSegment *in_segs,*seg; AIBoolean closed; AIPathStyle style; if( !(e = sPath->GetPathSegmentCount(path,&n)) && !(e = sPath->GetPathClosed(path,&closed)) ) { if( ! sPathStyle->GetPathStyle(path,&style) ){ // 'note' field of AIPathStyle not supported in Illustrator 8 and later // myp2cstr(style.note) /* in 4th column, give number of points; * in 5th, whether the path is closed (joined back to starting point); * in 6th and 7th, whether it is filled and stroked respectively; * and in 8th, the Note attribute string, if set. */ e = pf(" \t \tpoints:\t%d\t%s\t%s\t%s\015\012", n,closed?"closed":"",style.fillPaint?"filled":"",style.strokePaint?"stroked":""); } if( !e && n && !(e = sBlock->AllocateBlock(sizeof(AIPathSegment)*n,(void**)&in_segs)) ){ if( !(e = sPath->GetPathSegments(path,0,n,in_segs)) ){ for (seg = in_segs ; n-- ; seg++) { if(!POINTEQUAL(&seg->in,&seg->p)) if(e = pp(&seg->in,"in")) break; /* print the 'in' control point */ /* print anchor point, and if it's a 'corner' point, say so */ if(e = pp(&seg->p, seg->corner ? "corner" : "")) break; if(!POINTEQUAL(&seg->out,&seg->p)) if(e = pp(&seg->out,"out")) break; /* print the 'out' control point */ } } sBlock->DisposeBlock(in_segs); } if(!e) e = pf("\015\012"); } return e; } AIErr filter_go( AIFilterMessage *fm ) { SPMessageData *m = &fm->d; AIArtHandle **matches,*p; long n,i; AIErr e = kNoErr; AIMatchingArtSpec spec; void *pmatches; StandardFileReply sfr; if( !(e = acquire_suites(m)) ){ spec.type = kPathArt; spec.whichAttr = spec.attr = kArtSelected; if( !(e = sMatch->GetMatchingArt( &spec,1,&matches,&n )) && matches ) { if(putfile((StringPtr)"\013Save points",(StringPtr)"\016pathtotext.txt",'TEXT','ttxt',&reply,&sfr, "TXT","Text file (.TXT)\0*.TXT\0\0",1)){ FSpCreate(&sfr.sfFile,'ttxt','TEXT',sfr.sfScript); /* ignore any error - most likely due to pre-existing file */ if( !(e = FSpOpenDF(&sfr.sfFile,fsWrPerm,&outfile)) && !(e = SetEOF(outfile,0)) /* truncate file to empty */ && !(e = pf(" X\t Y\tpaths:\t%d\015\012",n)) ) { sMdMemory->MdMemoryLock((AIMdMemoryHandle)matches,&pmatches); for( i = n, p = (AIArtHandle*)pmatches ; i-- ; ) if(e = do_art(m,*p++)) break; /* here's a good place to update progress bar */ sMdMemory->MdMemoryDisposeHandle((AIMdMemoryHandle)matches); FSClose(outfile); completesave(&reply); } } } release_suites( m ); } return e; }