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