blob: 17e823008c04e03becb1ab5bd9122af5a1aab4a0 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"
#include <tools/color.hxx>
#include <vcl/bmpacc.hxx>
#include <vcl/bitmapex.hxx>
#include <vcl/alpha.hxx>
#include <vcl/pngread.hxx>
#include <vcl/pngwrite.hxx>
#include "bmpcore.hxx"
#include <vcl/dibtools.hxx>
#include <vector>
#include <algorithm>
#undef WRITE_ALPHA_PNG
// -------------------------
// - ImplGetSystemFileName -
// -------------------------
static String ImplGetSystemFileName( const String& rFileName )
{
String aRet( rFileName );
const sal_Unicode aReplace = DirEntry::GetAccessDelimiter( FSYS_STYLE_HOST ).GetChar( 0 );
aRet.SearchAndReplaceAll( '/', aReplace );
aRet.SearchAndReplaceAll( '\\', aReplace );
return aRet;
}
// --------------
// - BmpCreator -
// --------------
BmpCreator::BmpCreator()
{
}
// -----------------------------------------------------------------------------
BmpCreator::~BmpCreator()
{
}
// -----------------------------------------------------------------------------
void BmpCreator::Message( const String&, sal_uInt8 )
{
}
// -----------------------------------------------------------------------
void BmpCreator::ImplCreate( const ::std::vector< DirEntry >& rInDirs,
const DirEntry& rOut,
const String& rName,
const LangInfo& rLang )
{
const sal_uInt32 nOldPos = pSRS->Tell();
const char* pCollectFile = getenv( "BMP_COLLECT_FILE" );
SvFileStream* pCollectStm = pCollectFile ? new SvFileStream( String( pCollectFile, RTL_TEXTENCODING_ASCII_US ),
STREAM_WRITE ) : NULL;
if( pCollectStm )
pCollectStm->Seek( STREAM_SEEK_TO_END );
if( rInDirs.size() )
{
ByteString aLine;
String aInfo, aPrefix, aName( rName ), aString;
SvFileStream aOutStream;
BitmapEx aTotalBmpEx;
DirEntry aOutFile( rOut );
::std::vector< DirEntry > aInFiles( rInDirs );
::std::vector< String > aNameVector;
sal_uInt32 i;
for( i = 0; i < aInFiles.size(); i++ )
aInFiles[ i ] += DirEntry( String( RTL_CONSTASCII_USTRINGPARAM( "xxx.xxx" ) ) );
// get prefix for files
if( ( aName.Len() >= 3 ) && ( aName.GetChar( 2 ) != '_' ) )
aPrefix = String( aName, 0, 3 );
else
aPrefix = String( aName, 0, 2 );
String aNumStr( String::CreateFromAscii( rLang.maLangDir )) ;
if( aNumStr.Len() == 1 )
aNumStr.Insert( '0', 0 );
aName = DirEntry( aName ).GetBase();
aName += String( RTL_CONSTASCII_USTRINGPARAM( ".bmp" ) );
// create output file name
aOutFile += DirEntry( aName );
// get number of bitmaps
while( aLine.Search( '}' ) == STRING_NOTFOUND )
{
if( !pSRS->ReadLine( aLine ) )
break;
aLine.EraseLeadingChars( ' ' );
aLine.EraseLeadingChars( '\t' );
aLine.EraseAllChars( ';' );
if( aLine.IsNumericAscii() )
{
aString = aPrefix;
if( atoi( aLine.GetBuffer() ) < 10000 )
aString += String::CreateFromInt32( 0 );
// search for pngs by default
String aPngString( aString += String( aLine.GetBuffer(), RTL_TEXTENCODING_UTF8 ) );
aNameVector.push_back( aPngString += String( RTL_CONSTASCII_USTRINGPARAM( ".png" ) ) );
}
}
if( !aNameVector.size() )
Message( String( RTL_CONSTASCII_USTRINGPARAM( "WARNING: No imagelist resource found: " ) ).Append( aString ), EXIT_MISSING_RESOURCE );
else
{
// write info
aInfo = String( RTL_CONSTASCII_USTRINGPARAM( "CREATING ImageList for language: " ) );
aInfo += String( ::rtl::OUString::createFromAscii( rLang.maLangDir ) );
aInfo += String( RTL_CONSTASCII_USTRINGPARAM( " [ " ) );
for( i = 0; i < rInDirs.size(); i++ )
( aInfo += rInDirs[ i ].GetFull() ) += String( RTL_CONSTASCII_USTRINGPARAM( "; " ) );
aInfo += String( RTL_CONSTASCII_USTRINGPARAM( " ]" ) );
Message( aInfo );
// create bit vector to hold flags for valid bitmaps
::std::bit_vector aValidBmpBitVector( aNameVector.size(), false );
BitmapEx aBmpEx;
for( sal_uInt32 n = 0; n < aNameVector.size(); n++ )
{
aBmpEx.SetEmpty();
for( i = 0; i < aInFiles.size() && aBmpEx.IsEmpty(); i++ )
{
DirEntry aInFile( aInFiles[ i ] );
aInFile.SetName( aString = aNameVector[ n ] );
bool bPNG = aInFile.Exists();
if( !bPNG )
{
aInFile.SetExtension( String( RTL_CONSTASCII_USTRINGPARAM( "bmp" ) ) );
aString = aInFile.GetName();
}
if( aInFile.Exists() )
{
const String aFileName( aInFile.GetFull() );
SvFileStream aIStm( aFileName, STREAM_READ );
if( bPNG )
{
::vcl::PNGReader aPNGReader( aIStm );
aBmpEx = aPNGReader.Read();
}
else
{
ReadDIBBitmapEx(aBmpEx, aIStm);
}
if( pCollectStm && !aBmpEx.IsEmpty() )
{
const ByteString aCollectString( aFileName, RTL_TEXTENCODING_ASCII_US );
pCollectStm->WriteLine( aCollectString );
}
}
}
const Size aSize( aBmpEx.GetSizePixel() );
if( aBmpEx.IsEmpty() )
{
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: graphic is missing: " ) ).Append( aString ), EXIT_MISSING_BITMAP );
}
else
{
if( aTotalBmpEx.IsEmpty() )
{
// first bitmap determines metrics of total bitmap
Size aTotalSize( aOneSize = aSize );
aTotalSize.Width() *= aNameVector.size();
aTotalBmpEx = Bitmap( aTotalSize, aBmpEx.GetBitmap().GetBitCount() );
}
if( ( aSize.Width() > aOneSize.Width() ) || ( aSize.Height() > aOneSize.Height() ) )
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Different dimensions in file: " ) ).Append( aString ), EXIT_DIMENSIONERROR );
else
{
Point aPoint;
const Rectangle aDst( Point( aOneSize.Width() * n, 0L ), aSize );
const Rectangle aSrc( aPoint, aSize );
if( !aTotalBmpEx.IsEmpty() && !aBmpEx.IsEmpty() && !aDst.IsEmpty() && !aSrc.IsEmpty() )
{
if( !aTotalBmpEx.IsTransparent() && aBmpEx.IsTransparent() )
{
const Bitmap aTmpBmp( aTotalBmpEx.GetBitmap() );
aTotalBmpEx = BitmapEx( aTmpBmp, AlphaMask( aTmpBmp.CreateMask( COL_LIGHTMAGENTA ) ) );
}
else if( aTotalBmpEx.IsTransparent() && !aBmpEx.IsTransparent() )
{
const Bitmap aTmpBmp( aBmpEx.GetBitmap() );
aBmpEx = BitmapEx( aTmpBmp, AlphaMask( aTmpBmp.CreateMask( COL_LIGHTMAGENTA ) ) );
}
aTotalBmpEx.CopyPixel( aDst, aSrc, &aBmpEx );
aValidBmpBitVector[ n ] = true;
}
}
}
}
if( !aTotalBmpEx.IsEmpty() )
{
// do we have invalid bitmaps?
if( ::std::find( aValidBmpBitVector.begin(), aValidBmpBitVector.end(), false ) != aValidBmpBitVector.end() )
{
Bitmap aTmpBmp( aTotalBmpEx.GetBitmap() );
BitmapWriteAccess* pAcc = aTmpBmp.AcquireWriteAccess();
if( pAcc )
{
pAcc->SetLineColor( Color( COL_LIGHTGREEN ) );
for( sal_uInt32 n = 0; n < aValidBmpBitVector.size(); n++ )
{
if( !aValidBmpBitVector[ n ] )
{
const Rectangle aDst( Point( aOneSize.Width() * n, 0L ), aOneSize );
pAcc->DrawRect( aDst );
pAcc->DrawLine( aDst.TopLeft(), aDst.BottomRight() );
pAcc->DrawLine( aDst.TopRight(), aDst.BottomLeft() );
}
}
aTmpBmp.ReleaseAccess( pAcc );
if( aTotalBmpEx.IsAlpha() )
aTotalBmpEx = BitmapEx( aTmpBmp, aTotalBmpEx.GetAlpha() );
else if( aTotalBmpEx.IsTransparent() )
aTotalBmpEx = BitmapEx( aTmpBmp, aTotalBmpEx.GetMask() );
else
aTotalBmpEx = aTmpBmp;
}
}
// write output file
const String aOutFileName( aOutFile.GetFull() );
aOutStream.Open( aOutFileName, STREAM_WRITE | STREAM_TRUNC );
if( !aOutStream.IsOpen() )
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Could not open output file: " ) ).Append( aOutFileName ), EXIT_IOERROR );
else
{
if( aOutFileName.Search( String( RTL_CONSTASCII_USTRINGPARAM( ".png" ) ) ) != STRING_NOTFOUND )
{
::vcl::PNGWriter aPNGWriter( aTotalBmpEx );
aPNGWriter.Write( aOutStream );
}
else
{
WriteDIBBitmapEx(aTotalBmpEx, aOutStream);
}
if( aOutStream.GetError() )
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Could not write to output file: " ) ).Append( aOutFileName ), EXIT_IOERROR );
else
Message( String( RTL_CONSTASCII_USTRINGPARAM( "Successfully generated ImageList " ) ).Append( aOutFileName ) );
aOutStream.Close();
}
}
else
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Could not generate " ) ).Append( aOutFile.GetFull() ), EXIT_COMMONERROR );
Message( ' ' );
}
}
else
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: SOLARSRC environment variable not set!" ) ), EXIT_MISSING_SOLARSRC_ENV );
pSRS->Seek( nOldPos );
delete pCollectStm;
}
// -----------------------------------------------------------------------------
void BmpCreator::Create( const String& rSRSName,
const ::std::vector< String >& rInDirs,
const String& rOutName,
const LangInfo& rLang )
{
DirEntry aFileName( ImplGetSystemFileName( rSRSName ) ), aOutDir( ImplGetSystemFileName( rOutName ) );
::std::vector< DirEntry > aInDirs;
sal_Bool bDone = sal_False;
aFileName.ToAbs();
aOutDir.ToAbs();
// create vector of all valid input directories,
// including language subdirectories
for( sal_uInt32 i = 0; i < rInDirs.size(); i++ )
{
DirEntry aInDir( ImplGetSystemFileName( rInDirs[ i ] ) );
aInDir.ToAbs();
if( aInDir.Exists() )
{
DirEntry aLangInDir( aInDir );
if( ( aLangInDir += DirEntry( ::rtl::OUString::createFromAscii( rLang.maLangDir ) ) ).Exists() )
aInDirs.push_back( aLangInDir );
aInDirs.push_back( aInDir );
}
}
pSRS = new SvFileStream ( aFileName.GetFull(), STREAM_STD_READ );
if( pSRS->GetError() )
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Kein SRS file!" ) ), EXIT_NOSRSFILE );
else
{
String aText;
ByteString aByteText;
sal_Bool bLangDep = sal_False;
do
{
do
{
if (!pSRS->ReadLine(aByteText))
break;
}
while ( aByteText.Search( "ImageList" ) == STRING_NOTFOUND );
do
{
if (!pSRS->ReadLine( aByteText ) )
break;
}
while ( aByteText.Search( "File" ) == STRING_NOTFOUND );
aText = String::CreateFromAscii( aByteText.GetBuffer() );
const String aName( aText.GetToken( 1, '"' ) );
do
{
if( !bLangDep &&
aByteText.Search( "File" ) != STRING_NOTFOUND &&
aByteText.Search( '[' ) != STRING_NOTFOUND &&
aByteText.Search( ']' ) != STRING_NOTFOUND )
{
bLangDep = sal_True;
}
if (!pSRS->ReadLine(aByteText))
break;
}
while (aByteText.Search( "IdList" ) == STRING_NOTFOUND );
aText = String::CreateFromAscii( aByteText.GetBuffer() );
// if image list is not language dependent, don't do anything for languages except german
if( aText.Len() )
{
bDone = sal_True;
ImplCreate( aInDirs, aOutDir, aName, rLang );
}
/* else if( ( rLang.mnLangNum != 49 ) && !bLangDep )
{
Message( String( RTL_CONSTASCII_USTRINGPARAM( "INFO: ImageList is not language dependent! Nothing to do for this language." ) ) );
bDone = sal_True;
}*/
}
while ( aText.Len() );
}
if( !bDone )
Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: No ImageList found in SRS file!" ) ), EXIT_NOIMGLIST );
delete pSRS;
}