/* This example use of jpeg.library loads the jpeg file specified
		on the command line and viewsit halved in size on a cybergraphics
		screen. It uses a DecompressHook to store the image data from
		jpeg.library. This example uses memory based jpeg streams for the
		source image.

		Supports RGB and Grayscale source jpeg images.
*/

#include <stdio.h>

#include <dos/dos.h>
#include <exec/memory.h>
#include <exec/types.h>

#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/cybergraphics_protos.h>
#include <clib/intuition_protos.h>
#include <intuition/intuitionbase.h>

#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/cybergraphics_pragmas.h>

#include <cybergraphics/cybergraphics.h>

#include <jpeg/jpeg.h>
#include <jpeg/jpeg_protos.h>
#include <jpeg/jpeg_pragmas.h>

/* Function prototypes */
__saveds __asm storeline( register __a0 void *scanline, register __d0 ULONG line, register __d1 ULONG bytes, register __a1 void *userdata );

extern struct Library *DOSBase;
struct Library *JpegBase, *IntuitionBase;
struct CyberGfxBase *CyberGfxBase;

void main( int argc, char **argv )
{
	JpegBase = OpenLibrary( "jpeg.library", NULL );
	IntuitionBase = OpenLibrary( "intuition.library", NULL );
	CyberGfxBase = (struct CyberGfxBase *)OpenLibrary( "cybergraphics.library", 0L );

	if ( IntuitionBase != NULL && CyberGfxBase != NULL && JpegBase != NULL )
	{
		ULONG err;
		ULONG DisplayID;
		struct Screen *scr;
		struct Window *win;
		struct Message *msg;
		struct JPEGDecHandle *jph;
		UBYTE *jstream;
		ULONG jstreamsize;
		UBYTE *buffer;
		ULONG x, y;
		BPTR fp, lock;
		struct FileInfoBlock *fib;
		UBYTE colourspace;
		ULONG bpp;

		fib = AllocDosObject( DOS_FIB, TAG_DONE );
		if ( fib != NULL )
		{
			lock = Lock( argv[1], ACCESS_READ );
			if ( lock != NULL )
			{
				if ( Examine( lock, fib ) )
				{
					jstreamsize = fib->fib_Size;

					jstream = AllocVec( jstreamsize, MEMF_PUBLIC | MEMF_CLEAR );
					if ( jstream != NULL )
					{
						fp = OpenFromLock( lock );
						if ( fp != NULL )
						{
							lock = NULL;

							/* Spool file into memory */
							Read( fp, jstream, jstreamsize );

							Close( fp );

							err = AllocJPEGDecompress( &jph,
								JPG_SrcMemStream, jstream,
								JPG_SrcMemStreamSize, jstreamsize,
								TAG_DONE );
							if ( !err )
							{
								err = GetJPEGInfo( jph,
									JPG_Width, &x, JPG_Height, &y,
									JPG_ColourSpace, &colourspace,
									JPG_BytesPerPixel, &bpp,
									JPG_ScaleNum, 1, JPG_ScaleDenom, 2,
									TAG_DONE );
								if ( !err )
								{
									printf( "colourspace=%d\n", colourspace );
									printf( "bytes per pixel=%d\n", bpp );
									printf( "width=%d\n", x );
									printf( "height=%d\n", y );

									buffer = AllocBufferFromJPEG( jph,
										JPG_ScaleNum, 1, JPG_ScaleDenom, 2,
										TAG_DONE );
									if ( buffer != NULL )
									{
										err = DecompressJPEG( jph, JPG_DecompressHook, storeline,
											JPG_DecompressUserData, buffer,
											JPG_ScaleNum, 1, JPG_ScaleDenom, 2,
											TAG_DONE );
										if ( !err )
										{
											DisplayID = BestCModeIDTags( CYBRBIDTG_NominalWidth, 640,
												CYBRBIDTG_NominalHeight, 480,
												CYBRBIDTG_Depth, 24,
												TAG_DONE );

											if ( DisplayID != INVALID_ID )
											{
												scr = OpenScreenTags( NULL,
													SA_Title, "Proof",
													SA_DisplayID, DisplayID,
													SA_Depth, GetCyberIDAttr( CYBRIDATTR_DEPTH, DisplayID ),
													TAG_DONE );

												if ( scr != NULL )
												{
													win = OpenWindowTags( NULL,
														WA_Title, "Proof",
														WA_Flags, WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH |
															WFLG_SIZEGADGET | WFLG_RMBTRAP | WFLG_DRAGBAR |
															WFLG_DEPTHGADGET | WFLG_CLOSEGADGET,
														WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW |
															IDCMP_SIZEVERIFY | IDCMP_NEWSIZE | IDCMP_RAWKEY,
														WA_Left, 16,
														WA_Top, scr->BarHeight+16,
														WA_Width, x,
														WA_Height, y,
														WA_CustomScreen, scr,
														TAG_DONE );

													if ( win != NULL )
													{
														UBYTE format = RECTFMT_RGB;
														UWORD rowwidth = x * 3;

														switch ( colourspace )
														{
															case JPCS_UNKNOWN:
															case JPCS_GRAYSCALE:
																format = RECTFMT_GREY8;
																rowwidth = x * bpp;
															break;
														}

														WritePixelArray( buffer, 0, 0, rowwidth, win->RPort, 0, 0, x, y, format );

														Wait( 1L << win->UserPort->mp_SigBit );
														while ( ( msg = GetMsg( win->UserPort ) ) != NULL ) ReplyMsg( msg );

														CloseWindow( win );
													}
													else printf( "failed to open window\n" );

													CloseScreen( scr );
												}
												else printf( "failed to open screen\n" );
											}
											else printf( "failed to get display id\n" );
										}
										else printf( "decompress jpeg error:%d\n", err );

										FreeJPEGBuffer( buffer );
									}
									else printf( "cant allocate rgb buffer\n" );
								}
								else printf( "get jpeg info error:%d\n", err );

								FreeJPEGDecompress( jph );
							}
							else printf( "alloc jpeg error:%d\n", err );
						}
						else printf( "cant open from lock\n" );

						FreeVec( jstream );
					}
					else printf( "cant allocate jstream buffer\n" );
				}
				else printf( "cant examine file\n" );

				UnLock( lock );
			}
			else printf( "cant lock file\n" );

			FreeDosObject( DOS_FIB, fib );
		}
		else printf( "cant allocate fib\n" );
	}

	if ( JpegBase != NULL ) CloseLibrary( JpegBase );
	if ( IntuitionBase ) CloseLibrary ( IntuitionBase );
	if ( CyberGfxBase ) CloseLibrary ( (struct Library *)CyberGfxBase );
}

__saveds __asm storeline( register __a0 void *scanline, register __d0 ULONG line, register __d1 ULONG bytes, register __a1 void *userdata )
{
	UBYTE *buffer = userdata;

	CopyMem( scanline, buffer + ( ( line - 1 ) * bytes ), bytes );

	return NULL;
}
