Re: MNG/JNG specification updates

Adeluc <png-8CwYj0sA/[email protected]>
Newsgroups gmane.comp.graphics.png.general
Organization Adeluc
Message-ID <A4FE87F9D6CA49C0A638787D69945A17@HPP72600MHZ>
When I create the "Stereo Image Maker v2.0.10 Alpha" freeware software to 
demonstrate the possibilities of the "sTER" chunk, I wanted to include an 
import JPS feature.  So I made some searches to get the file format 
specifications.  A JPS file is essentially a JPG file with a "Stereo 
Descriptor".  This "Stereo Descriptor" as the JPS extension has been created 
by the (no more existing) "VRex Inc" company that was selling affordable 3D 
helmet.

The original "JPS Specifications.pdf" file can de downloaded from this link:
http://paulbourke.net/dataformats/stereoimage/spec.pdf

I included two other small files that may help anyone who need to work with 
JPS files.

The included "jpssdflags.h" header file contains useful defines and macros.

The included "GetFileInfoJPG.cpp" file contains an example of how to 
retrieve descriptors from JPG/JPS files.


Jean-Claude Hébert
Adeluc

------------------------------------------------------------------------------

_______________________________________________
png-mng-misc mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/png-mng-misc
GetFileInfoJPG.cpp (text/plain, 7.9 KB)
////////////////////////////////////////////////////////////////////////////
/////////////////////////
//																																	//
//	Coded by www.adeluc.com   All rights reserved.    Created: 2004-10-28©
Modified: 2011-07-01©	//
//																																	//
//	Purpose:	1- Test if the specified file can be read and if so then get the
file status.				//
//				2- Test if the specified file is a valid JPG or JPS file.										//
//																																	//
//	'pfsFileStatus': May be NULL if you do not need this information.
//
//																																	//
//	'punWidth': May be NULL if you do not need this information.
//
//																																	//
//	'punHeight': May be NULL if you do not need this information.
//
//																																	//
//	'pnBitDepth': May be NULL if you do not need this information.
//
//																																	//
//	'pnColorSpace': May be NULL if you do not need this information.
//
//																																	//
//	'punJPSStereoDataDescriptor': May be NULL if you do not need this
information.  When				//
//											'punJPSStereoDataDescriptor' == 0, if an JPS Stereo Data				//
//											Descriptor marker is present in the file, it will be completely
//
//											ignored and of course no error checking about this descriptor
//
//											data will be made.  If its returned contents value is set to
//
//											0xFFFFFFFF (not a valid value), then that means no valid JPS
//
//											Stereo Data Descriptor marker has been found.							//
//																																	//
//	'pnResolutionX': May be NULL if you do not need this information.
//
//																																	//
//	'pnResolutionY': May be NULL if you do not need this information.
//
//																																	//
//	'pnResolutionType': May be NULL if you do not need this information.
//
//							  Possible values are rutUnknown, rutInch or rutCentimeter.
//
//																																	//
//	Result: Returns fecOk if no error occurs.																			//
//			  Returns fecInvalid if the file is not a valid JPG or JPS file.
//
//			  Returns fecFileNotFound if the file doesn't exist.													//
//																																	//
////////////////////////////////////////////////////////////////////////////
/////////////////////////

int JCH_PixelMap::GetFileInfoJPG( LPCTSTR pcszFileName, struct CFileStatus
*pfsFileStatus, unsigned int *punWidth,
											 unsigned int *punHeight, int *pnBitDepth, int *pnColorSpace,
											 unsigned int *punJPSStereoDataDescriptor, int *pnResolutionX,
											 int *pnResolutionY, ResolutionUnitType *pnResolutionType )
{
	int									nStatus			= fecOk;
	bool									bCallDestroy	= FALSE;
	bool									bGetStereoInfo	= (punJPSStereoDataDescriptor != 0);
	unsigned int						unJPSStereoDataDescriptor = 0xFFFFFFFF;	//	Not a valid
value.
	unsigned int						unTmp;
	jpeg_saved_marker_ptr			pSavedMarker;
	struct jpeg_decompress_struct	jdinfo;
	JCH_JPG_Error_Mgr					jerr;
	CStdioFile							file;
	CFileStatus							fsFileStatus;

	//------------------------------------------------

	try
	{
		if ( (nStatus == fecOk) && !file.Open( pcszFileName,
				(CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary) ) )
		{
			nStatus = fecFileNotFound;
		}

		if ( (nStatus == fecOk) && (pfsFileStatus != 0) && !file.GetStatus(
fsFileStatus ) )
		{
			nStatus = fecFileNotFound;
		}

		if ( nStatus == fecOk )
		{
			jdinfo.err = jpeg_std_error( &jerr.err_mgr );
			jerr.err_mgr.error_exit = JCH_JPG_Error_Exit;

			if ( setjmp( jerr.setjmp_buffer ) )
			{
				nStatus = fecInvalid;		//	If we get here, the JPEG code has signaled an
error.
			}
		}

		//------------------------------------------------

		if ( nStatus == fecOk )
		{
			bCallDestroy = TRUE;
			jpeg_create_decompress( &jdinfo );
			jpeg_stdio_src( &jdinfo, file.m_pStream );

			if ( bGetStereoInfo ) jpeg_save_markers( &jdinfo, (JPEG_APP0 + 3), 14 );
// JPS Stereoscopic Descriptor is stored in JPEG_APP03.

			jpeg_read_header( &jdinfo, TRUE );

			//················································

			if ( bGetStereoInfo )
			{
				for( pSavedMarker = jdinfo.marker_list; pSavedMarker != 0; pSavedMarker
= pSavedMarker->next )
				{
					if ( (pSavedMarker->marker == (JPEG_APP0 + 3)) &&
(pSavedMarker->data_length == 14) &&
							(strncmp( (const char *)&pSavedMarker->data[0], cszJPSSDDId_JPSJPS_,
8 ) == 0) &&
							(((((unsigned int)pSavedMarker->data[8]) << 8) |
pSavedMarker->data[9]) >= 4) )
					{
						if ( unJPSStereoDataDescriptor == 0xFFFFFFFF )	//	Value not set yet?
						{
							unTmp = ((((unsigned int)pSavedMarker->data[10]) << 24) |
										(((unsigned int)pSavedMarker->data[11]) << 16) |
										(((unsigned int)pSavedMarker->data[12]) <<  8) |
pSavedMarker->data[13]);

							if ( JPS_IS_VALID_DESCRIPTOR( unTmp ) )
							{
								//	Clearing unused bits from descriptor value to be sure to make a
clean load.
								if ( JPS_IS_MONOSCOPIC( unTmp ) )
								{
									unTmp &= (JPS_SD_MEDIA_TYPE_MASK | JPS_SD_DISPLAY_MASK |
												 /*JPS_SD_FULL_HEIGHT*/JPS_SD_HALF_HEIGHT | JPS_SD_HALF_WIDTH);
								}
								else	//	if ( JPS_IS_STEREOSCOPIC( unTmp ) )
								{
									if ( JPS_IS_LAYOUT_INTERLEAVED( unTmp ) ||
JPS_IS_LAYOUT_ANAGLYPH( unTmp ) )
									{
										unTmp &= (JPS_SD_MEDIA_TYPE_MASK | JPS_SD_DISPLAY_MASK |
/*JPS_SD_FULL_HEIGHT*/JPS_SD_HALF_HEIGHT |
													 JPS_SD_HALF_WIDTH | JPS_SD_LEFT_FIELD_FIRST);
									}
									else	//	if ( JPS_IS_LAYOUT_SIDEBYSIDE( unTmp ) ||
JPS_IS_LAYOUT_OVERUNDER( unTmp ) )
									{
										unTmp &= (JPS_SD_MEDIA_TYPE_MASK | JPS_SD_DISPLAY_MASK |
/*JPS_SD_FULL_HEIGHT*/JPS_SD_HALF_HEIGHT |
													 JPS_SD_HALF_WIDTH | JPS_SD_LEFT_FIELD_FIRST |
JPS_SD_FIELD_SEPARATION_MASK);
									}
								}

								unJPSStereoDataDescriptor = unTmp;
							}
							else
							{
								nStatus = fecInvalid;	//	Invalid descriptor value.
								break;
							}
						}
						else
						{
							nStatus = fecInvalid;	//	Error: Dupplicate JPSSDD marker found.
							break;
						}
					}
				}
			}

			//················································

			if ( nStatus == fecOk )
			{
				if ( (jdinfo.jpeg_color_space == JCS_GRAYSCALE) ||
					  (jdinfo.jpeg_color_space == JCS_RGB) || (jdinfo.jpeg_color_space ==
JCS_YCbCr) )
				{
					jdinfo.dct_method = JDCT_FLOAT;
					jpeg_calc_output_dimensions( &jdinfo );

					if ( (jdinfo.output_width != 0) && (jdinfo.output_height != 0) &&
						 ((jdinfo.output_components == 1) || (jdinfo.output_components ==
3)) )
					{
						if ( pfsFileStatus != 0 ) *(pfsFileStatus) = fsFileStatus;
						if ( punWidth		 != 0 ) *(punWidth)		 = jdinfo.output_width;
						if ( punHeight		 != 0 ) *(punHeight)		 = jdinfo.output_height;
						if ( pnBitDepth	 != 0 ) *(pnBitDepth)	 = (jdinfo.output_components *
BITS_IN_JSAMPLE);
						if ( pnColorSpace	 != 0 ) *(pnColorSpace)	 = jdinfo.out_color_space;
						if ( pnResolutionX != 0 ) *(pnResolutionX) = jdinfo.X_density;
						if ( pnResolutionY != 0 ) *(pnResolutionY) = jdinfo.Y_density;

						if ( punJPSStereoDataDescriptor != 0 ) *(punJPSStereoDataDescriptor) =
unJPSStereoDataDescriptor;

						if ( pnResolutionType != 0 )
						{
							if		  ( jdinfo.density_unit == 1 ) *(pnResolutionType) = rutInch;
							else if ( jdinfo.density_unit == 2 ) *(pnResolutionType) =
rutCentimeter;
							else											 *(pnResolutionType) = rutUnknown;
						}
					}
					else nStatus = fecInvalid;
				}
				else nStatus = fecInvalid;
			}
		}
	}

	//------------------------------------------------

	catch( CFileException *pException )
	{
		pException->Delete();
		nStatus = fecInvalid;
	}

	//------------------------------------------------

	if ( bCallDestroy )
	{
		jpeg_destroy_decompress( &jdinfo );
		bCallDestroy = FALSE;
	}

	if ( file.m_hFile != CFile::hFileNull ) file.Close();		// Also
automatically called by its destructor.

	//------------------------------------------------

	return( nStatus );
}
jpssdflags.h (text/plain, 3.9 KB)
#pragma once

/*=====================================================================
 *
 * jpssdflags.h -- JPS general purpose stereoscopic descriptor
 *
 *	Fixes and improvements made by www.adeluc.com  July-2011.
 *
 *====================================================================*/
/*
 * MEDIA TYPE
 */
#define JPS_SD_MEDIA_TYPE_MASK          0x000000FF
#define JPS_SD_MTYPE_MONOSCOPIC_IMAGE   0x00000000
#define JPS_SD_MTYPE_STEREOSCOPIC_IMAGE 0x00000001
/*
 * DISPLAY options for JPS_SD_MTYPE_MONOSCOPIC_IMAGE
 */
#define JPS_SD_DISPLAY_MASK 0x0000FF00
#define JPS_SD_EYE_BOTH     0x00000000
#define JPS_SD_EYE_LEFT     0x00000100
#define JPS_SD_EYE_RIGHT    0x00000200
/*
 * LAYOUT options for JPS_SD_MTYPE_STEREOSCOPIC_IMAGE
 */
#define JPS_SD_LAYOUT_MASK        0x0000FF00
#define JPS_SD_LAYOUT_INTERLEAVED 0x00000100
#define JPS_SD_LAYOUT_SIDEBYSIDE  0x00000200
#define JPS_SD_LAYOUT_OVERUNDER   0x00000300
#define JPS_SD_LAYOUT_ANAGLYPH    0x00000400
/*
 * MISCELLANEOUS FLAGS bits
 */
#define JPS_SD_MISC_FLAGS_MASK     0x00FF0000
#define JPS_SD_FULL_HEIGHT         0x00000000
#define JPS_SD_HALF_HEIGHT         0x00010000
#define JPS_SD_FULL_WIDTH          0x00000000
#define JPS_SD_HALF_WIDTH          0x00020000
#define JPS_SD_RIGHT_FIELD_FIRST   0x00000000
#define JPS_SD_LEFT_FIELD_FIRST    0x00040000
#define JPS_SD_RED_FIELD_RIGHT_EYE 0x00000000
#define JPS_SD_RED_FIELD_LEFT_EYE  0x00040000
/*
 * FIELD_SEPARATION
 */
#define JPS_SD_FIELD_SEPARATION_MASK 0xFF000000
/*
 * Handy macros
 */
#define JPS_GET_MEDIA_TYPE(f) ((f) & JPS_SD_MEDIA_TYPE_MASK)
#define JPS_GET_DISPLAY(f)    ((f) & JPS_SD_DISPLAY_MASK   )
#define JPS_GET_LAYOUT(f)     ((f) & JPS_SD_LAYOUT_MASK    )
#define JPS_GET_MISC_FLAGS(f) ((f) & JPS_SD_MISC_FLAGS_MASK)

#define JPS_GET_FIELD_SEPARATION(f)   (((unsigned int)(f)) >> 24)
#define JPS_SET_FIELD_SEPARATION(f,s) ((((unsigned int)(s)) << 24) | ((f) &
~JPS_SD_FIELD_SEPARATION_MASK))

#define JPS_IS_MONOSCOPIC(f)   (JPS_GET_MEDIA_TYPE(f) ==
JPS_SD_MTYPE_MONOSCOPIC_IMAGE  )
#define JPS_IS_STEREOSCOPIC(f) (JPS_GET_MEDIA_TYPE(f) ==
JPS_SD_MTYPE_STEREOSCOPIC_IMAGE)

#define JPS_IS_DISPLAY_EYE_BOTH(f)  (JPS_GET_DISPLAY(f) == JPS_SD_EYE_BOTH )
#define JPS_IS_DISPLAY_EYE_LEFT(f)  (JPS_GET_DISPLAY(f) == JPS_SD_EYE_LEFT )
#define JPS_IS_DISPLAY_EYE_RIGHT(f) (JPS_GET_DISPLAY(f) == JPS_SD_EYE_RIGHT)

#define JPS_IS_LAYOUT_INTERLEAVED(f) (JPS_GET_LAYOUT(f) ==
JPS_SD_LAYOUT_INTERLEAVED)
#define JPS_IS_LAYOUT_SIDEBYSIDE(f)  (JPS_GET_LAYOUT(f) ==
JPS_SD_LAYOUT_SIDEBYSIDE )
#define JPS_IS_LAYOUT_OVERUNDER(f)   (JPS_GET_LAYOUT(f) ==
JPS_SD_LAYOUT_OVERUNDER  )
#define JPS_IS_LAYOUT_ANAGLYPH(f)    (JPS_GET_LAYOUT(f) ==
JPS_SD_LAYOUT_ANAGLYPH   )

#define JPS_IS_FULL_HEIGHT(f) (((f) & JPS_SD_HALF_HEIGHT       ) == 0)
#define JPS_IS_HALF_HEIGHT(f) (((f) & JPS_SD_HALF_HEIGHT       ) != 0)
#define JPS_IS_FULL_WIDTH(f)  (((f) & JPS_SD_HALF_WIDTH        ) == 0)
#define JPS_IS_HALF_WIDTH(f)  (((f) & JPS_SD_HALF_WIDTH        ) != 0)
#define JPS_IS_RIGHT_FIRST(f) (((f) & JPS_SD_LEFT_FIELD_FIRST  ) == 0)
#define JPS_IS_LEFT_FIRST(f)  (((f) & JPS_SD_LEFT_FIELD_FIRST  ) != 0)
#define JPS_IS_RIGHT_RED(f)   (((f) & JPS_SD_RED_FIELD_LEFT_EYE) == 0)
#define JPS_IS_LEFT_RED(f)    (((f) & JPS_SD_RED_FIELD_LEFT_EYE) != 0)

#define JPS_IS_VALID_DESCRIPTOR(f)                                         \
   ((JPS_IS_MONOSCOPIC(f) && (JPS_IS_DISPLAY_EYE_BOTH(f) ||                \
     JPS_IS_DISPLAY_EYE_LEFT(f) || JPS_IS_DISPLAY_EYE_RIGHT(f))) ||        \
    (JPS_IS_STEREOSCOPIC(f) && (JPS_IS_LAYOUT_INTERLEAVED(f) ||            \
     JPS_IS_LAYOUT_SIDEBYSIDE(f) || JPS_IS_LAYOUT_OVERUNDER(f) ||
JPS_IS_LAYOUT_ANAGLYPH(f))))
/*
 * Defaults
 */
#define JPS_SD_DEFAULT (JPS_SD_MTYPE_STEREOSCOPIC_IMAGE |                  \
                        JPS_SD_LAYOUT_SIDEBYSIDE | JPS_SD_FULL_HEIGHT |    \
                        JPS_SD_FULL_WIDTH | JPS_SD_RIGHT_FIELD_FIRST)

/*====================================================================*/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.