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