! File: fire2.f90 ! Public domain 2006 James Van Buskirk module bitmap_types implicit none integer, parameter :: ik1 = selected_int_kind(2) integer, parameter :: ik2 = selected_int_kind(4) integer, parameter :: ik4 = selected_int_kind(9) integer, parameter :: ik8 = selected_int_kind(18) integer, parameter :: sp = selected_real_kind(6,30) integer, parameter :: dp = selected_real_kind(15,300) type BITMAPFILEHEADER SEQUENCE ! df & ifort pack SEQUENCE types by default; lf95 & g95 do not ! integer(ik2) bfType ! signature word "BM" or Z'4d42' ! integer(ik4) bfSize ! entire size of file ! integer(ik2) bfReserved1 ! must be zero ! integer(ik2) bfReserved2 ! must be zero ! integer(ik4) bfOffsetBits ! offset in file of DIB pixel bits integer(ik2) bfType ! signature word "BM" or Z'4d42' integer(ik2) bfSize(2) ! entire size of file integer(ik2) bfReserved1 ! must be zero integer(ik2) bfReserved2 ! must be zero integer(ik2) bfOffsetBits(2) ! offset in file of DIB pixel bits end type BITMAPFILEHEADER type RGBQUAD SEQUENCE integer(ik1) rgbBlue ! blue level integer(ik1) rgbGreen ! green level integer(ik1) rgbRed ! red level integer(ik1) rgbReserved ! = 0 end type RGBQUAD type CIEXYZ SEQUENCE integer(ik4) ciexyzX integer(ik4) ciexyzY integer(ik4) ciexyzZ end type CIEXYZ type CIEXYZTRIPLE SEQUENCE type(CIEXYZ) ciexyzRed type(CIEXYZ) ciexyzGreen type(CIEXYZ) ciexyzBlue end type CIEXYZTRIPLE type BITMAPV5HEADER SEQUENCE integer(ik4) bV5Size ! size of the structure = 120 (124?) integer(ik4) bV5Width ! width of the image in pixels integer(ik4) bV5Height ! height of the image in pixels integer(ik2) bV5Planes ! = 1 integer(ik2) bV5BitCount ! bits per pixel (1, 4, 8, 16, 24, or 32) integer(ik4) bV5Compression ! compression code integer(ik4) bV5SizeImage ! number of bytes in image integer(ik4) bV5XPelsPerMeter ! horizontal resolution integer(ik4) bV5YPelsPerMeter ! vertical resolution integer(ik4) bV5ClrUsed ! number of colors used integer(ik4) bV5ClrImportant ! number of important colors integer(ik4) bV5RedMask ! Red color mask integer(ik4) bV5GreenMask ! Green color mask integer(ik4) bV5BlueMask ! Blue color mask integer(ik4) bV5AlphaMask ! Alpha mask integer(ik4) bV5CSType ! color space type type(CIEXYZTRIPLE) bV5EndPoints ! XYZ values integer(ik4) bV5GammaRed ! Red gamma value integer(ik4) bV5GammaGreen ! Green gamma value integer(ik4) bV5GammaBlue ! Blue gamma value integer(ik4) bV5Intent ! rendering intent integer(ik4) bV5ProfileData ! profile data or filename integer(ik4) bV5ProfileSize ! size of embedded data or filename integer(ik4) bV5Reserved end type BITMAPV5HEADER end module bitmap_types module chk_ftn95 implicit none private public is_ftn95 interface operator(.NEQV.) module procedure my_neqv end interface operator(.NEQV.) contains elemental function my_neqv(a,b) logical my_neqv integer, intent(in) :: a, b my_neqv = (a == 0 .AND. b /= 0) .OR. & (a /= 0 .AND. b == 0) end function my_neqv function is_ftn95() logical is_ftn95 integer a, b a = 2 b = 4 if(a .NEQV. b) then is_ftn95 = .TRUE. else is_ftn95 = .FALSE. end if end function is_ftn95 end module chk_ftn95 module chk_g95 implicit none private public is_g95 type t integer x end type t interface assignment(=) module procedure assign_t end interface assignment(=) contains function is_g95() logical is_g95 type(t) y(3) y%x = (/1,2,3/) y = y((/2,3,1/)) is_g95 = y(3)%x == 1 end function is_g95 elemental subroutine assign_t(lhs,rhs) type(t), intent(in) :: rhs type(t), intent(out) :: lhs lhs%x = rhs%x end subroutine assign_t end module chk_g95 program fire use bitmap_types use chk_ftn95 use chk_g95 implicit none type(BITMAPFILEHEADER) bmp_file_header type(RGBQUAD), allocatable :: palette(:) type(BITMAPV5HEADER) bmp_header integer RowLength, ColHeight integer(ik1), allocatable :: image(:,:) integer bfOffsetBits integer bfSize integer i, j integer PelsPerMeter real(dp) lambda integer x0, y0 real(dp) f real(dp) r real(dp) width real(dp) height character(20) access, form integer DPI character(80) flt_err character(80) line integer line_size logical dither, apodize real(dp) harvest(2) real(dp) r0 real(dp) sigma real(dp) r12 real(dp) r1 ! ************************************* ! Create *.BMP file header ! File type code bmp_file_header%bfType = transfer('BM',bmp_file_header%bfType) ! (Done later) store entire size of file bmp_file_header%bfSize = transfer(0,bmp_file_header%bfSize) ! Reserved words alwys 0 bmp_file_header%bfReserved1 = 0_ik2 bmp_file_header%bfReserved2 = 0_ik2 ! (Done later) store offset in file of DIB pixel bits bmp_file_header%bfOffsetBits = transfer(0,bmp_file_header%bfOffsetBits) ! ************************************* ! Create *.BMP info header bmp_header%bV5Size = size(transfer(bmp_header,(/1_ik1/))) write(*,'(a)',advance='no') 'Enter resolution in dots/inch:> ' read(*,*) DPI if(DPI <= 0) then write(*,'(a,i0,a)') 'Invalid resolution: ',DPI,' DPI' write(*,'(a)') 'Program aborting' stop end if write(*,'(a)',advance='no') 'Enter image width in inches:> ' read(*,*) width if(width <= 0) then write(flt_err,*) width write(*,'(3a)') 'Invalid width: ',trim(adjustl(flt_err)),' inches' write(*,'(a)') 'Program aborting' stop end if write(*,'(a)',advance='no') 'Enter image height in inches:> ' read(*,*) height if(height <= 0) then write(flt_err,*) height write(*,'(3a)') 'Invalid height: ',trim(adjustl(flt_err)),' inches' write(*,'(a)') 'Program aborting' stop end if ! (Done later) set image width in pixels bmp_header%bV5Width = 0 ! (Done later) set image height in pixels bmp_header%bV5Height = 0 bmp_header%bV5Planes = 1 ! 1 bit per pixel bmp_header%bV5BitCount = 1 ! Compression code = 0: no compression bmp_header%bV5Compression = 0 ! (Done later) set image size in bytes bmp_header%bV5SizeImage = 0 ! Horizontal resolution obtained above PelsPerMeter = nint(DPI/0.0254_dp) bmp_header%bV5XPelsPerMeter = PelsPerMeter ! Vertical resolution also obtained above bmp_header%bV5YPelsPerMeter = PelsPerMeter ! Use full palette if(bmp_header%bV5BitCount < 16) then bmp_header%bV5ClrUsed = 2**bmp_header%bV5BitCount bmp_header%bV5ClrImportant = bmp_header%bV5ClrUsed else bmp_header%bV5ClrUsed = 0 bmp_header%bV5ClrImportant = 0 end if !! All colors important ! bmp_header%bV5ClrImportant = 0 ! We won't worry about the next 4 fields for now bmp_header%bV5RedMask = 0 bmp_header%bV5GreenMask = 0 bmp_header%bV5BlueMask = 0 bmp_header%bV5AlphaMask = 0 bmp_header%bV5CSType = 2 ! LCS_WINDOWS_COLOR_SPACE ! Remaining fields ignored: we will set them to zero. bmp_header%bV5EndPoints = CIEXYZTRIPLE( & CIEXYZ(0,0,0), & CIEXYZ(0,0,0), & CIEXYZ(0,0,0)) bmp_header%bV5GammaRed = 0 bmp_header%bV5GammaGreen = 0 bmp_header%bV5GammaBlue = 0 bmp_header%bV5Intent = 0 bmp_header%bV5ProfileData = 0 bmp_header%bV5ProfileSize = 0 bmp_header%bV5Reserved = 0 ! ************************************* ! Create palette ! Black & white 2-color palette allocate(palette(0:2**bmp_header%bV5BitCount-1)) ! 0 = black palette(0) = RGBQUAD(0_ik1,0_ik1,0_ik1,0_ik1) ! 1 = white palette(1) = RGBQUAD(-1_ik1,-1_ik1,-1_ik1,0_ik1) ! ************************************* ! Define image dimensions ! Calculate image width bmp_header%bV5Width = nint(width*DPI) RowLength = 4*((bmp_header%bV5Width*bmp_header%bV5BitCount+31)/32) bmp_header%bV5Width = RowLength*8/bmp_header%bV5BitCount RowLength = 4*((bmp_header%bV5Width*bmp_header%bV5BitCount+31)/32) ! Calculate image height bmp_header%bV5Height = nint(height*DPI) ColHeight = bmp_header%bV5Height ! Allocate image allocate(image(0:Rowlength-1,0:ColHeight-1)) ! Store size of image in bytes bmp_header%bV5SizeImage = size(image) ! Store offset in file of DIB pixel bits bfOffsetBits = size(transfer(bmp_file_header,(/1_ik1/)))+ & bmp_header%bV5Size+ & size(transfer(palette,(/1_ik1/))) ! bmp_file_header%bfOffsetBits = transfer(bfOffsetBits, & ! bmp_file_header%bfOffsetBits) ! Work around ftn95 bug bmp_file_header%bfOffsetBits = transfer(bfOffsetBits, & (/1_ik2/)) bfSize = bfOffsetBits+size(image) ! bmp_file_header%bfSize = transfer(bfSize, & ! bmp_file_header%bfSize) ! Work around ftn95 bug bmp_file_header%bfSize = transfer(bfSize, & (/1_ik2/)) ! Work on image ! lambda = 0.6563e-6_dp ! Red light !lambda = 1.0e-5_dp write(*,'(a)',advance='no') 'Enter the wavelength in meters:> ' read(*,*) lambda if(lambda <= 0) then write(flt_err,*) lambda write(*,'(3a)') 'Invalid wavelength: ',trim(adjustl(flt_err)),' meters' write(*,'(a)') 'Program aborting' stop end if ! f = 0.3_dp ! Focal lenth = 30 cm !f = 0.5_dp write(*,'(a)',advance='no') 'Enter the focal length in meters:> ' read(*,*) f if(f <= 0) then write(flt_err,*) f write(*,'(3a)') 'Invalid focal length: ',trim(adjustl(flt_err)),' meters' write(*,'(a)') 'Program aborting' stop end if write(*,'(a)',advance='no') 'Use dithering? (default=no):> ' read(*,'(a)',advance='no',eor=10,size=line_size) line read(*,'()') 10 continue if(line_size == 0) line(1:1) = 'N' line = adjustl(line) dither = scan(line(1:1),'tTyY') /= 0 if(dither) then apodize = .FALSE. else write(*,'(a)',advance='no') 'Apodize? (default=no):> ' read(*,'(a)',advance='no',eor=20,size=line_size) line read(*,'()') 20 continue if(line_size == 0) line(1:1) = 'N' line = adjustl(line) apodize = scan(line(1:1),'tTyY') /= 0 end if r0 = f/sqrt((1/(PelsPerMeter*lambda))**2+1) sigma = r0 ! The following tests for g95 and others if(is_ftn95()) then ! Use ftn95-style stream I/O access = 'transparent' form = 'unformatted' else if(is_g95()) then ! Use f03-compatible stream I/O access = 'stream' form = 'unformatted' else ! Use values appropriate for lf95 express 7.10.02, ! ifort Package ID: W_FC_C_9.0.029, or cvf 6.6c3 access = 'sequential' form = 'binary' end if open(10,file='fire.bmp',access=access,form=form,status='replace') write(10) bmp_file_header write(10) bmp_header write(10) palette x0 = bmp_header%bV5Width/2 y0 = bmp_header%bV5Height/2 ! Initialize image to white image = -1_ik1 if(dither) then call random_seed() do i = 0, bmp_header%bV5Width-1 do j = 0, bmp_header%bV5Height-1 call random_number(harvest) r = sqrt(((i-x0+harvest(1))/real(PelsPerMeter,dp))**2+ & ((j-y0+harvest(2))/real(PelsPerMeter,dp))**2+ & f**2) if(abs(mod(r/lambda,1.0_dp)-0.5_dp) < 0.25_dp) then image(i/8,j) = iand(image(i/8,j),not(ishft(1_ik1,7-mod(i,8)))) else image(i/8,j) = ior(image(i/8,j),ishft(1_ik1,7-mod(i,8))) end if end do end do else if(apodize) then do i = 0, bmp_header%bV5Width-1 do j = 0, bmp_header%bV5Height-1 r12 = ((i-x0)/real(PelsPerMeter,dp))**2+ & ((j-y0)/real(PelsPerMeter,dp))**2 r = sqrt(r12+f**2) r1 = sqrt(r12) if(abs(mod(r/lambda,1.0_dp)-0.5_dp) < 0.25_dp*exp(-(r1/sigma)**2)) then image(i/8,j) = iand(image(i/8,j),not(ishft(1_ik1,7-mod(i,8)))) else image(i/8,j) = ior(image(i/8,j),ishft(1_ik1,7-mod(i,8))) end if end do end do else do i = 0, bmp_header%bV5Width-1 do j = 0, bmp_header%bV5Height-1 r12 = ((i-x0)/real(PelsPerMeter,dp))**2+ & ((j-y0)/real(PelsPerMeter,dp))**2 r = sqrt(r12+f**2) r1 = sqrt(r12) ! if(abs(mod(r/lambda,1.0_dp)-0.5_dp) < 0.25_dp .OR. & ! abs(r1-r0) < 3.0_dp/PelsPerMeter) then ! Plot circle if(abs(mod(r/lambda,1.0_dp)-0.5_dp) < 0.25_dp) then image(i/8,j) = iand(image(i/8,j),not(ishft(1_ik1,7-mod(i,8)))) else image(i/8,j) = ior(image(i/8,j),ishft(1_ik1,7-mod(i,8))) end if end do end do end if write(10) image close(10) end program fire ! End of file: fire2.f90