屈辱の画像変換w
(追記 R6 夏:AIの力を借りて Windows での Fortran only jpg, png etc. I/O ができました。) fortran66.hatenablog.com
Fortran で jpg や png を読み書きするのに、Python スクリプトを内部生成してテンポラリな bmp ファイルを経由して I/O するという屈辱的な方法を使ってみます。まぁどうせどんなファイルも読み込めば BMP になるんだし~手段をえらばず。
python script を生成して実行。bmp ファイルに/から変換する
subroutine conv_bmp(fn_in, fn_out) character(*), intent(in) :: fn_in, fn_out character(*), parameter :: fn_tmp = 'my_python_tmp.py' integer :: iw open(newunit = iw, file = fn_tmp) write(iw, '(a)') 'from PIL import Image' write(iw, '(*(a))') 'img = Image.open("', trim(fn_in), '").convert("RGB")' write(iw, '(*(a))') 'img.save("', trim(fn_out), '")' close(iw) call execute_command_line('python3 '//fn_tmp) call delete_file(fn_tmp) end subroutine conv_bmp
実行例
image size 535 210
入力 1966.png
出力 1966_without_red.jpg
赤色を消します。符号なし 8 bit 整数の代用として文字を使っています。
bmp%rgb(:,:)%r = achar(0)
open(iw, fn) close(iw, status = 'delete')
でテンポラリファイルを消しています。
write(iw, '(*(a))') 'img = Image.open("', trim(fn_in), '").convert("RGB")'
Python の pillow を使っています。Fortran 側の BMP I/O が 24 bit RGB 専用なので、読み込む時に .convert("RGB") をつけておく必要があるようです。
module m_bmp use, intrinsic :: iso_fortran_env implicit none type :: t_bmp_file_header sequence integer(int16) :: bfType = transfer('BM', 0_int16) ! BitMap integer(int32) :: bfSize ! file size in bytes integer(int16) :: bfReserved1 = 0 ! always 0 integer(int16) :: bfReserved2 = 0 ! always 0 integer(int32) :: bfOffBits end type t_bmp_file_header ! type :: t_bmp_info_header sequence integer(int32) :: biSize = Z'28' ! size of bmp_info_header ; 40bytes integer(int32) :: biWidth integer(int32) :: biHeight integer(int16) :: biPlanes = 1 ! always 1 integer(int16) :: biBitCount integer(int32) :: biCompression = 0 ! 0:nocompression, 1:8bitRLE, 2:4bitRLE, 3:bitfield integer(int32) :: biSizeImage integer(int32) :: biXPelsPerMeter = 3780 ! 96dpi integer(int32) :: biYPelsPerMeter = 3780 ! 96dpi integer(int32) :: biClrUsed = 0 integer(int32) :: biClrImportant = 0 end type t_bmp_info_header ! type :: t_rgb sequence character :: b, g, r end type t_rgb ! type :: t_bmp type(t_bmp_file_header) :: file_header type(t_bmp_info_header) :: info_header type(t_rgb), allocatable :: rgb(:, :) contains procedure :: rd => rd_py procedure :: wr => wr_py procedure :: rd_bmp procedure :: wr_bmp end type t_bmp contains subroutine rd_py(bmp, fn) class(t_bmp), intent(out) :: bmp character(len = *), intent(in) :: fn character(*), parameter :: fn_tmp = 'my_bmp_rd_tmp' call conv_bmp(fn, fn_tmp//'.bmp') call bmp%rd_bmp(fn_tmp) call delete_file(fn_tmp//'.bmp') end subroutine rd_py subroutine wr_py(bmp, fn) class(t_bmp), intent(in out) :: bmp character(len = *), intent(in) :: fn character(*), parameter :: fn_tmp = 'my_bmp_wr_tmp' call bmp%wr_bmp(fn_tmp) call conv_bmp(fn_tmp//'.bmp', fn) call delete_file(fn_tmp//'.bmp') end subroutine wr_py subroutine rd_bmp(bmp, fn) class(t_bmp), intent(out) :: bmp character(len = *), intent(in) :: fn type(t_bmp_file_header) :: bmp_file_header type(t_bmp_info_header) :: bmp_info_header integer :: ix, iy, nx, ny, ir character :: dummy open(newunit = ir, file = fn//'.bmp', access = 'stream', status = 'unknown') read(ir) bmp_file_header, bmp_info_header nx = bmp_info_header%biWidth ny = bmp_info_header%biHeight allocate( bmp%rgb(nx, ny) ) read(ir) (bmp%rgb(:, iy), (dummy, ix = 1, mod(nx, 4)), iy = 1, ny) close(ir) end subroutine rd_bmp subroutine wr_bmp(bmp, fn) class(t_bmp), intent(in out) :: bmp character(len = *) :: fn integer :: ix, iy, nx, ny, iw nx = size(bmp%rgb, 1) ny = size(bmp%rgb, 2) bmp%file_header%bfSize = 14 + 40 + 0 + (3 * nx + mod(nx, 4)) * ny bmp%file_header%bfOffBits = 14 + 40 bmp%info_header%biWidth = nx bmp%info_header%biHeight = ny bmp%info_header%biBitCount = 24 bmp%info_header%biSizeImage = (3 * nx + mod(nx, 4)) * ny open(newunit = iw, file = trim(fn)//'.bmp', access = 'stream', status = 'unknown') write(iw) bmp%file_header, bmp%info_header write(iw) (bmp%rgb(:, iy), (achar(0), ix = 1, mod(nx, 4)), iy = 1, ny) close(iw) end subroutine wr_bmp subroutine conv_bmp(fn_in, fn_out) character(*), intent(in) :: fn_in, fn_out character(*), parameter :: fn_tmp = 'my_python_tmp.py' integer :: iw open(newunit = iw, file = fn_tmp) write(iw, '(a)') 'from PIL import Image' write(iw, '(*(a))') 'img = Image.open("', trim(fn_in), '").convert("RGB")' write(iw, '(*(a))') 'img.save("', trim(fn_out), '")' close(iw) call execute_command_line('python3 '//fn_tmp) call delete_file(fn_tmp) end subroutine conv_bmp subroutine delete_file(fn) character(*), intent(in) :: fn integer :: iw open(newunit = iw, file = fn) close(iw, status = 'delete') end subroutine delete_file end module m_bmp program imgage use, intrinsic :: iso_fortran_env use :: m_bmp implicit none type(t_bmp) :: bmp call bmp%rd('1966.png') print *, 'image size', shape(bmp%rgb) bmp%rgb(:, :)%r = achar(0) call bmp%wr('1966_without_red.jpg') end program imgage
R2-10-2 微修正 delete_file 追加 R2-10-3 微修正 tmp file 名 parameter 化
最近オライリー本が白くなってマイケル・ジャクソンみたい。中の紙も漂白紙になって目が痛い。ホワイトウォッシュだなw