MAKIchan image format?

Ask for help and post your question on how to use XnView Classic.

Moderators: XnTriq, helmut, xnview

Post Reply
Ben321
Posts: 39
Joined: Fri Jul 30, 2010 8:05 am

MAKIchan image format?

Post by Ben321 »

Ok I've seen this format for a while now as relating to images on the Japanese computer PC98. It has a file extension of MAG. Unfortuneately all documentation I've seen so far is written in Japanese. Now I know that XNview supports this format. So I'm hoping that maybe someone here at these forums can explain to me how it works. I've tried reverse engineering this but all I get is garbage (often from only slightly altering one byte in the file). This suggests it uses some kind of compression. Now if only someone here could explain the format to me, in English.

Thanks in advance for any help you may provide.
User avatar
Clo
XnThusiast
Posts: 4441
Joined: Sun Oct 17, 2004 4:57 am
Location: Bordeaux, France
Contact:

Re: MAKIchan image format?

Post by Clo »

:arrow: Ben321

:) Hello !

• I can't explain the structure of this format, but all I can say is from my old doc :
mag---- MAKIchan Graphics----ext. : mag
- XnView supports it at reading only

:mrgreen: KR
Claude
Clo
Old user ON SELECTIVE STRIKE till further notice
mimulus
Posts: 3
Joined: Sun Aug 28, 2011 1:24 pm

Re: MAKIchan image format?

Post by mimulus »

While working on a visual novel engine, I've happened upon a few MAG images, and wrote a basic specification. It is available here: http://mooncore.eu/mimu/txt/makichan.htm

Helpful, I hope!
User avatar
Clo
XnThusiast
Posts: 4441
Joined: Sun Oct 17, 2004 4:57 am
Location: Bordeaux, France
Contact:

Re: MAKIchan image format?

Post by Clo »

:arrow: mimulus

:) Hello ! Welcome aboard !

• Thank you for this link!
- Maybe Pierre (the Author) will find there some useful info…

- The best should be indeed to find a Japanese user able to translate the full specs… Image

:mrgreen: Kind regards,
Claude
Clo
Old user ON SELECTIVE STRIKE till further notice
Ben321
Posts: 39
Joined: Fri Jul 30, 2010 8:05 am

Re: MAKIchan image format?

Post by Ben321 »

mimulus wrote:While working on a visual novel engine, I've happened upon a few MAG images, and wrote a basic specification. It is available here: http://mooncore.eu/mimu/txt/makichan.htm

Helpful, I hope!

Yes BIG THANKS, but you neglected a few things I'll need to know if I'm to make an encoder. What do the boolean values in flag A do? Also you explained how to use flag B to copy pixels, but not how to set flag B to make original pixels. Please explain in more detail how flags A, B, and the color array work together to make an image.

Also please list other screen modes than just mode 04 (16 color mode) if you know what the codes are for other screen modes.
mimulus
Posts: 3
Joined: Sun Aug 28, 2011 1:24 pm

Re: MAKIchan image format?

Post by mimulus »

I updated the specification document, hopefully making it clearer. I also translated the screen modes as listed in the official Japanese specs.

You're hoping to write an encoder? Hmm. If you don't care about compression, I think this might work: fill the flag A buffer with only zeros, and presumably the entire image will be directly read from the color word array.
quietroit
Posts: 1
Joined: Wed Nov 02, 2011 2:16 pm

Re: MAKIchan image format?

Post by quietroit »

mimulus wrote:If you don't care about compression, I think this might work: fill the flag A buffer with only zeros, and presumably the entire image will be directly read from the color word array.
By the way, very good tip
Ben321
Posts: 39
Joined: Fri Jul 30, 2010 8:05 am

Re: MAKIchan image format?

Post by Ben321 »

mimulus wrote:I updated the specification document, hopefully making it clearer. I also translated the screen modes as listed in the official Japanese specs.

You're hoping to write an encoder? Hmm. If you don't care about compression, I think this might work: fill the flag A buffer with only zeros, and presumably the entire image will be directly read from the color word array.
Does that mean that there would be no Flag B array? And does that also mean that the header entry for Flag B size would be set at 0? If so, What would I set the header entry for Flag B offset too? Would it be the same entry as the Color Index array offset? Please explain further. Your suggested technique sounds good in theory, but you didn't provide enough info for actually implementing it.
mimulus
Posts: 3
Joined: Sun Aug 28, 2011 1:24 pm

Re: MAKIchan image format?

Post by mimulus »

Does that mean that there would be no Flag B array? And does that also mean that the header entry for Flag B size would be set at 0? If so, What would I set the header entry for Flag B offset too? Would it be the same entry as the Color Index array offset? Please explain further. Your suggested technique sounds good in theory, but you didn't provide enough info for actually implementing it.
By now you've probably gotten it to work perfectly, but just in case:

As far as I can tell, your guesses are all correct. The Flag B array would be empty, its size would be 0 bytes, and its offset equal to the Color Index array offset. Or, you could put a bunch of garbage data in the Flag B array - a decompressor would just never read it, as long as the Flag A array is all zeroes.

This is obviously just an inefficient hack; figuring out a good algorithm for optimal Maki-chan compression is a challenge of its own, while I only needed decompressing capability.
Ben321
Posts: 39
Joined: Fri Jul 30, 2010 8:05 am

Re: MAKIchan image format?

Post by Ben321 »

This is an overly complex compression scheme. The choices for DeltaX and DeltaY values make no sense, they don't seem to have any pattern:
deltax : array[0..15] of byte = (0,1,2,4,0,1,0,1,2,0,1,2,0,1,2,0);
deltay : array[0..15] of byte = (0,0,0,0,1,1,2,2,2,4,4,4,8,8,8,16);
They seem to be just arbitrary values pulled out of the inventor's hat.

The color channels are GRB instead of the standard RGB or BGR.

It uses a complicated XOR scheme:
If (next flag A bit) = TRUE
Then flag_buffer[x] = flag_buffer[x] XOR (next flag B byte)

instead of just a simple equal to scheme like
If (next flag A bit) = TRUE
Then flag_buffer[x] = (next flag B byte)

It actually bothers to keep a flag buffer such that the previous line's actions with flagB have an effect on the current line, although that is a dumb thing since the DeltaX and DeltaY already are a form of "look up previous data" type compression. So it basically is performing multiple compressions, rather than a simple single compression. Then to make the complexity worse, parts of it are handled as whole bytes, other parts are handled as nibbles, yet other parts are handled as single bits. And even other parts are handled as words (pairs of bytes). And to further complicate things, some parts are handled as different sized data units at different steps in the process.


This makes the whole compression scheme overly complicated. And if you want to even DREAM OF writing a COMPRESSER for this, the analysis that the compressor software would have to do to perform the action of compressing the image would be so INSANELY COMPLICATED that the compression algorithm is basically IMPOSSIBLE to reverse engineer from the decompressor algorithm unless you are a SUPER GENIUS SOFTWARE ENGINEER!

I thought I could make a compressor after figuring out the decompressor. But nope. I've written a VB6 implementation of the decompressor, but I'm no closer now to writing a compressor for this format than before I was before. I was hoping someone maybe could help out with that, but I doubt it given the complexity of the compression scheme. I'd basically have to find the Japanese guy who invented the compression and hope he would be willing to give me the official specs on his compressor.
Ben321
Posts: 39
Joined: Fri Jul 30, 2010 8:05 am

Re: MAKIchan image format?

Post by Ben321 »

I finally wrote a successful MAG image file decoder in VB6, thanks to the specs provided here by Mimulus. The source code is in a zip file attached to this message.
The first line defines the constant FName has the file name (it requires the full path c:\etc...) to the mag image file. This isn't suitable in its current form for compiling as there's no way to select an image file to load at runtime (it's a constant set at design-time), but you can easily run it from the VB6 IDE as-is. Also this could be a building block for a project that is a full fledged mag viewer, or it could be used as a way to implement MAG format images in a computer game if you are writing a computer game in VB6.

The program as it is now, when run it does a number of things.
First if verifies that the path specified by the constant FName is valid. If this fails, the program quits.
(it doesn't yet check the file extension, so you could use a Makichan2 format image with a different extension like .XYZ instead of .MAG, and it would still load, but I may add file extension checking in a later version).

Then it loads the file.
The first thing it does after loading is it checks the first 6 bytes of the file to make sure they contain the string "MAKI02". If this check fails, the program quits.

If it passes these checks, it then procedes to parse the header and other data in the file and display the image, as well as in another box it displays the info provided in byte 4 of the header (the "screen mode" byte). This includes the number of colors in the palette (8, 16, or 256), the number of lines on the display that was the type of display that the image was intended to be viewed on (200 or 400), and whether the dispalay that the image was intended to be viewed on was an "analog" or "digital" display (except for the palette, these other infos seem useless, pretty much just meta data about the type of display that the artist who created the image expected it to appear best on). Also this image info box displays the width and height of the image.

This program also properly handles nonstandard image sizes. Typically a MAG image is supposed to have widths that are multiples of 8 pixels. If this isn't the case it originally caused my program to crash. I have created a workaround where the image (if its width isn't a multiple of 8 pixels) is padded to such a multiple during decompression and then prior to display the padding is removed so that it has the correct image width as stated in the header of the file. The next best program for this is Fine-View (it has the ability to do both loading and saving in MAG format) does pad it so it will decompress properly, but then it fails to remove that padding, and as such the image will have a black bar on the right side if it isn't an exact multiple of 8 pixels in width. My program doesn't make this mistake.
Attachments
MAG Viewer.zip
(3.33 KiB) Downloaded 168 times
User avatar
xnview
Author of XnView
Posts: 43326
Joined: Mon Oct 13, 2003 7:31 am
Location: France
Contact:

Re: MAKIchan image format?

Post by xnview »

Thanks, i'll check your viewer
Pierre.
sd_snatcher
Posts: 39
Joined: Sat Sep 10, 2016 11:29 pm

Re: MAKIchan image format?

Post by sd_snatcher »

I found the original asm sources of the MG.EXE v0.99. It's considered to be the one of the best Makichan/Pi encoders of that era. Maybe it can help on the development of a modern encoder?

The ana86 assembler is also supplied in that page.

The author still seems to be kicking around, and if I understood that page correctly, his e-mail is tenka at sixty eight zero nine dot net. Maybe he could also provide some help.
Attachments
mg-lfn-v0.99c-src.zip
(260.08 KiB) Downloaded 39 times
sd_snatcher
Posts: 39
Joined: Sat Sep 10, 2016 11:29 pm

Re: MAKIchan image format?

Post by sd_snatcher »

This ana assembly language looks like some hybrid between Pascal and 8086 asm. This is the content of the mag_wrt.ana file:

Code: Select all


submodule Mag
	import GH
	import Dos
	import Pri
	import Subr
	import Deb
	import Std

@define	GHT()	GH.T[ds:0]

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

cvar pdataBuf:d

cvar dbufAseg:w, dbufAsiz:w
cvar dbufBseg:w, dbufBsiz:w
cvar dbufPseg:w, dbufPszs:w, dbufPendSeg:w
cvar flgLinBufSeg:w,flgLinBufSiz:w
cvar flgLinBufSeg2:w
cvar ptrA:w, ptrB:w, ptrP:d
cvar vsizXh:w
cvar hdl:w,c256flg:b
cvar curY:w
cvar gh_t:d

cvar flagAofs:d, flagBofs:d, pdataOfs:d
cvar flagAsiz:d, flagBsiz:d

cvar pos:w(16)
cvar posX:w(16) = {0,-1,-2,-4, 0,-1, 0,-1,-2, 0,-1,-2, 0,-1,-2,  0}
cvar posY:w(16) = {0, 0, 0, 0,-1,-1,-2,-2,-2,-4,-4,-4,-8,-8,-8,-16}

proc WrtBufA(di)
//	フラグA のデータを書込む
//	arg di	出力するバイト数
enter
	save pusha,ds

	go (di == 0) RET
	ds.bx = gh_t
	GH.SeekW bx, flagAofs
	cx = di
	dx.ax = ww(0,cx)
	dx.ax += flagAofs
	flagAofs = dx.ax

	ptrA = dx = 0
	ax = dbufAseg
	GH.Write bx,ax.dx,cx
	Deb.Chk
	if (==)
		Deb.SaveReg
		Pri.Fmt "フラグA 書き出し:%x->%x¥N",cx,ax
		Deb.LoadReg
	fi
  RET:
	return
endproc

cvar wkAcnt:b = 8, wkAdat:b = 0
@define ResetWkA()	wkAcnt = 8;wkAdat = 0

proc WrtA()
//	フラグA のバッファへ1ビット書込む
//	in  cf
begin
	|wkAdat <<=. 1
	--wkAcnt
	if (wkAcnt == 0)
		push ax,di,es
			di = ptrA
			if (di >= dbufAsiz)
				WrtBufA di
				di = ptrA
			fi
			es = dbufAseg
			rep.set di,	wkAdat
			ptrA = di
			wkAcnt = 8
		pop  ax,di,es
	fi
  //Deb.PRI "WrtA¥N"
	return
endproc


proc WrtBufB(di)
//	フラグB のデータを書込む
//	arg di	出力するバイト数
enter
	save pusha,ds

	go (di == 0) RET
	ds.bx = gh_t
	GH.SeekW bx, flagBofs
	cx = di
	dx.ax = ww(0, cx)
	dx.ax += flagBofs
	flagBofs = dx.ax

	dx.ax = flagBsiz
	dx.ax += ww(0, cx)
	flagBsiz = dx.ax

	ptrB = dx = 0
	ax = dbufBseg
	GH.Write bx,ax.dx,cx
	Deb.Chk
	if (==)
		Deb.SaveReg
		Pri.Fmt "フラグB 書き出し:%x->%x¥N",cx,ax
		Deb.LoadReg
	fi
  RET:
	return
endproc

proc WrtB(al)
//	フラグB のバッファへ1バイト書込む
//	in  cf
begin
	save ax,di,es

  //Deb.PRI "WrtB¥N"
	di = ptrB
	if (di >= dbufBsiz)
		WrtBufB di
		di = ptrB
	fi
	es = dbufBseg
	rep.set di,	al
	ptrB = di
	return
endproc



proc SetBufAddr(ax, dx, cx)
//  入力バッファの分割(フラグA,フラグB,ピクセル・データ,展開用ライン・バッファ)
//	arg	ax	バッファのセグメント
//	arg dx  バッファのパラグラフ・サイズ
enter
	save pusha,es,ds
	local topSeg:w = ax, szs:w = dx

	bx = dx
	flgLinBufSiz = cx
	Std.ParaSize cx, dx
	cx <<= 1
	go (bx <= cx) ERR
	bx -= cx
	dx.ax = flagAsiz
	if (dx || ax > ((640/4)*512/8))
		ax = Mag.RDBUFA
	fi
	dbufAsiz = ax
	Std.ParaSize ax,dx
	go (bx <= ax) ERR
	bx -= ax
	if (bx >= 0x1000)
		ax = 0x6000
		bx -= 0x600
	elsif (bx >= 0x800)
		ax = 0x3000
		bx -= 0x300
	elsif (bx > 0x100)
		ax = 0x800
		bx -= 0x80
	else
  ERR:
		Subr.PriExit "Magのバッファのメモリが確保できない¥N"
	fi
	dbufBsiz = ax
	dbufPszs = bx

	flgLinBufSeg = ax = topSeg

	cx = flgLinBufSiz
	Std.ParaSize cx,bx
	ax += cx
	flgLinBufSeg2 = ax

	cx = flgLinBufSiz
	Std.ParaSize cx,bx
	ax += cx
	dbufAseg = ax

	cx = dbufAsiz
	Std.ParaSize cx,bx
	ax += cx
	dbufBseg = ax
	
	cx = dbufBsiz
	Std.ParaSize cx,bx
	ax += cx
	dbufPseg = ax

	ptrP = ww(ax,0)
	ax += dbufPszs
	dbufPendSeg = ax

	Deb.Chk
	if (==)
		Pri.Fmt "A Seg=$%04x  Siz=$%04x¥N",dbufBseg, dbufAsiz
		Pri.Fmt "B Seg=$%04x  Siz=$%04x¥N",dbufBseg, dbufBsiz
		Pri.Fmt "P Seg=$%04x  Siz=$%04x0¥N",dbufPseg, dbufPszs
		Pri.Fmt "Top=$%04x szs=$%04x EndSeg=$%04x¥N",topSeg,szs,dbufPendSeg
	fi
	return
endproc



*proc InitWrite(bx)
//  Mag ファイル書込みの準備
//	arg si	GH.T へのポインタ
enter
	save pusha,es,ds

	gh_t = ds.bx
	hdl = dx = GHT.wrtHdl

	// フラグA,フラグB,ピクセル・データの各ブロック・サイズの数と余りサイズを計算
	flagAofs = dx.ax = GHT.magWflagAofs
	flagBofs = dx.ax = GHT.magWflagBofs
	pdataOfs = dx.ax = GHT.magWpdataOfs
	flagAsiz = dx.ax = GHT.magWflagAsiz
	// 256色?
	c256flg = 0
	if (GHT.plnW == 8)
		c256flg = 1
	fi
	al = c256flg
	ah = 0
//pusha;Pri.Fmt "256flg:%d¥N",ax;popa

	//ピクセル・データ・バッファ
	pdataBuf = dx.ax = ww(GHT.pdbSeg, GHT.hisSizO)

	// 横幅関係
	ax = GHT.sizeXo
	ax >>= 2
	if (c256flg == 0)
		ax >>= 1
	fi
	vsizXh = ax	//1行分のフラグ(4ビット)がしめるバイト数
				//=処理上のピクセル(16色なら4ドット.256色なら2ドット)での横幅 div 2
//pusha;Pri.Fmt "vxh=%d¥N",vsizXh;popa

	//メモリ分配
	GH.GetMem bx, 0x400, 0xffff
	dx = cx
	SetBufAddr ax, dx, vsizXh

  @if 0
	// フラグAのブロック・サイズの数と余りサイズを計算
	dx.ax = flagAsiz
	div dx.ax, dbufAsiz
	blkCntA = ax
	rstSizA = dx
  @fi


	//相対位置のオフセット値を求める.
	//16色時、1dot4ビット。作業1ピクセル(2byte)は4dot単位
	//256 色時、1dot8ビット。作業1ピクセル(2byte)は2dot単位
	cx = GHT.sizeXo
	bx = 4
	if (c256flg)
		bx = 2
	fi
	ax = 0
	pos(0) = ax		//( 0, 0)
	ax += bx
	pos(1) = ax		//(-1, 0)
	ax += bx
	pos(2) = ax		//(-2, 0)
	ax += bx
	ax += bx
	pos(3) = ax		//(-4, 0)
	ax = cx
	pos(4) = ax		//( 0,-1)
	ax += bx
	pos(5) = ax		//(-1,-1)
	ax = cx
	ax <<= 1
	pos(6) = ax		//( 0,-2)
	ax += bx
	pos(7) = ax		//(-1,-2)
	ax += bx
	pos(8) = ax		//(-2,-2)
	ax = cx
	ax <<= 2
	pos(9) = ax		//( 0,-4)
	ax += bx
	pos(10) = ax	//(-1,-4)
	ax += bx
	pos(11) = ax	//(-2,-4)
	ax = cx
	ax <<= 3
	pos(12) = ax	//( 0,-8)
	ax += bx
	pos(13) = ax	//(-1,-8)
	ax += bx
	pos(14) = ax	//(-2,-8)
	ax = cx
	ax <<= 4
	pos(15) = ax	//(0,-16)

	//その他の変数初期化
	ResetWkA
	ax = 0
	ptrA = ax
	ptrB = ax
	flagBsiz = ww(ax,ax)
	curY = ax

	// フラグ展開用のライン・バッファの初期化
	di = ax 	//	= 0
	cx = flgLinBufSiz
	es = flgLinBufSeg
	rep.set di,al,cx
	cx = flgLinBufSiz
	es = flgLinBufSeg2
	di = ax
	rep.set di,al,cx
	
	return
endproc


proc ChkPos(al,cx,si)
//  in ds
//	break di,ax
begin
	save ax

	go (al == 0) RET0
	ah = 0
	di = ax
	di <<= 1
	ax = posY[di]
	ax += curY
	go (ax .<. 0) RET0
	ax = posX[di]
	ax += cx
	go (ax .<. 0) RET0
	ax = pos[di]
	di = si
	di -= ax
	ax = w[di]
	go (ax != w[si]) RET0
	if (c256flg == 0)
		ax = w[di+2]
		go (ax != w[si+2]) RET0
	fi
	stc
	return
  RET0:
  	clc
  	return
endproc

proc PosNo (al,cx,si)
//	相対位置のピクセルと比較し、一致する番号を求める。
//	一致しなかったばあいは、ピクセル・データを出力
//	arg al  1行間上のフラグの番号
//	arg si  ピクセル・データ・バッファでの現在位置
//	in  ds  ピクセル・データ・バッファのセグメント
//	out al  相対位置番号 0〜15	(0:一致しなかった)
//	break di
begin
//Deb.PRI "PosNo¥N"
	block
		ChkPos al,cx,si;	break (_c_)
		ChkPos  1,cx,si; 	break (_c_)
		ChkPos  4,cx,si; 	break (_c_)
		ChkPos  5,cx,si; 	break (_c_)
		ChkPos  6,cx,si; 	break (_c_)
		ChkPos  7,cx,si; 	break (_c_)
		ChkPos  9,cx,si; 	break (_c_)
		ChkPos 10,cx,si; 	break (_c_)
		ChkPos  2,cx,si; 	break (_c_)
		ChkPos  8,cx,si; 	break (_c_)
		ChkPos 11,cx,si; 	break (_c_)
		ChkPos 12,cx,si; 	break (_c_)
		ChkPos 13,cx,si; 	break (_c_)
		ChkPos 14,cx,si; 	break (_c_)
		ChkPos  3,cx,si; 	break (_c_)
		ChkPos 15,cx,si; 	break (_c_)
		go L_ZERO
	endblock
	return

  L_ZERO:
	 /* ピクセル・データ・バッファへ2バイト書込む */
	push ax,si,es
	ax.di = ptrP
	if (ax >= dbufPendSeg)
		Subr.PriExit "メモリが足り無くなった(ピクセル・データのバッファが溢れた)¥N"
	fi
	es = ax
	if (c256flg)
		rep.cpy.w di, si
	else
		rep.load.w ax,si
		al <<= 4
		ah &= 0x0f
		al |= ah
		rep.set di, al
		rep.load.w ax,si
		al <<= 4
		ah &= 0x0f
		al |= ah
		rep.set di, al
	fi
	ax = es
	Std.FpToHp ax,di, si
	ptrP = ax.di
	pop ax,si,es
	al = 0	// 一致しなかったら、位置番号は 0
	return

endproc

*proc WritePDB(ght:d,lincnt:w);cdecl
// ピクセル・データ・バッファ ax 行, MAGに変換
//	arg  si  GH.T へのポインタ(ダミー)
//	arg  ax  行数
enter
	save pusha,es,ds
	local pdptr:d, cnt:w, ofs:w

	cnt = ax = lincnt
	ofs = 4
	if (c256flg)
		ofs = 2
	fi
	pdptr = dx.si = pdataBuf
	// 指定行数分、ループ
	loop.w
		si = pdptr.l
		cx = bx = 0
		loop
			ds = flgLinBufSeg2
			ah = al = b[bx]
			ds = flgLinBufSeg
			b[bx] = al
			ah &= 0x0f
			al >>= 4
			ds = pdptr.h
			PosNo al,cx,si
			si += ofs
			++cx
			al <<= 4
			ah <=> al
			PosNo al,cx,si
			si += ofs
			al |= ah
			ds = flgLinBufSeg2
			b[bx] = al
			ds = flgLinBufSeg
			b[bx] ^= al
			++bx
			++cx
		endloop (bx < vsizXh)
		pdptr.l = si
		//ds = flgLinBufSeg
		si = 0
		cx = vsizXh
		loop
			rep.load al,si
			if (al == 0)
				clc
				WrtA
			else
				stc
				WrtA
				WrtB al
			fi
		endloop (--cx)
	  @if 0
		Deb.Chk
		if (==)
			Pri.Word curY
			Pri.Chr '¥r'
		fi
	  @fi
		++curY
	endloop (--cnt)
	return
endproc

*proc CloseW(ght:d);cdecl
	//*proc Flush(ght:d);cdecl
	//バッファの残りを掃き出す
enter
	save pusha,es,ds
	local tmp:d
	local pdataOfs:d,pdataSiz:d

//Deb.PRI "FLush¥N"
	cl = wkAcnt
	if (cl < 8 /* && cl > 0*/)
		ch = 0
		loop
			clc
			WrtA
		endloop (--cx)
	fi
	WrtBufA ptrA
	WrtBufB ptrB
	
	ds.bx = ght
	
	// フラグBのサイズを収める位置へシーク
	dx.ax = GHT.magWhdrOfs
	dx.ax += 20
	GH.SeekW bx, dx.ax

	// フラグBのサイズを書込む
	dx = &tmp
	ax.di = flagBsiz
	tmp = ax.di
	cx = 4
	GH.Write bx, ss.dx, cx
//Pri.Fmt "sizeB = %ld(%lx)¥N", tmp, tmp

	// ピクセル・データのオフセットを書込む
	ax.di = GHT.magWflagBofs0
//Pri.Fmt "flagBofs0 = %lx¥N", ax.di
	ax.di += tmp
	if (di & 0x01)
		ax.di += 1
	fi
	tmp = ax.di
	pdataOfs = ax.di
	GH.Write bx, ss.dx, cx
//Pri.Fmt "pdataOfs = %lx¥N", tmp

	// ピクセル・データのサイズを書込む
	ax.di = ptrP
	ax -= dbufPseg
	Std.FpToDw ax,di, cx
	tmp = ax.di
	pdataSiz = ax.di
	GH.Write bx, ss.dx, 4
//Pri.Fmt "sizeP = %ld(%lx)¥N", tmp, tmp

	// ピクセル・データの先頭へシーク
	dx.ax = GHT.magWhdrOfs
//Pri.Fmt "hdrPos = %lx¥N", dx.ax
	dx.ax += pdataOfs
//Pri.Fmt "pdatPos = %lx¥N", dx.ax
	GH.SeekW bx, dx.ax

	// ピクセル・データを書込む
	di.cx = pdataSiz
//Pri.Fmt "sizeP = %ld(%lx)¥N", di.cx, di.cx
	push cx
	dx = 0
	ax = dbufPseg
	if (di)
		cx = 0x8000
		loop
			GH.Write bx, ax.dx, cx
			ax += 0x800
			GH.Write bx, ax.dx, cx
			ax += 0x800
		endloop (--di)
	fi
	pop cx
	if (cx)
		GH.Write bx, ax.dx, cx
	fi
	GH.CloseW  ds.bx
	return

endproc

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

*proc InitW(ght:d);cdecl
enter
	save ax,ds,bx
	ds.bx = ght
	GH.SetHisLin bx,16
	GHT.wrtX8flg = 1
	//GH.Df_wrtX8mode 1
	GHT.fmtW = GH.MAG
	return
endproc


cvar hdrHdl:w

proc InitPutC(ax)
begin
	hdrHdl = ax
	return
endproc

proc Err()
begin
	dx = ax
	Pri.S "MAGヘッダ書込みでエラー #"; Pri.Int dx; Pri.Cr
	Dos.Exit(1)
endproc

proc PutC(al)
begin
	save pusha,ax,bx,cx,dx,ds
	var gcbuf:b

	ds = bx = %var
	gcbuf = al
	Dos.Write hdrHdl,&gcbuf,1
	if (_c_)
		Err
	fi
	return
endproc

proc PutW(ax)
begin
	save pusha,ax,bx,cx,dx,ds
	var gcbuf:w

	ds = bx = %var
	gcbuf = ax
	Dos.Write hdrHdl,&gcbuf,2
	if (_c_)
		Err
	fi
	return
endproc

proc PutD(dx.ax)
begin
	save pusha,ax,bx,cx,dx,ds
	var gcbuf:d

	ds = bx = %var
	gcbuf = dx.ax
	Dos.Write hdrHdl,&gcbuf,4
	if (_c_)
		Err
	fi
	return
endproc


*proc Create(ght:d,filename:d);cdecl
//	Magファイルのヘッダ出力
//	arg si  GH.T へのポインタ
//	arg dx	ファイル名
//  out ax  0:成功  以外:エラー
enter
	save bx,cx,dx,si,di,es,ds
	cvar fmt:b() = "MAG"

	ds.bx = ght
	GHT.wrtFmtName = dx.ax = ww(cs,&fmt)
	//GHT.fmtW = GH.MAG
	//GHT.wrtX8flg = 1
	es = ds
	GH.Create bx, filename
	InitPutC GHT.wrtHdl

	//ID出力
	GH.Write bx,ww(%var,"MAKI02  "),8
	//セーバ機種名出力
	if (GHT.macNameMode == 0)
		GH.Write bx,ww(ds,&GHT.macName), 4
	else
		GH.Write bx,ww(%var,"MG  "), 4
	fi
	PutC ' '
	//ユーザ名出力
	cx = GHT.userNameLen
	if (cx)
		if (cx >= 18)
			cx = 18
		fi
		GH.Write bx, GHT.userName, cx
		if (cx < 18)
			cx -= 18
			neg cx
			GH.Write bx, ww(%var,"                  "), cx
		fi
	else
		GH.Write bx, ww(%var,">謎<              "), 18
	fi
	//コメント出力
	cx = GHT.commentLen
	if (cx)
		PutC ' '
		es.di = GHT.comment
		loop
			al = b[es:di];++di
			break (al == 0 || al == 0x1a)
			PutC al
		endloop
	fi
	PutC 0x1a

	//ヘッダ先頭のシーク位置を取得
	push bx
	    bx = GHT.wrtHdl
	    cx.dx = 0
	    al = 1
	    Dos.Lseek bx,cx.dx,al
	    if (_c_)
		    Subr.PriExit "シーク・エラー(Magヘッダ)¥N"
	    fi
	pop bx
	GHT.magWhdrOfs = dx.ax

	//ヘッダ本体
	PutC 0x00				//ヘッダ先頭
	if (GHT.bakCol)
		PutC 98
		al = GHT.bakCol.l
		--al
		al |= 0x10
		PutC al
	else
		PutC GHT.magMacNo 	//機種コード
		PutC GHT.magMacFlg	//機種依存フラグ
	fi
	//200ラインフラグを立てるかどうか
	ah = 0
	al = GHT.asp1
	dl = GHT.asp2
	if (al && dl)
		div ax,dl
		ah = al
	fi
	al = GHT.magScrnMode
	al &= (‾(Mag.MF_200L|Mag.MF_256C))&0xff
	if (ah >= 2)
		al |= Mag.MF_200L
	fi
	//256色か
	if (GHT.plnW == 8)
		al |= Mag.MF_256C
	fi
    PutC al		//スクリーン・フラグ
	
	//始点、終点
	PutW GHT.startX
	PutW GHT.startY
	PutW GHT.endX
	PutW GHT.endY
	
	//フラグA のオフセット
	dx = ax = GHT.col
	ax += ax; ax += dx	// ax = ax * 3
	ax += 32
	dx = 0
	PutD dx.ax
	bx.cx = dx.ax
	dx.ax += GHT.magWhdrOfs
	GHT.magWflagAofs = dx.ax

	//フラグA のサイズ計算
	dx.ax = GHT.sizeXo * GHT.sizeY
	if (GHT.plnW == 8)
	  @if 0
		if (GHT.startXofs>3 || (GHT.endXofs>0 && GHT.endXofs<5))
			Pri.Fmt "ごめん... この256MAG生成は誤変換する可能性大です.¥N"
			//Dos.EXIT (1)
		fi
	  @fi
		if (ax & 0x1f)
			dx.ax += 4*8
		fi
		dx.ax >>= 5		//dx.ax /= 4*8
	else
		if (ax & 0x3f)
			dx.ax += 4*2*8
		fi
		dx.ax >>= 6		//dx.ax /= 4*2*8
	fi
	if (ax & 0x01)
		dx.ax += 1
	fi
	GHT.magWflagAsiz = dx.ax

	//フラグB のオフセット
	dx.ax += bx.cx
	PutD dx.ax
	GHT.magWflagBofs0 = dx.ax
	dx.ax += GHT.magWhdrOfs		//seek
	GHT.magWflagBofs = dx.ax

	//フラグB のサイズ(ダミー...後で設定)
	PutD 0

	//ピクセル・データのオフセット(ダミー...後で設定)
	PutD 0

	//ピクセル・データのサイズ(ダミー...後で設定)
	PutD 0

	//パレット
	cx = GHT.col
	es.di = GHT.rgbPal
	loop
		al = b[es:di + 1]	//G
		PutC al
		al = b[es:di + 0]	//R
		PutC al
		al = b[es:di + 2]	//B
		PutC al
		di += 3
	endloop (--cx)
	
	//
	InitWrite bx

	//ヘッダ出力おわり
	ax = 0
	return
endproc



endmodule

Note: All files are encoded in Shift JIS.
sd_snatcher
Posts: 39
Joined: Sat Sep 10, 2016 11:29 pm

Re: MAKIchan image format?

Post by sd_snatcher »

It's also worth mentioning that the Makichan supported many more platforms than just the PC98. Namely, it supported: PC98, PC88, MSX2, MSX2+, X68000, FM-Towns and Mac. I believe it's the only multi-platform image format that has full support for the MSX2/2+ advanced screen modes (interlace, high-color, etc).

More info in English can be found here.

Gazillions of MAG images for all major Japanese computer platforms can be found at the Retro Gallery. This image format was more important in Japan at that time than GIF or IFF were for the contemporary IBM-PC and Amiga.

Some Japanese artists still publish MAG files up to these days.
Post Reply