'Ink Separation Generator 'Conceived and programmed by Shannon Larratt 'shannon@bmezine.com 'Ink properties: ' Transparency curve - How "opaque" (or "accurate") is an ink at a given saturation? ' Color - RGB color ' Sequence - Ink order is important 'Backing properties: ' Existance - Should the base (shirt/paper) color be used to compose the image? ' Color - RGB color 'TGA file format info: (Type 2: Uncompressed RGB image) ' Offset Description ' 0 Number of characters in identification field (often 0) ' 1 Color map type - Should be 0 (no color map) ' 2 Image type - Must be 2 ' 3 Color Map Specs (ignore) ' 8 X co-ord of lower-left corner (2 bytes, lo-hi) ' 10 Y co-ord of lower-left corner (2 bytes, lo-hi) ' 12 Width of image (2 bytes, lo-hi) ' 14 Height of image (2 bytes, lo-hi) ' 16 Image pixel size (should be 24 - RGB) ' 17 Image descriptor byte. Bits are: ' 0-3 Num of attribute bits; should be 0 ' 4 Reserved; must be 0 ' 5 Screen origin: 0 (lower left-hand), 1 (upper left-hand) ' 6-7 Interleaving (should be 00 / non-interleaved) ' 18 Image identification field (unless specified as 0 above) ' 18+ Image data field, BGR BGR BGR BGR BGR 'Raw process for separation generation - Do this for each pixel ' 0. See if this RGB color has a value in the lookup table ' 1. Start with all inks at 50% (15) saturation, and generate "score" (distance from true) ' 2. Generate THREE*NUMBEROFINKS new values (saturation up/same/down on each ink) and score them ' 3. If all are no better than current score, quit ' 4. Pick top score and jump to #2 TYPE Ink Red AS INTEGER Green AS INTEGER Blue AS INTEGER END TYPE DEFINT a-z DECLARE FUNCTION LoadTGA(TheFile$, ImgWidth, ImgHeight, ImageData()) DECLARE FUNCTION SaveTGA(TheFile$, ImgWidth, ImgHeight, ImageData()) DECLARE FUNCTION SaveInk(TheFile$, ImgWidth, ImgHeight, InkArray(), InkColor AS Ink) DECLARE FUNCTION Combine(Result AS Ink, Ink1 AS Ink, Ink1depth, Ink2 AS Ink, Ink2depth, Ink3 AS Ink, Ink3depth, Ink4 AS Ink, Ink4depth, Ink5 AS Ink, Ink5depth, Shirt AS Ink, Inks) DECLARE FUNCTION DisplayTGA(ImgWidth, ImgHeight, ImageData(), ForceScale) DECLARE FUNCTION Distance(Ink1 AS Ink, Ink2 AS Ink) 'How "far apart" are these two colors? DECLARE FUNCTION GetWord$(sentance$,wordno) FUNCTION PBMAIN() ON ERROR GOTO diediedie GLOBAL depth AS INTEGER GLOBAL depthminus AS INTEGER GLOBAL depthinverse AS INTEGER depth = 32: depthminus = 31: depthinverse = 8 DIM ImageData(1,1,1) 'Raw image data DIM Distances(1 TO 5, 1 TO 3) 'Distances for wandering match-finder DIM Lookup(0 TO 255, 0 TO 255, 0 TO 255) 'lookup table to speed up build DIM InkList(1 TO 25000, 1 TO 5) 'list of ink saturations for lookup table DIM Ink1array(1,1), Ink2array(1,1), Ink3array(1,1), Ink4array(1,1), Ink5array(1,1) DIM Ink1 AS Ink, Ink2 AS Ink, Ink3 AS Ink, Ink4 AS Ink, Ink5 AS Ink, Shirt AS Ink, Result AS Ink DIM TempInk AS Ink, FakeInk AS Ink Inks = 1: built = 0 Shirt.Red = 0: Shirt.Green = 0: Shirt.Blue = 0 Ink1.Red = 255: Ink1.Green = 255: Ink1.Blue = 255 cmd$ = "" DO SELECT CASE GetWord$(cmd$,1) CASE "cls" CLS CASE "load" x = LoadTGA(GetWord$(cmd$,2), ImgWidth, ImgHeight, ImageData()) built = 0 IF x <> 0 THEN REDIM Ink1array(ImgWidth, ImgHeight) REDIM Ink2array(ImgWidth, ImgHeight) REDIM Ink3array(ImgWidth, ImgHeight) REDIM Ink4array(ImgWidth, ImgHeight) REDIM Ink5array(ImgWidth, ImgHeight) END IF CASE "save" IF built = 1 THEN filebase$ = LCASE$(TRIM$(GetWord$(cmd$,2))) IF filebase$ = "" THEN STDOUT "ERROR: You didn't specify a filename." ELSE IF RIGHT$(filebase$, 4) = ".tga" THEN filebase$ = MID$(filebase$,1,LEN(filebase$)-4) END IF IF inks > 0 THEN SaveInk filebase$ & "-ink1.tga", ImgWidth, ImgHeight, Ink1Array(), Ink1 IF inks > 1 THEN SaveInk filebase$ & "-ink2.tga", ImgWidth, ImgHeight, Ink2Array(), Ink2 IF inks > 2 THEN SaveInk filebase$ & "-ink3.tga", ImgWidth, ImgHeight, Ink3Array(), Ink3 IF inks > 3 THEN SaveInk filebase$ & "-ink4.tga", ImgWidth, ImgHeight, Ink4Array(), Ink4 IF inks = 5 THEN SaveInk filebase$ & "-ink5.tga", ImgWidth, ImgHeight, Ink5Array(), Ink5 STDOUT "Separations saved. Building estimage"; REDIM Estimage(ImgWidth, ImgHeight + ((inks + 1) * 20), 1 TO 3) FOR r=1 TO ImgHeight STDOUT "."; FOR c=1 TO ImgWidth Combine TempInk, Ink1, Ink1Array(c,r)\depthinverse, Ink2, Ink2Array(c,r)\depthinverse, Ink3, Ink3Array(c,r)\depthinverse, Ink4, Ink4Array(c,r)\depthinverse, Ink5, Ink5Array(c,r)\depthinverse, Shirt, Inks Estimage(c,r,1) = TempInk.Red Estimage(c,r,2) = TempInk.Green Estimage(c,r,3) = TempInk.Blue NEXT NEXT FOR r = 0 TO inks FOR z = 1 TO 20 FOR c = 1 TO ImgWidth SELECT CASE r CASE 0 Estimage(c,ImgHeight + ((r) * 20) + z,1) = Shirt.Red Estimage(c,ImgHeight + ((r) * 20) + z,2) = Shirt.Green Estimage(c,ImgHeight + ((r) * 20) + z,3) = Shirt.Blue CASE 1 Estimage(c,ImgHeight + ((r) * 20) + z,1) = Ink1.Red Estimage(c,ImgHeight + ((r) * 20) + z,2) = Ink1.Green Estimage(c,ImgHeight + ((r) * 20) + z,3) = Ink1.Blue CASE 2 Estimage(c,ImgHeight + ((r) * 20) + z,1) = Ink2.Red Estimage(c,ImgHeight + ((r) * 20) + z,2) = Ink2.Green Estimage(c,ImgHeight + ((r) * 20) + z,3) = Ink2.Blue CASE 3 Estimage(c,ImgHeight + ((r) * 20) + z,1) = Ink3.Red Estimage(c,ImgHeight + ((r) * 20) + z,2) = Ink3.Green Estimage(c,ImgHeight + ((r) * 20) + z,3) = Ink3.Blue CASE 4 Estimage(c,ImgHeight + ((r) * 20) + z,1) = Ink4.Red Estimage(c,ImgHeight + ((r) * 20) + z,2) = Ink4.Green Estimage(c,ImgHeight + ((r) * 20) + z,3) = Ink4.Blue CASE 5 Estimage(c,ImgHeight + ((r) * 20) + z,1) = Ink5.Red Estimage(c,ImgHeight + ((r) * 20) + z,2) = Ink5.Green Estimage(c,ImgHeight + ((r) * 20) + z,3) = Ink5.Blue END SELECT NEXT NEXT NEXT SaveTGA filebase$ & "-estimage.tga", ImgWidth, (ImgHeight + ((inks + 1) * 20)), Estimage() STDOUT "Done" END IF ELSE STDOUT "ERROR: You must build the separations first." END IF CASE "display", "show" IF ImgWidth > 0 THEN DisplayTGA ImgWidth, ImgHeight, ImageData(), VAL(GetWord$(cmd$,2)) END IF CASE "build" IF ImgHeight = 0 THEN STDOUT "Load an image first!" ELSE STDOUT "Initializing inks"; SELECT CASE Inks CASE 1 REDIM InkResult(0 TO depthminus) AS Ink FOR r = 0 TO depthminus STDOUT "."; Combine InkResult(r), Ink1, r, Ink2, 0, Ink3, 0, Ink4, 0, Ink5, 0, Shirt, Inks NEXT CASE 2 REDIM InkResult(0 TO depthminus, 0 TO depthminus) AS Ink FOR r = 0 TO depthminus STDOUT "."; FOR s = 0 TO depthminus Combine InkResult(r,s), Ink1, r, Ink2, s, Ink3, 0, Ink4, 0, Ink5, 0, Shirt, Inks NEXT NEXT CASE 3 REDIM InkResult(0 TO depthminus, 0 TO depthminus, 0 TO depthminus) AS Ink FOR r = 0 TO depthminus STDOUT "."; FOR s = 0 TO depthminus FOR t = 0 TO depthminus Combine InkResult(r,s,t), Ink1, r, Ink2, s, Ink3, t, Ink4, 0, Ink5, 0, Shirt, Inks NEXT NEXT NEXT CASE 4 REDIM InkResult(0 TO depthminus, 0 TO depthminus, 0 TO depthminus, 0 TO depthminus) AS Ink FOR r = 0 TO depthminus STDOUT "."; FOR s = 0 TO depthminus FOR t = 0 TO depthminus FOR u = 0 TO depthminus Combine InkResult(r,s,t,u), Ink1, r, Ink2, s, Ink3, t, Ink4, u, Ink5, 0, Shirt, Inks NEXT NEXT NEXT NEXT CASE 5 REDIM InkResult(0 TO depthminus, 0 TO depthminus, 0 TO depthminus, 0 TO depthminus, 0 TO depthminus) AS Ink FOR r = 0 TO depthminus STDOUT "."; FOR s = 0 TO depthminus FOR t = 0 TO depthminus FOR u = 0 TO depthminus FOR v = 0 TO depthminus Combine InkResult(r,s,t,u,v), Ink1, r, Ink2, s, Ink3, t, Ink4, u, Ink5, v, Shirt, Inks NEXT NEXT NEXT NEXT NEXT END SELECT STDOUT STDOUT "Note: If this takes too long, index your image colors!" STDOUT "Analyzing/building image"; Inklookupat = 0 FOR row = 1 TO ImgHeight STDOUT "."; FOR col = 1 TO ImgWidth IF LookUp(ImageData(col, row, 1), ImageData(col, row, 2), ImageData(col, row, 3)) > 0 THEN 'already done Ink1Array(col, row) = InkList(LookUp(ImageData(col, row, 1), ImageData(col, row, 2), ImageData(col, row, 3)), 1) * depthinverse IF Inks > 1 THEN Ink2Array(col, row) = InkList(LookUp(ImageData(col, row, 1), ImageData(col, row, 2), ImageData(col, row, 3)), 2) * depthinverse IF Inks > 2 THEN Ink3Array(col, row) = InkList(LookUp(ImageData(col, row, 1), ImageData(col, row, 2), ImageData(col, row, 3)), 3) * depthinverse IF Inks > 3 THEN Ink4Array(col, row) = InkList(LookUp(ImageData(col, row, 1), ImageData(col, row, 2), ImageData(col, row, 3)), 4) * depthinverse IF Inks > 4 THEN Ink4Array(col, row) = InkList(LookUp(ImageData(col, row, 1), ImageData(col, row, 2), ImageData(col, row, 3)), 5) * depthinverse ELSE 'Try and find a good set. Slowness isn't a big issue due to look-up table 'FakeInk is the desired color FakeInk.Red = ImageData(col, row, 1) FakeInk.Green = ImageData(col, row, 2) FakeInk.Blue = ImageData(col, row, 3) Ink1sat = 0: Ink2sat = 0: Ink3sat = 0: Ink4sat = 0: Ink5sat = 0 SELECT CASE Inks BestDistance = Distance(InkResult(0), FakeInk) CASE 1 FOR r=0 TO depthminus ThisDistance = Distance(InkResult(r), FakeInk) IF ThisDistance < BestDistance THEN BestDistance = ThisDistance Ink1sat = r END IF NEXT CASE 2 BestDistance = Distance(InkResult(0,0), FakeInk) FOR r=0 TO depthminus FOR s=0 TO depthminus ThisDistance = Distance(InkResult(r,s), FakeInk) IF ThisDistance < BestDistance THEN BestDistance = ThisDistance Ink1sat = r Ink2sat = s END IF NEXT NEXT CASE 3 BestDistance = Distance(InkResult(0,0), FakeInk) FOR r=0 TO depthminus FOR s=0 TO depthminus FOR t=0 TO depthminus ThisDistance = Distance(InkResult(r,s,t), FakeInk) IF ThisDistance < BestDistance THEN BestDistance = ThisDistance Ink1sat = r Ink2sat = s Ink3sat = t END IF NEXT NEXT NEXT CASE 4 BestDistance = Distance(InkResult(0,0), FakeInk) FOR r=0 TO depthminus FOR s=0 TO depthminus FOR t=0 TO depthminus FOR u=0 TO depthminus ThisDistance = Distance(InkResult(r,s,t,u), FakeInk) IF ThisDistance < BestDistance THEN BestDistance = ThisDistance Ink1sat = r Ink2sat = s Ink3sat = t Ink4sat = u END IF NEXT NEXT NEXT NEXT CASE 5 BestDistance = Distance(InkResult(0,0), FakeInk) FOR r=0 TO 15 FOR s=0 TO 15 FOR t=0 TO 15 FOR u=0 TO 15 FOR v=0 TO 15 ThisDistance = Distance(InkResult(r,s,t,u,v), FakeInk) IF ThisDistance < BestDistance THEN BestDistance = ThisDistance Ink1sat = r Ink2sat = s Ink3sat = t Ink4sat = u Ink5sat = v END IF NEXT NEXT NEXT NEXT NEXT END SELECT IF InkLookupAt < 25000 THEN INCR InkLookupAt LookUp(ImageData(col, row, 1), ImageData(col, row, 2), ImageData(col, row, 3)) = InkLookupAt InkList(InkLookupAt, 1) = Ink1sat InkList(InkLookupAt, 2) = Ink2sat InkList(InkLookupAt, 3) = Ink3sat InkList(InkLookupAt, 4) = Ink4sat InkList(InkLookupAt, 5) = Ink5sat END IF Ink1Array(col, row) = Ink1sat * depth Ink2Array(col, row) = Ink2sat * depth Ink3Array(col, row) = Ink3sat * depth Ink4Array(col, row) = Ink4sat * depth Ink5Array(col, row) = Ink5sat * depth END IF NEXT NEXT STDOUT END IF built = 1 CASE "inks" Inks = VAL(GetWord$(cmd$,2)) IF Inks < 1 THEN Inks = 1 IF Inks > 5 THEN Inks = 5 STDOUT "Using inks 1 through " & FORMAT$(Inks) CASE "define" InkNo = VAL(GetWord$(cmd$,2)) Red = VAL(GetWord$(cmd$,3)) Green = VAL(GetWord$(cmd$,4)) Blue = VAL(GetWord$(cmd$,5)) SELECT CASE InkNo CASE 1 Ink1.Red = Red: Ink1.Green = Green: Ink1.Blue = Blue: Which$ = "Ink #1" CASE 2 Ink2.Red = Red: Ink2.Green = Green: Ink2.Blue = Blue: Which$ = "Ink #2" CASE 3 Ink3.Red = Red: Ink3.Green = Green: Ink3.Blue = Blue: Which$ = "Ink #3" CASE 4 Ink4.Red = Red: Ink4.Green = Green: Ink4.Blue = Blue: Which$ = "Ink #4" CASE 5 Ink5.Red = Red: Ink5.Green = Green: Ink5.Blue = Blue: Which$ = "Ink #5" CASE ELSE Shirt.Red = Red: Shirt.Green = Green: Shirt.Blue = Blue: Which$ = "Shirt" END SELECT STDOUT Which$ & " set to " & FORMAT$(Red) & ", " & FORMAT$(Green) & ", " & FORMAT$(Blue) & " (RGB)" CASE "exit", "quit" EXIT LOOP CASE "dir" x$ = DIR$("*.tga") DO IF x$ = "" THEN EXIT DO STDOUT x$ x$ = DIR$ LOOP CASE "cube" TheFile$ = LCASE$(GetWord$(cmd$,2)) IF LEN(TheFile$) < 1 THEN STDOUT "Error: You didn't specify a filename to output to." ELSE IF LEN(TheFile$)>3 THEN IF RIGHT$(TheFile$, 4) <> ".tga" THEN TheFile$ = TheFile$ & ".tga" END IF ELSE TheFile$ = TheFile$ & ".tga" END IF InkNo = VAL(GetWord$(cmd$,3)) IF InkNo = 0 THEN InkNo = 1 END IF DO IF (InkNo + 1) > Inks THEN InkNo = InkNo - 1 ELSE EXIT DO END IF LOOP IF InkNo = 0 THEN InkNo = 1 END IF STDOUT "Outputting cube for shirt color plus inks " & FORMAT$(InkNo) & " and " & FORMAT$(InkNo+1) & "..."; REDIM ImageData(1 TO depth, 1 TO depth, 1 TO 3) FOR r=1 TO depth FOR c=1 TO depth SELECT CASE InkNo CASE 1 Combine TempInk, Ink1, r, Ink2, c, Ink3, 0, Ink4, 0, Ink5, 0, Shirt, Inks CASE 2 Combine TempInk, Ink1, 0, Ink2, r, Ink3, c, Ink4, 0, Ink5, 0, Shirt, Inks CASE 3 Combine TempInk, Ink1, 0, Ink2, 0, Ink3, r, Ink4, c, Ink5, 0, Shirt, Inks CASE 4 Combine TempInk, Ink1, 0, Ink2, 0, Ink3, 0, Ink4, r, Ink5, c, Shirt, Inks END SELECT ImageData(c,r,1) = TempInk.Red ImageData(c,r,2) = TempInk.Green ImageData(c,r,3) = TempInk.Blue NEXT NEXT SaveTGA TheFile$, depth, depth, ImageData() STDOUT "Done" END IF CASE "depth" SELECT CASE VAL(GetWord$(cmd$,2)) CASE 2 depth = 2: depthminus = 1: depthinverse = 128 CASE 4 depth = 4: depthminus = 3: depthinverse = 64 CASE 8 depth = 8: depthminus = 7: depthinverse = 32 CASE 16 depth = 16: depthminus = 15: depthinverse = 16 CASE 32 depth = 32: depthminus = 31: depthinverse = 8 CASE 64 depth = 64: depthminus = 63: depthinverse = 4 CASE 128 depth = 128: depthminus = 127: depthinverse = 2 CASE 256 depth = 256: depthminus = 255: depthinverse = 1 CASE ELSE STDOUT "Error: Must be a ^2. Using current." END SELECT STDOUT "Using a saturation resolution of " & FORMAT$(depth) & "." CASE "" CASE ELSE STDOUT "load filename - Load type 2 TGA file" STDOUT "save basename - Save separations (and ""guestimate"")" STDOUT "display scalefactor- Quick ASCII display of file" STDOUT "build - Attempt to build separations" STDOUT "inks number - Tell program how many inks to use" STDOUT "dir - Show TGAs in this directory" STDOUT "define ink r g b - define an ink (ink# and RGB value), 0=shirt" STDOUT "cube filename [ink]- output 2D color cube, starting at ink#" STDOUT "cls - clearscreen if things start overflowing" STDOUT "depth value - saturation resolution: 2/4/8/16/[32]/64/128/256" STDOUT "exit - quit" END SELECT LINE INPUT "screener> ", cmd$ LOOP EXIT FUNCTION diediedie: STDOUT STDOUT STDOUT "ERROR: " & FORMAT$(ERR) STDOUT ' LoadTGA COMMAND$, ImgWidth, ImgHeight, ImageData() ' DisplayTGA ImgWidth, ImgHeight, ImageData() ' SaveTGA "test-out.tga", ImgWidth, ImgHeight, ImageData() END FUNCTION FUNCTION DisplayTGA(ImgWidth, ImgHeight, ImageData(), ForceScale) CONSOLE SCREEN 45, 111 divider = (ImgWidth \ 110) + 1 IF divider < ForceScale THEN divider = ForceScale IF divider > 1 THEN PRINT "Warning: Image shrunk by a factor of " & FORMAT$(divider) FOR row = 1 TO ImgHeight STEP divider FOR col = 1 TO ImgWidth STEP divider thiscol1 = 0: thiscol2 = 0 IF ImageData(col, row, 1) > 160 THEN thiscol1 = 12 ELSEIF ImageData(col, row, 1) > 90 THEN thiscol1 = 4 END IF IF ImageData(col, row, 2) > 160 THEN 'bright green IF ImageData(col, row, 3) > 160 THEN thiscol2 = 11 ELSEIF ImageData(col, row, 3) > 90 THEN thiscol2 = 10 ELSE thiscol2 = 10 END IF ELSEIF ImageData(col, row, 2) > 90 THEN 'dark green IF ImageData(col, row, 3) > 160 THEN thiscol2 = 9 ELSEIF ImageData(col, row, 3) > 90 THEN thiscol2 = 2 ELSE thiscol2 = 2 END IF ELSE 'black green IF ImageData(col, row, 3) > 160 THEN thiscol2 = 9 ELSEIF ImageData(col, row, 3) > 90 THEN thiscol2 = 1 END IF END IF ' LOCATE row, col COLOR thiscol1, thiscol2 PRINT CHR$(178); NEXT COLOR 7, 0 PRINT NEXT COLOR 7, 0 PRINT END FUNCTION FUNCTION LoadTGA(TheFile$, ImgWidth, ImgHeight, ImageData()) 'First, make sure the file exists of course x$ = DIR$(TheFile$) IF x$ = "" THEN STDOUT "LoadTGA error: File not found." LoadTGA = 0 EXIT FUNCTION END IF 'Open it and make sure it's at least long enough to grab a header ff = FREEFILE OPEN TheFile$ FOR BINARY AS #ff BASE = 0 IF LOF(ff) < 20 THEN STDOUT "LoadTGA error: Does not appear to be a valid TGA file." CLOSE #ff LoadTGA = 0 EXIT FUNCTION END IF 'Suck in the header GET$ #ff, 1, x$: IDlength = ASC(x$) 'Image ID length GET$ #ff, 1, x$: CmapType = ASC(x$) 'Color map type (should be 0) GET$ #ff, 1, x$: ImageType = ASC(x$) 'Image type (must be 2) SEEK #ff, 8: GET$ #ff, 2, x$: Xstart = CVI(x$) 'Lower left corner (x) GET$ #ff, 2, x$: Ystart = CVI(x$) 'Lower left corner (y) GET$ #ff, 2, x$: ImgWidth = CVI(x$) 'Image width GET$ #ff, 2, x$: ImgHeight = CVI(x$) 'Image height GET$ #ff, 1, x$: Bits = ASC(x$) 'Should be 24 GET$ #ff, 1, x$: ImageDescriptor = CVI(x$) 'All bits should be 0 except 5 (0 for lower start, 1 for upper) IF IDlength > 0 THEN GET$ #ff, IDlength, ImageID$ ELSE ImageID$ = "" END IF 'Verify that header data is valid IF CmapType <> 0 THEN STDOUT "LoadTGA error: Contains color map. Invalid TGA file type." CLOSE #ff LoadTGA = 0 EXIT FUNCTION ELSEIF ImageType <> 2 THEN STDOUT "LoadTGA error: Invalid TGA type. Must be type 2 (RGB uncompressed)." CLOSE #ff LoadTGA = 0 EXIT FUNCTION ELSEIF ImgWidth > 5000 OR ImgHeight > 5000 OR ImgWidth < 1 OR ImgHeight < 1 THEN STDOUT "LoadTGA error: Invalid size. Must be between 1x1 and 5000x5000 pixels." CLOSE #ff LoadTGA = 0 EXIT FUNCTION ELSEIF Bits <> 24 THEN STDOUT "LoadTGA error: Must be a 24-bit RGB image." CLOSE #ff LoadTGA = 0 EXIT FUNCTION ELSEIF ImgWidth * ImgHeight + 18 + IDlength > LOF(1) THEN STDOUT "LoadTGA error: File corrupt. Not all image data is present." CLOSE #ff LoadTGA = 0 EXIT FUNCTION END IF 'Header data is valid, suck in the image REDIM ImageData(ImgWidth, ImgHeight, 1 TO 3) IF BIT(ImageDescriptor, 5) = 1 THEN startrow = 1: endrow = ImgHeight: rowstep = 1 ELSE startrow = ImgHeight: endrow = 1: rowstep = -1 END IF STDOUT "Loading TGA"; FOR row = startrow TO endrow STEP rowstep STDOUT "."; FOR col = 1 TO ImgWidth GET$ #ff, 1, x$: ImageData(col, row, 3) = ASC(x$) GET$ #ff, 1, x$: ImageData(col, row, 2) = ASC(x$) GET$ #ff, 1, x$: ImageData(col, row, 1) = ASC(x$) NEXT NEXT STDOUT CLOSE #ff STDOUT "TGA data successfully loaded (" & FORMAT$(ImgWidth) & "x" & FORMAT$(ImgHeight) & ")" LoadTGA = 1 END FUNCTION FUNCTION SaveInk(TheFile$, ImgWidth, ImgHeight, InkArray(), InkColor AS Ink) ff = FREEFILE OPEN TheFile$ FOR BINARY AS #ff InkDescript$ = "RGB = " & FORMAT$(InkColor.Red) & ", " & FORMAT$(InkColor.Green) & ", " & FORMAT$(InkColor.Blue) PUT$ #ff, CHR$(LEN(InkDescript$), 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0) 'Up to offset 11 PUT$ #ff, MKI$(ImgWidth+2) 'Offset 12-13 PUT$ #ff, MKI$(ImgHeight+2) 'Offset 14-15 PUT$ #ff, CHR$(24) 'Offset 16 PUT$ #ff, CHR$(0) 'Offset 17 PUT$ #ff, InkDescript$ 'Comment field (specifies the ink) FOR col = 1 TO ImgWidth+2 PUT$ #ff, CHR$(255,255,255) NEXT FOR row = ImgHeight TO 1 STEP -1 PUT$ #ff, CHR$(255,255,255) FOR col = 1 TO ImgWidth PUT$ #ff, CHR$(InkArray(col, row)) PUT$ #ff, CHR$(InkArray(col, row)) PUT$ #ff, CHR$(InkArray(col, row)) NEXT PUT$ #ff, CHR$(255,255,255) NEXT FOR col = 1 TO ImgWidth+2 PUT$ #ff, CHR$(255,255,255) NEXT CLOSE #ff STDOUT "Ink file " & TheFile$ & " saved." END FUNCTION FUNCTION SaveTGA(TheFile$, ImgWidth, ImgHeight, ImageData()) ff = FREEFILE OPEN TheFile$ FOR BINARY AS #ff PUT$ #ff, CHR$(0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0) 'Up to offset 11 PUT$ #ff, MKI$(ImgWidth) 'Offset 12-13 PUT$ #ff, MKI$(ImgHeight) 'Offset 14-15 PUT$ #ff, CHR$(24) 'Offset 16 PUT$ #ff, CHR$(0) 'Offset 17 FOR row = ImgHeight TO 1 STEP -1 FOR col = 1 TO ImgWidth PUT$ #ff, CHR$(ImageData(col, row, 3)) PUT$ #ff, CHR$(ImageData(col, row, 2)) PUT$ #ff, CHR$(ImageData(col, row, 1)) NEXT NEXT CLOSE #ff END FUNCTION FUNCTION Combine(Result AS Ink, Ink1 AS Ink, Ink1depth, Ink2 AS Ink, Ink2depth, Ink3 AS Ink, Ink3depth, Ink4 AS Ink, Ink4depth, Ink5 AS Ink, Ink5depth, Shirt AS Ink, Inks) 'Result is the output color 'Ink# is the ink color 'Ink#depth is the saturation of the color (0 to depthminus) 'Shirt is the color of the shirt itself 'Inks is the number of inks '==Initialize "Virtual Shirt" DIM TempInk(0 TO depthminus) AS Ink FOR r = 0 TO depthminus: TempInk(r) = Shirt: NEXT '==Print the "Virtual Inks" IF Inks > 0 AND Ink1Depth <= depthminus THEN FOR r = 0 TO Ink1Depth-1: TempInk(r) = Ink1: NEXT IF Ink1Depth = depthminus THEN TempInk(depthminus) = Ink1 END IF IF Inks > 1 AND Ink2Depth <= depthminus THEN FOR r = 0 TO Ink2Depth-1: TempInk(r) = Ink2: NEXT IF Ink2Depth = depthminus THEN TempInk(depthminus) = Ink2 END IF IF Inks > 2 AND Ink3Depth <= depthminus THEN FOR r = 0 TO Ink3Depth-1: TempInk(r) = Ink3: NEXT IF Ink3Depth = depthminus THEN TempInk(depthminus) = Ink3 END IF IF Inks > 3 AND Ink4Depth <= depthminus THEN FOR r = 0 TO Ink4Depth-1: TempInk(r) = Ink4: NEXT IF Ink4Depth = depthminus THEN TempInk(depthminus) = Ink4 END IF IF Inks > 4 AND Ink5Depth <= depthminus THEN FOR r = 0 TO Ink5Depth-1: TempInk(r) = Ink5: NEXT IF Ink5Depth = depthminus THEN TempInk(depthminus) = Ink5 END IF '==Clear the result Result.Red = 0 Result.Green = 0 Result.Blue = 0 '==Try and build the average FOR r = 0 TO depthminus Result.Red = Result.Red + TempInk(r).Red Result.Green = Result.Green + TempInk(r).Green Result.Blue = Result.Blue + TempInk(r).Blue NEXT Result.Red = Result.Red \ depth Result.Green = Result.Green \ depth Result.Blue = Result.Blue \ depth END FUNCTION FUNCTION Distance(Ink1 AS Ink, Ink2 AS Ink) 'How "far apart" are these two colors? Red = ABS(Ink1.Red) - ABS(Ink2.Red) Green = ABS(Ink1.Green) - ABS(Ink2.Green) Blue = ABS(Ink1.Blue) - ABS(Ink2.Blue) Distance = SQR(Red^2 + Green^2 + Blue^2) END FUNCTION FUNCTION GetWord$(sentance$,wordno) 'get word# from sentance currentrest$=TRIM$(sentance$) DO 'remove double spaces REPLACE " " WITH " " IN currentrest$ IF INSTR(currentrest$," ")=0 THEN EXIT DO LOOP IF currentrest$="" THEN 'Blank! No words available! GetWord$="" EXIT FUNCTION END IF space=INSTR(currentrest$," ") IF space=0 THEN 'Just one word IF wordno=1 THEN 'good, that's all we needed GetWord$=currentrest$ ELSE GetWord$="" 'No other words available END IF EXIT FUNCTION END IF currentword$ = MID$(currentrest$,1,space-1) 'get current first word currentrest$ = TRIM$(MID$(currentrest$,space+1)) 'and get the rest (trim double spaces) currentat = 1 'word at DO IF currentat=wordno THEN 'we've got the one we want GetWord$=currentword$ EXIT FUNCTION END IF INCR currentat space=INSTR(currentrest$," ") IF space=0 THEN 'reached end of sentance currentword$=currentrest$ currentrest$="" 'clear for next step (last chance!) ELSE currentword$ = MID$(currentrest$,1,space-1) 'get current first word currentrest$ = TRIM$(MID$(currentrest$,space+1)) 'and get the rest (trim double spaces) END IF LOOP UNTIL currentword$="" 'until reached end of sentance GetWord$="" END FUNCTION