/*	This example use of jpeg.library loads the jpeg file specified
		on the command line and views it 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;

char *version = "$VER: loadmem 1.1 (11.2.2000)";

void main( int argc, char **argv )
{
	if ( argv[1] )
	{
		JpegBase = OpenLibrary( "jpeg.library", 5 );
		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 );
	}
	else
	{
		printf( "no source file specified\n" );
	}
}

__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;
}
