; $Id: write_pict.pro,v 1.14 2001/01/15 22:28:15 scottm Exp $ ; ; Copyright (c) 1990-2001, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. pro write_pict_item, unit, data, key ; procedure write ; This procedure swaps bytes for short and long words on little endian ; machines. COMPILE_OPT hidden common write_pict_rev, rev if (key eq 0) or (rev eq 0) then begin writeu, unit, data return endif if (key eq 1) then begin x = data byteorder,x,/sswap writeu, unit, x endif else if (key eq 2) then begin x = data byteorder,x,/lswap writeu, unit, x endif else writeu, unit, data end FUNCTION PackData, image ; Function PackData ; This function is used by the WRITE_PICT user library routine and ; it performs the Quickdraw style run length encoding for PICT ; files. Image is the unpacked data. COMPILE_OPT hidden imagesize = SIZE(image) IF (imagesize[0] NE 2) THEN MESSAGE, "non two dimensional array passed to pack" width = FIX(imagesize[1]) height = FIX(imagesize[2]) retval = BYTARR((LONG(width) + 10L) * LONG(height), /NOZERO) retvalindex = 0L pack = bytarr(width * 1.5, /NOZERO) indexarray = lindgen(width) FOR scanline = height - 1, 0, -1 DO BEGIN in = image[*,scanline] IF width GT 250 THEN packindex = 2 ELSE packindex = 1 runstart = WHERE((in EQ in[1:*]) AND (in EQ in[2:*]), found) IF (found EQ 0) THEN runstart = width ELSE runstart = [runstart, width] inpind = 0 endrun = -1 FOR i = 0,N_ELEMENTS(runstart)-1 DO BEGIN ;For each run IF (endrun LT runstart[i]) THEN BEGIN WHILE inpind LT runstart[i] DO BEGIN ;Send out the bytes before it packlen = (runstart[i] - inpind) < 128 ;in 128 byte chunks pack[packindex] = packlen-1 pack[packindex+1:packindex+packlen] = in[inpind:inpind+packlen-1] packindex = packindex + packlen + 1 inpind = inpind + packlen ENDWHILE IF runstart[i] NE width THEN BEGIN runinds = WHERE((WHERE(in[runstart[i]] EQ in[runstart[i]:*]) EQ $ indexarray)) runsize = N_ELEMENTS(runinds) WHILE (runsize NE 0) DO BEGIN runlen = runsize < 128 pack[packindex] = 256 - (runlen - 1) pack[packindex+1] = in[runstart[i]] packindex = packindex + 2 inpind = inpind + runlen endrun = inpind runsize = runsize - runlen ENDWHILE ENDIF ENDIF ENDFOR IF WIDTH GT 250 THEN BEGIN pack[0] = (packindex - 2) / 256 pack[1] = (packindex - 2) mod 256 ENDIF ELSE BEGIN pack[0] = packindex - 1 ENDELSE retval[retvalindex:retvalindex + packindex - 1] = pack[0:packindex-1] retvalindex = retvalindex + packindex ENDFOR RETURN, retval[0:retvalindex - 1] END ;------------------------ end of PackData routine -------------------------- PRO WRITE_PICT, FILE, IMAGE, R, G, B ;+ ; NAME: WRITE_PICT ; PURPOSE: Writes image files with the current color palette in the PICT ; Version 2 Format. This format is used by Apple Macintosh ; Computers. ; CATEGORY: ; CALLING SEQUENCE: ; WRITE_PICT, FILE ;Writes contents of current window ; WRITE_PICT, FILE, IMAGE ;Writes given array ; WRITE_PICT, FILE, IMAGE, R, G, B ;Writes array w/given color table ; INPUTS: ; FILE = Scalar string giving the name of the PICT file to write. ; IMAGE = 2D matrix to be output. If IMAGE is omitted, ; the entire current window is read into an array and written ; to the PICT file. ; OPTIONAL INPUT PARAMETERS: ; R, G, B = The Red, Green, and Blue color vectors to be written ; with IMAGE. If not specified, the current color table is used ; OUTPUTS: ; FILE contains the image in a PICT version 2 file format. If color ; vectors were supplied, they are used. Otherwise, the last color tables ; established by LOADCT are used (If LOADCT hasn't been used ; to establish color tables yet it is used to load the B/W tables.). ; SIDE EFFECTS: ; If R, G, and B aren't supplied and LOADCT hasn't been called yet, ; this routine uses LOADCT to load the B/W tables. ; RESTRICTIONS: ; Only creates Version 2 PICT files. Only works with 8-bit displays ; PROCEDURE: ; Write out the header, size, and the following quickdraw opcodes: ; Version, HeaderOp, DefHilite, Clip, and PackBitsRect ; Then pack the image data using the QUICKDRAW PackBits ; run length encoding algorithm. ; Packing method: ; Each line is preceeded by a byte if the image width ; is less than 250 or a integer otherwise. This prefix ; tells how many bytes are in the packed line to follow. ; The line following this length descriptor is made up of ; a series of runs and data as follows: ; - Runs ; If there is a run, the high bit of the first byte is ; set and the other seven bits tell how many elements are ; in the run. The next byte is then the value of the run. ; Runs can only be 128 bytes in length so longer runs are ; broken up into smaller runs if they exceed 128 bytes. ; The smallest run is three bytes. ; - Data ; If there are a series of image values that differ at least ; every two bytes, they are written out after a byte that ; describes how many dissimilar data bytes are to follow. ; As with runs, the length of a run of data can not be ; longer than 128 without setting the high bit of the ; length descriptor so long strings of data are broken up ; into chunks 128 bytes or smaller. ; MODIFICATION HISTORY: ; Written 16 November 1990, Steve Richards. ; SMR, Aug 25, '92 Rewrote the packing routine and fixed bugs. ; JIY, Mar 30, '92 added fix to work on Ultrix and VMS. ; SMR, Oct 12, '93 Added changes suggested by Joe Gurman that ; prevented the clobbering of color vectors on ; exit from the routine. ; SMR, Jan 12, '94 Added a case for OSF byte ordering, suggested ; by Joe Gurman. ; DMS, Jun 24, 1994 Fixed byte ordering logic. ; Added code to clip image to # of colors-1 ;- common write_pict_rev, rev i = byte(1,0,2) ;Test byte ordering of this machine rev = i[0] eq 1b ;TRUE to reverse for little endian ON_ERROR, 2 ;Return to caller if error ; let user know about demo mode limitation. ; all write options disabled in demo mode if (LMGR(/DEMO)) then begin MESSAGE, 'OPENW: Feature disabled for demo mode.' return endif n_params = N_PARAMS(); ;Check the arguments IF (n_params EQ 1) THEN BEGIN ;if no image passed in, n_params = 2 ;Fake 2 param call IMAGE = TVRD() ;Read screen ENDIF IF ((n_params NE 2) AND (n_params NE 5)) THEN $ ;return error if args MESSAGE, "usage: WRITE_PICT, file, [IMAGE], [r,g,b]" ;were incorrect ; If any color vectors are supplied, do they have right attributes ? IF (n_params EQ 5) THEN BEGIN r_size = SIZE(r) g_size = SIZE(g) b_size = SIZE(b) IF ( (r_size[0] + g_size[0] + b_size[0]) NE 3) THEN $ MESSAGE, "R, G, & B must all be 1D vectors." IF ( (r_size[1] NE g_size[1]) OR (r_size[1] NE b_size[1]) ) THEN $ MESSAGE, "R, G, & B must all have the same length." ENDIF ELSE BEGIN tvlct, r,g,b,/GET ENDELSE r_mac = long(r) * 256L ;macs use ints for g_mac = long(g) * 256L ;color values so move b_mac = long(b) * 256L ;the values up arraysize = fix(SIZE(IMAGE)) ;make sure correct dimensions of image IF(arraysize[0] NE 2) THEN $ ;were used MESSAGE, "IMAGE must be a two dimensional matrix." if (!version.os EQ 'MacOS') then begin OPENW, unit, FILE, /GET_LUN,/STREAM, $ MACTYPE = "PICT" ;open the file for writing endif else begin OPENW, unit, FILE, /GET_LUN,/STREAM ;open the file for writing endelse hdr = BYTARR(512) ;pad the file with a 512 byte IMAGE write_pict_item, unit, hdr, 0 ;that contains nothing important imagesize = 0 ;integer padding for IMAGE size which write_pict_item, unit, imagesize,1 ;is ignored by version 2 PICT files Rect = {rect, top:0, left:0, bottom:arraysize[2], right:arraysize[1]} write_pict_item, unit, Rect, 1 opcode = 17 ;Version Opcode version = 2b ;This is a version 2 file lowbyte = 255b ;being written write_pict_item, unit, opcode, 1 write_pict_item, unit, version, 0 write_pict_item, unit, lowbyte, 0 opcode = 3072 ;HeaderOp Opcode headerdata = BYTE([[255,255,255,255],bytarr(20)]) write_pict_item, unit, opcode, 1 write_pict_item, unit, headerdata, 0 opcode = 30 ;DefHilite Opcode write_pict_item, unit, opcode, 1 opcode = 1 ;Clip Opcode regionsize = 10 clipregion = Rect write_pict_item, unit, opcode, 1 write_pict_item, unit, regionsize, 1 write_pict_item, unit, clipregion, 1 opcode = 152 ;PackBitsRect Opcode pixMap = {pixMapstr, $ rowBytes:fix(32768 + Rect.right),$ ;set high bit Boundtop:0, $ Boundleft:0, $ Boundbottom:Rect.bottom, $ Boundright:Rect.right, $ version:0, $ packType:0, $ packSize:0L, $ hRes:4718592L, $ vRes:4718592L, $ pixelType:0, $ pixelSize:8, $ cmpCount:1, $ cmpSize:8, $ planeBytes:0L, $ pmTable:0L, $ pmReserved:0L} colorlistsize = n_elements(r_mac) colorTable = {colorTablestr, ctseed:1038L, $ transIndex:0, $ ctSize:FIX(colorlistsize)-1} colors = INTARR(4, colorlistsize) colors[0,*] = INDGEN(colorlistsize) colors[1,*] = r_mac colors[2,*] = g_mac colors[3,*] = b_mac srcRect = Rect dstRect = Rect mode = 0 imagedata = byte(IMAGE) < byte(colorlistsize-1) ;Clip it IF(Rect.right GE 8) THEN BEGIN ;pack data imagedata = PackData(imagedata) ENDIF write_pict_item, unit, opcode, 1 write_pict_item, unit, pixmap.rowbytes, 1 write_pict_item, unit, pixmap.boundtop, 1 write_pict_item, unit, pixmap.boundleft, 1 write_pict_item, unit, pixmap.boundbottom, 1 write_pict_item, unit, pixmap.boundright, 1 write_pict_item, unit, pixmap.version, 1 write_pict_item, unit, pixmap.packtype, 1 write_pict_item, unit, pixmap.packsize, 1 write_pict_item, unit, pixmap.hres, 2 write_pict_item, unit, pixmap.vres, 2 write_pict_item, unit, pixmap.pixeltype, 1 write_pict_item, unit, pixmap.pixelsize, 1 write_pict_item, unit, pixmap.cmpcount, 1 write_pict_item, unit, pixmap.cmpsize, 1 write_pict_item, unit, pixmap.planebytes, 2 write_pict_item, unit, pixmap.pmtable, 2 write_pict_item, unit, pixmap.pmreserved, 2 write_pict_item, unit, colortable.ctseed, 2 write_pict_item, unit, colortable.transindex, 1 write_pict_item, unit, colortable.ctsize, 1 write_pict_item, unit, colors, 1 write_pict_item, unit, srcrect, 1 write_pict_item, unit, dstrect, 1 write_pict_item, unit, mode, 1 write_pict_item, unit, imagedata, 0 IF ((N_ELEMENTS(imagedata) MOD 2) NE 0) THEN $ write_pict_item, unit, 0B, 0 write_pict_item, unit, 255, 1 ;EOF Opcode FREE_LUN, unit END