summaryrefslogtreecommitdiffstats
path: root/vcl/source/filter/ipbm/ipbm.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vcl/source/filter/ipbm/ipbm.cxx541
1 files changed, 541 insertions, 0 deletions
diff --git a/vcl/source/filter/ipbm/ipbm.cxx b/vcl/source/filter/ipbm/ipbm.cxx
new file mode 100644
index 000000000..37736a48f
--- /dev/null
+++ b/vcl/source/filter/ipbm/ipbm.cxx
@@ -0,0 +1,541 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <sal/config.h>
+#include <o3tl/safeint.hxx>
+#include <vcl/FilterConfigItem.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <tools/stream.hxx>
+#include <filter/PbmReader.hxx>
+
+//============================ PBMReader ==================================
+
+namespace {
+
+class PBMReader {
+
+private:
+
+ SvStream& mrPBM; // the PBM file to read
+
+ bool mbStatus;
+ bool mbRemark; // sal_False if the stream is in a comment
+ bool mbRaw; // RAW/ASCII MODE
+ sal_uInt8 mnMode; // 0->PBM, 1->PGM, 2->PPM
+ std::unique_ptr<vcl::bitmap::RawBitmap> mpRawBmp;
+ std::vector<Color> mvPalette;
+ sal_Int32 mnWidth, mnHeight; // dimensions in pixel
+ sal_uInt16 mnCol;
+ sal_uInt64 mnMaxVal; // max value in the <missing comment>
+ bool ImplReadBody();
+ bool ImplReadHeader();
+
+public:
+ explicit PBMReader(SvStream & rPBM);
+ bool ReadPBM(Graphic & rGraphic );
+};
+
+}
+
+//=================== Methods of PBMReader ==============================
+
+PBMReader::PBMReader(SvStream & rPBM)
+ : mrPBM(rPBM)
+ , mbStatus(true)
+ , mbRemark(false)
+ , mbRaw(true)
+ , mnMode(0)
+ , mnWidth(0)
+ , mnHeight(0)
+ , mnCol(0)
+ , mnMaxVal(0)
+{
+}
+
+bool PBMReader::ReadPBM(Graphic & rGraphic )
+{
+ if ( mrPBM.GetError() )
+ return false;
+
+ mrPBM.SetEndian( SvStreamEndian::LITTLE );
+
+ // read header:
+
+ mbStatus = ImplReadHeader();
+ if ( !mbStatus )
+ return false;
+
+ if ( ( mnMaxVal == 0 ) || ( mnWidth <= 0 ) || ( mnHeight <= 0 ) )
+ return false;
+
+ sal_uInt32 nPixelsRequired;
+ if (o3tl::checked_multiply<sal_uInt32>(mnWidth, mnHeight, nPixelsRequired))
+ return false;
+ const auto nRemainingSize = mrPBM.remainingSize();
+
+ // 0->PBM, 1->PGM, 2->PPM
+ switch ( mnMode )
+ {
+ case 0:
+ {
+ if (nRemainingSize < nPixelsRequired / 8)
+ return false;
+
+ mpRawBmp.reset( new vcl::bitmap::RawBitmap( Size( mnWidth, mnHeight ), 24 ) );
+ mvPalette.resize( 2 );
+ mvPalette[0] = Color( 0xff, 0xff, 0xff );
+ mvPalette[1] = Color( 0x00, 0x00, 0x00 );
+ break;
+ }
+ case 1 :
+ if (nRemainingSize < nPixelsRequired)
+ return false;
+
+ mpRawBmp.reset( new vcl::bitmap::RawBitmap( Size( mnWidth, mnHeight ), 24 ) );
+ mnCol = static_cast<sal_uInt16>(mnMaxVal) + 1;
+ if ( mnCol > 256 )
+ mnCol = 256;
+
+ mvPalette.resize( 256 );
+ for ( sal_uInt16 i = 0; i < mnCol; i++ )
+ {
+ sal_uInt16 nCount = 255 * i / mnCol;
+ mvPalette[i] = Color( static_cast<sal_uInt8>(nCount), static_cast<sal_uInt8>(nCount), static_cast<sal_uInt8>(nCount) );
+ }
+ break;
+ case 2 :
+ if (nRemainingSize / 3 < nPixelsRequired)
+ return false;
+
+ mpRawBmp.reset( new vcl::bitmap::RawBitmap( Size( mnWidth, mnHeight ), 24 ) );
+ break;
+ }
+
+ // read bitmap data
+ mbStatus = ImplReadBody();
+
+ if ( mbStatus )
+ rGraphic = vcl::bitmap::CreateFromData(std::move(*mpRawBmp));
+
+ return mbStatus;
+}
+
+bool PBMReader::ImplReadHeader()
+{
+ sal_uInt8 nID[ 2 ];
+ sal_uInt8 nDat;
+ sal_uInt8 nMax, nCount = 0;
+ bool bFinished = false;
+
+ mrPBM.ReadUChar( nID[ 0 ] ).ReadUChar( nID[ 1 ] );
+ if (!mrPBM.good() || nID[0] != 'P')
+ return false;
+ mnMaxVal = mnWidth = mnHeight = 0;
+ switch ( nID[ 1 ] )
+ {
+ case '1' :
+ mbRaw = false;
+ [[fallthrough]];
+ case '4' :
+ mnMode = 0;
+ nMax = 2; // number of parameters in Header
+ mnMaxVal = 1;
+ break;
+ case '2' :
+ mbRaw = false;
+ [[fallthrough]];
+ case '5' :
+ mnMode = 1;
+ nMax = 3;
+ break;
+ case '3' :
+ mbRaw = false;
+ [[fallthrough]];
+ case '6' :
+ mnMode = 2;
+ nMax = 3;
+ break;
+ default:
+ return false;
+ }
+ while ( !bFinished )
+ {
+ mrPBM.ReadUChar( nDat );
+
+ if (!mrPBM.good())
+ return false;
+
+ if ( nDat == '#' )
+ {
+ mbRemark = true;
+ continue;
+ }
+ else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
+ {
+ mbRemark = false;
+ nDat = 0x20;
+ }
+ if ( mbRemark )
+ continue;
+
+ if ( ( nDat == 0x20 ) || ( nDat == 0x09 ) )
+ {
+ if ( ( nCount == 0 ) && mnWidth )
+ nCount++;
+ else if ( ( nCount == 1 ) && mnHeight )
+ {
+ if ( ++nCount == nMax )
+ bFinished = true;
+ }
+ else if ( ( nCount == 2 ) && mnMaxVal )
+ {
+ bFinished = true;
+ }
+ continue;
+ }
+ if ( ( nDat >= '0' ) && ( nDat <= '9' ) )
+ {
+ nDat -= '0';
+ if ( nCount == 0 )
+ {
+ if (mnWidth > SAL_MAX_INT32 / 10)
+ {
+ return false;
+ }
+ mnWidth *= 10;
+ if (nDat > SAL_MAX_INT32 - mnWidth)
+ {
+ return false;
+ }
+ mnWidth += nDat;
+ }
+ else if ( nCount == 1 )
+ {
+ if (mnHeight > SAL_MAX_INT32 / 10)
+ {
+ return false;
+ }
+ mnHeight *= 10;
+ if (nDat > SAL_MAX_INT32 - mnHeight)
+ {
+ return false;
+ }
+ mnHeight += nDat;
+ }
+ else if ( nCount == 2 )
+ {
+ if (mnMaxVal > std::numeric_limits<sal_uInt64>::max() / 10)
+ {
+ return false;
+ }
+ mnMaxVal *= 10;
+ if (nDat > std::numeric_limits<sal_uInt64>::max() - mnMaxVal)
+ {
+ return false;
+ }
+ mnMaxVal += nDat;
+ }
+ }
+ else
+ return false;
+ }
+ return mbStatus;
+}
+
+bool PBMReader::ImplReadBody()
+{
+ sal_uInt8 nDat = 0, nCount;
+ sal_uInt64 nGrey, nRGB[3];
+ sal_Int32 nWidth = 0;
+ sal_Int32 nHeight = 0;
+
+ if ( mbRaw )
+ {
+ signed char nShift = 0;
+ switch ( mnMode )
+ {
+
+ // PBM
+ case 0 :
+ while ( nHeight != mnHeight )
+ {
+ if (!mrPBM.good())
+ return false;
+
+ if ( --nShift < 0 )
+ {
+ mrPBM.ReadUChar( nDat );
+ nShift = 7;
+ }
+ mpRawBmp->SetPixel( nHeight, nWidth, mvPalette[(nDat >> nShift) & 0x01] );
+ if ( ++nWidth == mnWidth )
+ {
+ nShift = 0;
+ nWidth = 0;
+ nHeight++;
+ }
+ }
+ break;
+
+ // PGM
+ case 1 :
+ while ( nHeight != mnHeight )
+ {
+ if (!mrPBM.good())
+ return false;
+
+ mrPBM.ReadUChar( nDat );
+ mpRawBmp->SetPixel( nHeight, nWidth++, mvPalette[nDat]);
+
+ if ( nWidth == mnWidth )
+ {
+ nWidth = 0;
+ nHeight++;
+ }
+ }
+ break;
+
+ // PPM
+ case 2 :
+ while ( nHeight != mnHeight )
+ {
+ if (!mrPBM.good())
+ return false;
+
+ sal_uInt8 nR, nG, nB;
+ sal_uInt8 nRed, nGreen, nBlue;
+ mrPBM.ReadUChar( nR ).ReadUChar( nG ).ReadUChar( nB );
+ nRed = 255 * nR / mnMaxVal;
+ nGreen = 255 * nG / mnMaxVal;
+ nBlue = 255 * nB / mnMaxVal;
+ mpRawBmp->SetPixel( nHeight, nWidth++, Color( nRed, nGreen, nBlue ) );
+ if ( nWidth == mnWidth )
+ {
+ nWidth = 0;
+ nHeight++;
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ bool bPara = false;
+ bool bFinished = false;
+
+ switch ( mnMode )
+ {
+ // PBM
+ case 0 :
+ while ( !bFinished )
+ {
+ if (!mrPBM.good())
+ return false;
+
+ mrPBM.ReadUChar( nDat );
+
+ if ( nDat == '#' )
+ {
+ mbRemark = true;
+ continue;
+ }
+ else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
+ {
+ mbRemark = false;
+ continue;
+ }
+ if ( mbRemark || nDat == 0x20 || nDat == 0x09 )
+ continue;
+
+ if ( nDat == '0' || nDat == '1' )
+ {
+ mpRawBmp->SetPixel( nHeight, nWidth, mvPalette[static_cast<sal_uInt8>(nDat - '0')] );
+ nWidth++;
+ if ( nWidth == mnWidth )
+ {
+ nWidth = 0;
+ if ( ++nHeight == mnHeight )
+ bFinished = true;
+ }
+ }
+ else
+ return false;
+ }
+ break;
+
+ // PGM
+ case 1 :
+
+ bPara = false;
+ nCount = 0;
+ nGrey = 0;
+
+ while ( !bFinished )
+ {
+ if ( nCount )
+ {
+ nCount--;
+ if ( nGrey <= mnMaxVal )
+ nGrey = 255 * nGrey / mnMaxVal;
+ mpRawBmp->SetPixel( nHeight, nWidth++, mvPalette[static_cast<sal_uInt8>(nGrey)] );
+ nGrey = 0;
+ if ( nWidth == mnWidth )
+ {
+ nWidth = 0;
+ if ( ++nHeight == mnHeight )
+ bFinished = true;
+ }
+ continue;
+ }
+
+ if (!mrPBM.good())
+ return false;
+
+ mrPBM.ReadUChar( nDat );
+
+ if ( nDat == '#' )
+ {
+ mbRemark = true;
+ if ( bPara )
+ {
+ bPara = false;
+ nCount++;
+ }
+ continue;
+ }
+ else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
+ {
+ mbRemark = false;
+ if ( bPara )
+ {
+ bPara = false;
+ nCount++;
+ }
+ continue;
+ }
+
+ if ( nDat == 0x20 || nDat == 0x09 )
+ {
+ if ( bPara )
+ {
+ bPara = false;
+ nCount++;
+ }
+ continue;
+ }
+ if ( nDat >= '0' && nDat <= '9' )
+ {
+ bPara = true;
+ nGrey *= 10;
+ nGrey += nDat-'0';
+ continue;
+ }
+ else
+ return false;
+ }
+ break;
+
+
+ // PPM
+ case 2 :
+
+ bPara = false;
+ nCount = 0;
+ nRGB[ 0 ] = nRGB[ 1 ] = nRGB[ 2 ] = 0;
+
+ while ( !bFinished )
+ {
+ if ( nCount == 3 )
+ {
+ nCount = 0;
+ mpRawBmp->SetPixel( nHeight, nWidth++, Color( static_cast< sal_uInt8 >( ( nRGB[ 0 ] * 255 ) / mnMaxVal ),
+ static_cast< sal_uInt8 >( ( nRGB[ 1 ] * 255 ) / mnMaxVal ),
+ static_cast< sal_uInt8 >( ( nRGB[ 2 ] * 255 ) / mnMaxVal ) ) );
+ nRGB[ 0 ] = nRGB[ 1 ] = nRGB[ 2 ] = 0;
+ if ( nWidth == mnWidth )
+ {
+ nWidth = 0;
+ if ( ++nHeight == mnHeight )
+ bFinished = true;
+ }
+ continue;
+ }
+
+ if (!mrPBM.good())
+ return false;
+
+ mrPBM.ReadUChar( nDat );
+
+ if ( nDat == '#' )
+ {
+ mbRemark = true;
+ if ( bPara )
+ {
+ bPara = false;
+ nCount++;
+ }
+ continue;
+ }
+ else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
+ {
+ mbRemark = false;
+ if ( bPara )
+ {
+ bPara = false;
+ nCount++;
+ }
+ continue;
+ }
+
+ if ( nDat == 0x20 || nDat == 0x09 )
+ {
+ if ( bPara )
+ {
+ bPara = false;
+ nCount++;
+ }
+ continue;
+ }
+ if ( nDat >= '0' && nDat <= '9' )
+ {
+ bPara = true;
+ nRGB[ nCount ] *= 10;
+ nRGB[ nCount ] += nDat-'0';
+ continue;
+ }
+ else
+ return false;
+ }
+ break;
+ }
+ }
+ return mbStatus;
+}
+
+//================== GraphicImport - the exported function ================
+
+bool ImportPbmGraphic( SvStream & rStream, Graphic & rGraphic)
+{
+ PBMReader aPBMReader(rStream);
+
+ return aPBMReader.ReadPBM(rGraphic );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */