xref: /aoo4110/main/svtools/bmpmaker/bmpcore.cxx (revision b1cdbd2c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svtools.hxx"
24 
25 #include <tools/color.hxx>
26 #include <vcl/bmpacc.hxx>
27 #include <vcl/bitmapex.hxx>
28 #include <vcl/alpha.hxx>
29 #include <vcl/pngread.hxx>
30 #include <vcl/pngwrite.hxx>
31 #include "bmpcore.hxx"
32 #include <vcl/dibtools.hxx>
33 #include <vector>
34 #include <algorithm>
35 
36 #undef WRITE_ALPHA_PNG
37 
38 // -------------------------
39 // - ImplGetSystemFileName -
40 // -------------------------
41 
ImplGetSystemFileName(const String & rFileName)42 static String ImplGetSystemFileName( const String& rFileName )
43 {
44     String              aRet( rFileName );
45     const sal_Unicode   aReplace = DirEntry::GetAccessDelimiter( FSYS_STYLE_HOST ).GetChar( 0 );
46 
47     aRet.SearchAndReplaceAll( '/', aReplace );
48     aRet.SearchAndReplaceAll( '\\', aReplace );
49 
50     return aRet;
51 }
52 
53 // --------------
54 // - BmpCreator -
55 // --------------
56 
BmpCreator()57 BmpCreator::BmpCreator()
58 {
59 }
60 
61 // -----------------------------------------------------------------------------
62 
~BmpCreator()63 BmpCreator::~BmpCreator()
64 {
65 }
66 
67 // -----------------------------------------------------------------------------
68 
Message(const String &,sal_uInt8)69 void BmpCreator::Message( const String&, sal_uInt8 )
70 {
71 }
72 
73 // -----------------------------------------------------------------------
74 
ImplCreate(const::std::vector<DirEntry> & rInDirs,const DirEntry & rOut,const String & rName,const LangInfo & rLang)75 void BmpCreator::ImplCreate( const ::std::vector< DirEntry >& rInDirs,
76                              const DirEntry& rOut,
77                              const String& rName,
78                              const LangInfo& rLang )
79 {
80     const sal_uInt32    nOldPos = pSRS->Tell();
81    	const char*         pCollectFile = getenv( "BMP_COLLECT_FILE" );
82    	SvFileStream*       pCollectStm = pCollectFile ? new SvFileStream( String( pCollectFile, RTL_TEXTENCODING_ASCII_US ),
83    	                                                                   STREAM_WRITE ) : NULL;
84 
85     if( pCollectStm )
86         pCollectStm->Seek( STREAM_SEEK_TO_END );
87 
88 	if( rInDirs.size() )
89 	{
90 	    ByteString                  aLine;
91         String 				        aInfo, aPrefix, aName( rName ), aString;
92 	    SvFileStream		        aOutStream;
93 	    BitmapEx				    aTotalBmpEx;
94 	    DirEntry			        aOutFile( rOut );
95 	    ::std::vector< DirEntry >   aInFiles( rInDirs );
96         ::std::vector< String >     aNameVector;
97         sal_uInt32                  i;
98 
99         for( i = 0; i < aInFiles.size(); i++ )
100             aInFiles[ i ] += DirEntry( String( RTL_CONSTASCII_USTRINGPARAM( "xxx.xxx" ) ) );
101 
102         // get prefix for files
103         if( ( aName.Len() >= 3 ) && ( aName.GetChar( 2 ) != '_' ) )
104             aPrefix = String( aName, 0, 3 );
105         else
106             aPrefix = String( aName, 0, 2 );
107 
108 		    String aNumStr( String::CreateFromAscii( rLang.maLangDir )) ;
109 
110 		    if( aNumStr.Len() == 1 )
111 			    aNumStr.Insert( '0', 0 );
112 
113 		    aName = DirEntry( aName ).GetBase();
114 		    aName += String( RTL_CONSTASCII_USTRINGPARAM( ".bmp" ) );
115 
116 	    // create output file name
117         aOutFile += DirEntry( aName );
118 
119 	    // get number of bitmaps
120         while( aLine.Search( '}' ) == STRING_NOTFOUND )
121 	    {
122 		    if( !pSRS->ReadLine( aLine ) )
123 			    break;
124 
125 		    aLine.EraseLeadingChars( ' ' );
126 		    aLine.EraseLeadingChars( '\t' );
127 		    aLine.EraseAllChars( ';' );
128 
129 		    if( aLine.IsNumericAscii() )
130             {
131                 aString = aPrefix;
132 
133                 if( atoi( aLine.GetBuffer() ) < 10000 )
134                     aString += String::CreateFromInt32( 0 );
135 
136                 // search for pngs by default
137                 String aPngString( aString += String( aLine.GetBuffer(), RTL_TEXTENCODING_UTF8 ) );
138                 aNameVector.push_back( aPngString += String( RTL_CONSTASCII_USTRINGPARAM( ".png" ) ) );
139            }
140 	    }
141 
142 	    if( !aNameVector.size() )
143 		    Message( String( RTL_CONSTASCII_USTRINGPARAM( "WARNING: No imagelist resource found: " ) ).Append( aString ), EXIT_MISSING_RESOURCE );
144         else
145         {
146 	        // write info
147 	        aInfo = String( RTL_CONSTASCII_USTRINGPARAM( "CREATING ImageList for language: " ) );
148 	        aInfo += String( ::rtl::OUString::createFromAscii( rLang.maLangDir ) );
149 	        aInfo += String( RTL_CONSTASCII_USTRINGPARAM( " [ " ) );
150 
151 	        for( i = 0; i < rInDirs.size(); i++ )
152 	            ( aInfo += rInDirs[ i ].GetFull() ) += String( RTL_CONSTASCII_USTRINGPARAM( "; " ) );
153 
154             aInfo += String( RTL_CONSTASCII_USTRINGPARAM( " ]" ) );
155 	        Message( aInfo );
156 
157             // create bit vector to hold flags for valid bitmaps
158             ::std::bit_vector   aValidBmpBitVector( aNameVector.size(), false );
159             BitmapEx            aBmpEx;
160 
161 	        for( sal_uInt32 n = 0; n < aNameVector.size(); n++ )
162 	        {
163                 aBmpEx.SetEmpty();
164 
165                 for( i = 0; i < aInFiles.size() && aBmpEx.IsEmpty(); i++ )
166                 {
167                     DirEntry aInFile( aInFiles[ i ] );
168 
169                     aInFile.SetName( aString = aNameVector[ n ] );
170                     bool bPNG = aInFile.Exists();
171 
172                     if( !bPNG )
173 		    {
174                         aInFile.SetExtension( String( RTL_CONSTASCII_USTRINGPARAM( "bmp" ) ) );
175 			aString = aInFile.GetName();
176 		    }
177 
178                     if( aInFile.Exists() )
179                     {
180                         const String    aFileName( aInFile.GetFull() );
181 			            SvFileStream    aIStm( aFileName, STREAM_READ );
182 
183                         if( bPNG )
184                         {
185                             ::vcl::PNGReader aPNGReader( aIStm );
186                             aBmpEx = aPNGReader.Read();
187                         }
188                         else
189                         {
190                             ReadDIBBitmapEx(aBmpEx, aIStm);
191                         }
192 
193                         if( pCollectStm && !aBmpEx.IsEmpty() )
194                         {
195                             const ByteString aCollectString( aFileName, RTL_TEXTENCODING_ASCII_US );
196                             pCollectStm->WriteLine( aCollectString );
197                         }
198                     }
199 		        }
200 
201                 const Size aSize( aBmpEx.GetSizePixel() );
202 
203 		        if( aBmpEx.IsEmpty() )
204 				{
205                     Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: graphic is missing: " ) ).Append( aString ), EXIT_MISSING_BITMAP );
206 				}
207                 else
208                 {
209 		            if( aTotalBmpEx.IsEmpty() )
210 		            {
211                         // first bitmap determines metrics of total bitmap
212 			            Size aTotalSize( aOneSize = aSize );
213 
214                         aTotalSize.Width() *= aNameVector.size();
215                         aTotalBmpEx = Bitmap( aTotalSize, aBmpEx.GetBitmap().GetBitCount() );
216 		            }
217 
218 		            if( ( aSize.Width() > aOneSize.Width() ) || ( aSize.Height() > aOneSize.Height() ) )
219  			            Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Different dimensions in file: " ) ).Append( aString ), EXIT_DIMENSIONERROR );
220 		            else
221 		            {
222 			            Point           aPoint;
223 			            const Rectangle aDst( Point( aOneSize.Width() * n, 0L ), aSize );
224 			            const Rectangle aSrc( aPoint, aSize );
225 
226 			            if( !aTotalBmpEx.IsEmpty() && !aBmpEx.IsEmpty() && !aDst.IsEmpty() && !aSrc.IsEmpty() )
227                         {
228                             if( !aTotalBmpEx.IsTransparent() && aBmpEx.IsTransparent() )
229                             {
230                                 const Bitmap aTmpBmp( aTotalBmpEx.GetBitmap() );
231                                 aTotalBmpEx = BitmapEx( aTmpBmp, AlphaMask( aTmpBmp.CreateMask( COL_LIGHTMAGENTA ) ) );
232                             }
233                             else if( aTotalBmpEx.IsTransparent() && !aBmpEx.IsTransparent() )
234                             {
235                                 const Bitmap aTmpBmp( aBmpEx.GetBitmap() );
236                                 aBmpEx = BitmapEx( aTmpBmp, AlphaMask( aTmpBmp.CreateMask( COL_LIGHTMAGENTA ) ) );
237                             }
238 
239 				            aTotalBmpEx.CopyPixel( aDst, aSrc, &aBmpEx );
240                             aValidBmpBitVector[ n ] = true;
241                         }
242 		            }
243                 }
244 	        }
245 
246             if( !aTotalBmpEx.IsEmpty() )
247             {
248                 // do we have invalid bitmaps?
249                 if( ::std::find( aValidBmpBitVector.begin(), aValidBmpBitVector.end(), false ) != aValidBmpBitVector.end() )
250                 {
251                     Bitmap              aTmpBmp( aTotalBmpEx.GetBitmap() );
252                     BitmapWriteAccess*  pAcc = aTmpBmp.AcquireWriteAccess();
253 
254                     if( pAcc )
255                     {
256                         pAcc->SetLineColor( Color( COL_LIGHTGREEN ) );
257 
258 	                    for( sal_uInt32 n = 0; n < aValidBmpBitVector.size(); n++ )
259                         {
260                             if( !aValidBmpBitVector[ n ] )
261                             {
262 			                    const Rectangle aDst( Point( aOneSize.Width() * n, 0L ), aOneSize );
263 
264 			                    pAcc->DrawRect( aDst );
265 			                    pAcc->DrawLine( aDst.TopLeft(), aDst.BottomRight() );
266 			                    pAcc->DrawLine( aDst.TopRight(), aDst.BottomLeft() );
267                             }
268                         }
269 
270                         aTmpBmp.ReleaseAccess( pAcc );
271 
272                         if( aTotalBmpEx.IsAlpha() )
273                             aTotalBmpEx = BitmapEx( aTmpBmp, aTotalBmpEx.GetAlpha() );
274                         else if( aTotalBmpEx.IsTransparent() )
275                             aTotalBmpEx = BitmapEx( aTmpBmp, aTotalBmpEx.GetMask() );
276                         else
277                             aTotalBmpEx = aTmpBmp;
278                     }
279                 }
280 
281 		        // write output file
282                 const String aOutFileName( aOutFile.GetFull() );
283 
284 		        aOutStream.Open( aOutFileName, STREAM_WRITE | STREAM_TRUNC );
285 
286 		        if( !aOutStream.IsOpen() )
287 			        Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Could not open output file: " ) ).Append( aOutFileName ), EXIT_IOERROR );
288 		        else
289 		        {
290                     if( aOutFileName.Search( String( RTL_CONSTASCII_USTRINGPARAM( ".png" ) ) ) != STRING_NOTFOUND )
291                     {
292                         ::vcl::PNGWriter aPNGWriter( aTotalBmpEx );
293                         aPNGWriter.Write( aOutStream );
294                     }
295                     else
296                     {
297                         WriteDIBBitmapEx(aTotalBmpEx, aOutStream);
298                     }
299 
300                     if( aOutStream.GetError()  )
301 				        Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Could not write to output file: " ) ).Append( aOutFileName ), EXIT_IOERROR );
302 			        else
303 				        Message( String( RTL_CONSTASCII_USTRINGPARAM( "Successfully generated ImageList " ) ).Append( aOutFileName ) );
304 
305 			        aOutStream.Close();
306 		        }
307 	        }
308 	        else
309 		        Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Could not generate  " ) ).Append( aOutFile.GetFull() ), EXIT_COMMONERROR );
310 
311 	        Message( ' ' );
312         }
313 	}
314 	else
315         Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: SOLARSRC environment variable not set!" ) ), EXIT_MISSING_SOLARSRC_ENV );
316 
317     pSRS->Seek( nOldPos );
318     delete pCollectStm;
319 }
320 
321 // -----------------------------------------------------------------------------
322 
Create(const String & rSRSName,const::std::vector<String> & rInDirs,const String & rOutName,const LangInfo & rLang)323 void BmpCreator::Create( const String& rSRSName,
324                          const ::std::vector< String >& rInDirs,
325 			             const String& rOutName,
326 			             const LangInfo& rLang )
327 {
328 	DirEntry	                aFileName( ImplGetSystemFileName( rSRSName ) ), aOutDir( ImplGetSystemFileName( rOutName ) );
329 	::std::vector< DirEntry >   aInDirs;
330 	sal_Bool		                bDone = sal_False;
331 
332 	aFileName.ToAbs();
333 	aOutDir.ToAbs();
334 
335 	// create vector of all valid input directories,
336 	// including language subdirectories
337 	for( sal_uInt32 i = 0; i < rInDirs.size(); i++ )
338 	{
339 		DirEntry aInDir( ImplGetSystemFileName( rInDirs[ i ] ) );
340 
341 		aInDir.ToAbs();
342 
343 		if( aInDir.Exists() )
344 		{
345 			DirEntry aLangInDir( aInDir );
346 
347 			if( ( aLangInDir += DirEntry( ::rtl::OUString::createFromAscii( rLang.maLangDir ) ) ).Exists() )
348 				aInDirs.push_back( aLangInDir );
349 
350 			aInDirs.push_back( aInDir );
351 		}
352 	}
353 
354 	pSRS = new SvFileStream ( aFileName.GetFull(), STREAM_STD_READ );
355 
356 	if( pSRS->GetError() )
357 		Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: Kein SRS file!" ) ), EXIT_NOSRSFILE );
358 	else
359 	{
360 		String		aText;
361 		ByteString	aByteText;
362 		sal_Bool		bLangDep = sal_False;
363 
364 		do
365 		{
366 			do
367 			{
368 				if (!pSRS->ReadLine(aByteText))
369 					break;
370 			}
371 			while ( aByteText.Search( "ImageList" ) == STRING_NOTFOUND );
372 
373 			do
374 			{
375 				if (!pSRS->ReadLine( aByteText ) )
376 					break;
377 			}
378 			while ( aByteText.Search( "File" ) == STRING_NOTFOUND );
379 			aText = String::CreateFromAscii( aByteText.GetBuffer() );
380 
381 			const String aName( aText.GetToken( 1, '"' ) );
382 
383 			do
384 			{
385 				if( !bLangDep &&
386 					aByteText.Search( "File" ) != STRING_NOTFOUND &&
387 					aByteText.Search( '[' ) != STRING_NOTFOUND &&
388 					aByteText.Search( ']' ) != STRING_NOTFOUND )
389 				{
390 					bLangDep = sal_True;
391 				}
392 
393 				if (!pSRS->ReadLine(aByteText))
394 					break;
395 			}
396 			while (aByteText.Search( "IdList" ) == STRING_NOTFOUND );
397 			aText = String::CreateFromAscii( aByteText.GetBuffer() );
398 
399 			// if image list is not language dependent, don't do anything for languages except german
400 			if( aText.Len() )
401 			{
402 				bDone = sal_True;
403 				ImplCreate( aInDirs, aOutDir, aName, rLang );
404 			}
405 /*			else if( ( rLang.mnLangNum != 49 ) && !bLangDep )
406 			{
407 				Message( String( RTL_CONSTASCII_USTRINGPARAM( "INFO: ImageList is not language dependent! Nothing to do for this language." ) ) );
408 				bDone = sal_True;
409 			}*/
410 		}
411 		while ( aText.Len() );
412 	}
413 
414 	if( !bDone )
415 		Message( String( RTL_CONSTASCII_USTRINGPARAM( "ERROR: No ImageList found in SRS file!" ) ), EXIT_NOIMGLIST );
416 
417     delete pSRS;
418 }
419