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)
/*====================================================================*/