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