[Libreoffice-commits] core.git: 14 commits - svx/inc svx/sdi sw/sdi sw/source vcl/inc vcl/Library_vcl.mk vcl/Package_inc.mk vcl/source

Tomaž Vajngerl quikee at gmail.com
Sun Apr 21 12:58:45 PDT 2013


 svx/inc/svx/svxids.hrc                       |    7 
 svx/sdi/svx.sdi                              |   47 
 sw/sdi/_grfsh.sdi                            |   12 
 sw/source/ui/app/app.src                     |    5 
 sw/source/ui/app/mn.src                      |   26 
 sw/source/ui/inc/app.hrc                     |    4 
 sw/source/ui/inc/grfsh.hxx                   |   10 
 sw/source/ui/shells/grfsh.cxx                |   85 +
 sw/source/ui/uiview/view2.cxx                |   65 -
 vcl/Library_vcl.mk                           |    7 
 vcl/Package_inc.mk                           |    2 
 vcl/inc/vcl/GraphicNativeMetadata.hxx        |   39 
 vcl/inc/vcl/GraphicNativeTransform.hxx       |   42 
 vcl/source/filter/GraphicNativeMetadata.cxx  |   58 
 vcl/source/filter/GraphicNativeTransform.cxx |  169 ++
 vcl/source/filter/jpeg/Exif.cxx              |  236 +++
 vcl/source/filter/jpeg/Exif.hxx              |   93 +
 vcl/source/filter/jpeg/JpegReader.cxx        |  473 +++++++
 vcl/source/filter/jpeg/JpegReader.hxx        |   62 +
 vcl/source/filter/jpeg/JpegTransform.cxx     |   49 
 vcl/source/filter/jpeg/JpegTransform.hxx     |   43 
 vcl/source/filter/jpeg/JpegWriter.cxx        |  274 ++++
 vcl/source/filter/jpeg/JpegWriter.hxx        |   58 
 vcl/source/filter/jpeg/jinclude.h            |   91 +
 vcl/source/filter/jpeg/jpeg.cxx              |  711 -----------
 vcl/source/filter/jpeg/jpeg.h                |   10 
 vcl/source/filter/jpeg/jpeg.hxx              |   72 -
 vcl/source/filter/jpeg/jpegc.c               |  212 ++-
 vcl/source/filter/jpeg/jpegcomp.h            |   30 
 vcl/source/filter/jpeg/transupp.c            | 1630 +++++++++++++++++++++++++++
 vcl/source/filter/jpeg/transupp.h            |  220 +++
 31 files changed, 3981 insertions(+), 861 deletions(-)

New commits:
commit 98ffb94d807625f87bfd27f84958ef10d3a105dc
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 21:53:11 2013 +0200

    Extract QueryBox rotation string and InsertGraphic cleanup.
    
    Change-Id: I46bb4b2436407cc2cb084f502ff8fb5ff7754400

diff --git a/sw/source/ui/app/app.src b/sw/source/ui/app/app.src
index 7212515..8dbc309 100644
--- a/sw/source/ui/app/app.src
+++ b/sw/source/ui/app/app.src
@@ -789,4 +789,9 @@ WarningBox MSG_DISABLE_READLINE_QUESTION
     Message [ en-US ] = "In the current document, changes are being recorded but not shown as such. In large documents, delays can occur when the document is edited. Do you want to show the changes to avoid delays?";
 };
 
+String STR_ROTATE_TO_STANDARD_ORIENTATION
+{
+    Text [ en-US ] = "This image is rotated. Would you like to rotate it into standard orientation?";
+};
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/inc/app.hrc b/sw/source/ui/inc/app.hrc
index de9dba0..d9295e5 100644
--- a/sw/source/ui/inc/app.hrc
+++ b/sw/source/ui/inc/app.hrc
@@ -118,7 +118,9 @@
 #define STR_AUTHMRK_EDIT                (RC_APP_BEGIN + 130)
 #define STR_AUTHMRK_INSERT              (RC_APP_BEGIN + 131)
 
-#define APP_ACT_END                     STR_AUTHMRK_INSERT
+#define STR_ROTATE_TO_STANDARD_ORIENTATION  (RC_APP_BEGIN + 132)
+
+#define APP_ACT_END                     STR_ROTATE_TO_STANDARD_ORIENTATION
 
 #if APP_ACT_END > RC_APP_END
 #error Resource-Id Ueberlauf in #file, #line
diff --git a/sw/source/ui/uiview/view2.cxx b/sw/source/ui/uiview/view2.cxx
index b48e403..26876d6 100644
--- a/sw/source/ui/uiview/view2.cxx
+++ b/sw/source/ui/uiview/view2.cxx
@@ -199,44 +199,45 @@ String SwView::GetPageStr( sal_uInt16 nPg, sal_uInt16 nLogPg,
 }
 
 int SwView::InsertGraphic( const String &rPath, const String &rFilter,
-                                sal_Bool bLink, GraphicFilter *pFlt,
+                                sal_Bool bLink, GraphicFilter *pFilter,
                                 Graphic* pPreviewGrf, sal_Bool bRule )
 {
-    SwWait aWait( *GetDocShell(), sal_True );
+    SwWait aWait( *GetDocShell(), true );
 
-    Graphic aGrf;
-    int nRes = GRFILTER_OK;
+    Graphic aGraphic;
+    int aResult = GRFILTER_OK;
     if ( pPreviewGrf )
-        aGrf = *pPreviewGrf;
+        aGraphic = *pPreviewGrf;
     else
     {
-        if( !pFlt )
-            pFlt = &GraphicFilter::GetGraphicFilter();
-        nRes = GraphicFilter::LoadGraphic( rPath, rFilter, aGrf, pFlt );
+        if( !pFilter )
+        {
+            pFilter = &GraphicFilter::GetGraphicFilter();
+        }
+        aResult = GraphicFilter::LoadGraphic( rPath, rFilter, aGraphic, pFilter );
     }
 
-    if( GRFILTER_OK == nRes )
+    if( GRFILTER_OK == aResult )
     {
         GraphicNativeMetadata aMetadata;
-        if (aMetadata.read(aGrf))
+        if ( aMetadata.read(aGraphic) )
         {
             sal_uInt16 aRotation = aMetadata.getRotation();
             if (aRotation != 0)
             {
-                OUString aMessage("This image is rotated. Would you like LibreOffice to rotate it into standard orientation?");
-                QueryBox aQueryBox(GetWindow(), WB_YES_NO | WB_DEF_YES, aMessage);
+                QueryBox aQueryBox(GetWindow(), WB_YES_NO | WB_DEF_YES, SW_RES(STR_ROTATE_TO_STANDARD_ORIENTATION) );
                 if (aQueryBox.Execute() == RET_YES)
                 {
-                    GraphicNativeTransform aTransform(aGrf);
+                    GraphicNativeTransform aTransform( aGraphic );
                     aTransform.rotate( aRotation );
                 }
             }
         }
 
-        SwFlyFrmAttrMgr aFrmMgr( sal_True, GetWrtShellPtr(), FRMMGR_TYPE_GRF );
+        SwFlyFrmAttrMgr aFrameManager( sal_True, GetWrtShellPtr(), FRMMGR_TYPE_GRF );
 
-        SwWrtShell &rSh = GetWrtShell();
-        rSh.StartAction();
+        SwWrtShell& rShell = GetWrtShell();
+        rShell.StartAction();
         if( bLink )
         {
             SwDocShell* pDocSh = GetDocShell();
@@ -245,18 +246,19 @@ int SwView::InsertGraphic( const String &rPath, const String &rFilter,
                     pDocSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) :
                     OUString());
 
-            String sURL = URIHelper::SmartRel2Abs(
-                aTemp, rPath, URIHelper::GetMaybeFileHdl() );
+            String sURL = URIHelper::SmartRel2Abs( aTemp, rPath, URIHelper::GetMaybeFileHdl() );
 
-            rSh.Insert( sURL,
-                        rFilter, aGrf, &aFrmMgr, bRule );
+            rShell.Insert( sURL, rFilter, aGraphic, &aFrameManager, bRule );
         }
         else
-            rSh.Insert( aEmptyStr, aEmptyStr, aGrf, &aFrmMgr );
-        // nach dem EndAction ist es zu spaet, weil die Shell dann schon zerstoert sein kann
-        rSh.EndAction();
+        {
+            rShell.Insert( aEmptyStr, aEmptyStr, aGraphic, &aFrameManager );
+        }
+
+        // it is too late after "EndAction" because the Shell can already be destroyed.
+        rShell.EndAction();
     }
-    return nRes;
+    return aResult;
 }
 
 sal_Bool SwView::InsertGraphicDlg( SfxRequest& rReq )
commit 922d87535b3413764928b70db159600c4ff2a8c2
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:10:10 2013 +0200

    Extract IFD processing in Exif.
    
    Change-Id: Ia00803c748cd40b7e2e6142a2802ea6e4e13f8fd

diff --git a/vcl/source/filter/jpeg/Exif.cxx b/vcl/source/filter/jpeg/Exif.cxx
index be054dc..318e2bd 100644
--- a/vcl/source/filter/jpeg/Exif.cxx
+++ b/vcl/source/filter/jpeg/Exif.cxx
@@ -155,6 +155,35 @@ bool Exif::processJpeg(SvStream& rStream, bool bSetValue)
     return false;
 }
 
+bool Exif::processIFD(sal_uInt8* pExifData, sal_uInt16 aLength, sal_uInt16 aOffset, sal_uInt16 aNumberOfTags, bool bSetValue)
+{
+    ExifIFD* ifd = NULL;
+
+    while (aOffset <= aLength - 12 && aNumberOfTags > 0)
+    {
+        ifd = (ExifIFD*) &pExifData[aOffset];
+
+        if (ifd->tag == Tag::ORIENTATION)
+        {
+            if(bSetValue)
+            {
+                ifd->tag = Tag::ORIENTATION;
+                ifd->type = 3;
+                ifd->count = 1;
+                ifd->offset = maOrientation;
+            }
+            else
+            {
+                maOrientation = convertToOrientation(ifd->offset);
+            }
+        }
+
+        aNumberOfTags--;
+        aOffset += 12;
+    }
+    return true;
+}
+
 bool Exif::processExif(SvStream& rStream, sal_uInt16 aSectionLength, bool bSetValue)
 {
     sal_uInt32  aMagic32;
@@ -193,31 +222,7 @@ bool Exif::processExif(SvStream& rStream, sal_uInt16 aSectionLength, bool bSetVa
     aNumberOfTags <<= 8;
     aNumberOfTags += aExifData[aOffset];
 
-    aOffset += 2;
-
-    ExifIFD* ifd = NULL;
-
-    while (aOffset <= aLength - 12 && aNumberOfTags > 0) {
-        ifd = (ExifIFD*) &aExifData[aOffset];
-
-        if (ifd->tag == Tag::ORIENTATION)
-        {
-            if(bSetValue)
-            {
-                ifd->tag = Tag::ORIENTATION;
-                ifd->type = 3;
-                ifd->count = 1;
-                ifd->offset = maOrientation;
-            }
-            else
-            {
-                maOrientation = convertToOrientation(ifd->offset);
-            }
-        }
-
-        aNumberOfTags--;
-        aOffset += 12;
-    }
+    processIFD(aExifData, aLength, aOffset+2, aNumberOfTags, bSetValue);
 
     if (bSetValue)
     {
diff --git a/vcl/source/filter/jpeg/Exif.hxx b/vcl/source/filter/jpeg/Exif.hxx
index eea8ada..def8ee3 100644
--- a/vcl/source/filter/jpeg/Exif.hxx
+++ b/vcl/source/filter/jpeg/Exif.hxx
@@ -54,6 +54,7 @@ private:
 
     bool processJpeg(SvStream& rStream, bool bSetValue);
     bool processExif(SvStream& rStream, sal_uInt16 aLength, bool bSetValue);
+    bool processIFD(sal_uInt8* pExifData, sal_uInt16 aLength, sal_uInt16 aOffset, sal_uInt16 aNumberOfTags, bool bSetValue);
 
     struct ExifIFD {
         sal_uInt16 tag;
commit c0bb58329e16c9346039a12882b9c3be412e9f0b
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:09:24 2013 +0200

    At native rotation of JPEG image detect and reset image orientation.
    
    Change-Id: I81bc0f4a7cb192f8f9806a9b5bb0d2a6ab1b00df

diff --git a/vcl/source/filter/GraphicNativeTransform.cxx b/vcl/source/filter/GraphicNativeTransform.cxx
index 11f3840..793621b 100644
--- a/vcl/source/filter/GraphicNativeTransform.cxx
+++ b/vcl/source/filter/GraphicNativeTransform.cxx
@@ -124,11 +124,17 @@ bool GraphicNativeTransform::rotateJPEG(sal_uInt16 aRotation)
 {
     GfxLink aLink = mrGraphic.GetLink();
 
-    sal_uInt32 aDataSize = aLink.GetDataSize();
-    sal_uInt8* aInputBuffer = new sal_uInt8[aDataSize];
+    SvMemoryStream aSourceStream;
+    aSourceStream.Write(aLink.GetData(), aLink.GetDataSize());
+    aSourceStream.Seek( STREAM_SEEK_TO_BEGIN );
 
-    memcpy(aInputBuffer, aLink.GetData(), aDataSize);
-    SvMemoryStream aSourceStream(aInputBuffer, aDataSize, STREAM_READ);
+    Orientation aOrientation = Orientation::TOP_LEFT;
+
+    Exif exif;
+    if ( exif.read(aSourceStream) )
+    {
+        aOrientation = exif.getOrientation();
+    }
 
     SvMemoryStream aTargetStream;
     JpegTransform tranform(aSourceStream, aTargetStream);
@@ -137,9 +143,12 @@ bool GraphicNativeTransform::rotateJPEG(sal_uInt16 aRotation)
 
     aTargetStream.Seek( STREAM_SEEK_TO_BEGIN );
 
-    Exif exif;
-    exif.setOrientation(Orientation::TOP_LEFT);
-    exif.write(aTargetStream);
+    // Reset orientation in exif if needed
+    if ( exif.hasExif() && aOrientation != Orientation::TOP_LEFT)
+    {
+        exif.setOrientation(Orientation::TOP_LEFT);
+        exif.write(aTargetStream);
+    }
 
     aTargetStream.Seek( STREAM_SEEK_TO_END );
     sal_uInt32 aBufferSize = aTargetStream.Tell();
@@ -152,6 +161,7 @@ bool GraphicNativeTransform::rotateJPEG(sal_uInt16 aRotation)
     aBitmap.Rotate(aRotation, COL_BLACK);
     mrGraphic = aBitmap;
     mrGraphic.SetLink( GfxLink( pBuffer, aBufferSize, aLink.GetType(), sal_True ) );
+
     return true;
 }
 
commit 4f3bc8cf69bedb831d81d716274427191319fef0
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:08:42 2013 +0200

    More correct reading of Exif metadata.
    
    Change-Id: Id9e7754cfcbd1d7e8b512eb1c1a3384df2db149f

diff --git a/vcl/source/filter/jpeg/Exif.cxx b/vcl/source/filter/jpeg/Exif.cxx
index f0b1970..be054dc 100644
--- a/vcl/source/filter/jpeg/Exif.cxx
+++ b/vcl/source/filter/jpeg/Exif.cxx
@@ -20,7 +20,8 @@
 #include "Exif.hxx"
 
 Exif::Exif() :
-    maOrientation(TOP_LEFT)
+    maOrientation(TOP_LEFT),
+    mbExifPresent(false)
 {}
 
 Exif::~Exif()
@@ -66,10 +67,15 @@ sal_Int32 Exif::getRotation()
     return 0;
 }
 
+bool Exif::hasExif()
+{
+    return mbExifPresent;
+}
+
 bool Exif::read(SvStream& rStream)
 {
     sal_Int32 nStreamPosition = rStream.Tell();
-    bool result = processJpegStream(rStream, false);
+    bool result = processJpeg(rStream, false);
     rStream.Seek( nStreamPosition );
 
     return result;
@@ -78,33 +84,81 @@ bool Exif::read(SvStream& rStream)
 bool Exif::write(SvStream& rStream)
 {
     sal_Int32 nStreamPosition = rStream.Tell();
-    bool result = processJpegStream(rStream, true);
+    bool result = processJpeg(rStream, true);
     rStream.Seek( nStreamPosition );
 
     return result;
 }
 
-bool Exif::processJpegStream(SvStream& rStream, bool bSetValue)
+bool Exif::processJpeg(SvStream& rStream, bool bSetValue)
 {
-    sal_uInt32  aMagic32;
     sal_uInt16  aMagic16;
+    sal_uInt8   aMarker;
     sal_uInt16  aLength;
 
+    rStream.Seek(STREAM_SEEK_TO_END);
+    sal_uInt32 aSize = rStream.Tell();
+    rStream.Seek(STREAM_SEEK_TO_BEGIN);
+
     rStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
-    rStream >> aMagic32;
+    rStream >> aMagic16;
 
     // Compare JPEG magic bytes
-    if( 0xffd8ff00 != ( aMagic32 & 0xffffff00 ) )
+    if( 0xFFD8 != aMagic16 )
     {
         return false;
     }
 
-    rStream >> aLength;
-    if (aLength < 8)
+    sal_uInt32 aPreviousPosition = STREAM_SEEK_TO_BEGIN;
+
+    while(true)
     {
-        return false;
+        sal_Int32 aCount;
+        for (aCount = 0; aCount < 7; aCount++)
+        {
+            rStream >> aMarker;
+            if (aMarker != 0xFF)
+            {
+                break;
+            }
+            if (aCount >= 6)
+            {
+                return false;
+            }
+        }
+
+        rStream >> aLength;
+
+        if (aLength < 8)
+        {
+            return false;
+        }
+
+        if (aMarker == 0xE1)
+        {
+            return processExif(rStream, aLength, bSetValue);
+        }
+        else if (aMarker == 0xD9)
+        {
+            return false;
+        }
+        else
+        {
+            sal_uInt32 aCurrentPosition = rStream.SeekRel(aLength-1);
+            if (aCurrentPosition == aPreviousPosition || aCurrentPosition > aSize)
+            {
+                return false;
+            }
+            aPreviousPosition = aCurrentPosition;
+        }
     }
-    aLength -= 8;
+    return false;
+}
+
+bool Exif::processExif(SvStream& rStream, sal_uInt16 aSectionLength, bool bSetValue)
+{
+    sal_uInt32  aMagic32;
+    sal_uInt16  aMagic16;
 
     rStream >> aMagic32;
     rStream >> aMagic16;
@@ -115,26 +169,36 @@ bool Exif::processJpegStream(SvStream& rStream, bool bSetValue)
         return false;
     }
 
-    sal_uInt8* exifData = new sal_uInt8[aLength];
+    sal_uInt16 aLength = aSectionLength - 6; // Length = Section - Header
+
+    sal_uInt8* aExifData = new sal_uInt8[aLength];
     sal_uInt32 aExifDataBeginPosition = rStream.Tell();
-    rStream.Read(exifData, aLength);
 
-    sal_uInt16 offset;
-    offset = exifData[5];
-    offset <<= 8;
-    offset += exifData[4];
+    rStream.Read(aExifData, aLength);
+
+    // Exif detected
+    mbExifPresent = true;
+
+    TiffHeader* aTiffHeader = (TiffHeader*) &aExifData[0];
+
+    if( 0x4949 != aTiffHeader->byteOrder || 0x002A != aTiffHeader->tagAlign )
+    {
+        return false;
+    }
+
+    sal_uInt16 aOffset = aTiffHeader->offset;
 
-    sal_uInt16 numberOfTags;
-    numberOfTags = exifData[offset+1];
-    numberOfTags <<= 8;
-    numberOfTags += exifData[offset];
+    sal_uInt16 aNumberOfTags = aExifData[aOffset];
+    aNumberOfTags = aExifData[aOffset + 1];
+    aNumberOfTags <<= 8;
+    aNumberOfTags += aExifData[aOffset];
 
-    offset += 2;
+    aOffset += 2;
 
     ExifIFD* ifd = NULL;
 
-    while (offset <= aLength - 12 && numberOfTags > 0) {
-        ifd = (ExifIFD*) &exifData[offset];
+    while (aOffset <= aLength - 12 && aNumberOfTags > 0) {
+        ifd = (ExifIFD*) &aExifData[aOffset];
 
         if (ifd->tag == Tag::ORIENTATION)
         {
@@ -151,14 +215,14 @@ bool Exif::processJpegStream(SvStream& rStream, bool bSetValue)
             }
         }
 
-        numberOfTags--;
-        offset += 12;
+        aNumberOfTags--;
+        aOffset += 12;
     }
 
     if (bSetValue)
     {
         rStream.Seek(aExifDataBeginPosition);
-        rStream.Write(exifData, aLength);
+        rStream.Write(aExifData, aLength);
     }
 
     return true;
diff --git a/vcl/source/filter/jpeg/Exif.hxx b/vcl/source/filter/jpeg/Exif.hxx
index cce6a63..eea8ada 100644
--- a/vcl/source/filter/jpeg/Exif.hxx
+++ b/vcl/source/filter/jpeg/Exif.hxx
@@ -38,11 +38,11 @@ enum Orientation {
 };
 
 enum Tag {
-    IMAGE_WIDTH     = 0x0100,
-    IMAGE_HEIGHT    = 0x0101,
-    BITS_PER_SAMPLE = 0x0102,
-    COMPRESSION     = 0x0103,
-    ORIENTATION     = 0x0112
+    ORIENTATION         = 0x0112,
+    X_RESOLUTION        = 0x011a,
+    Y_RESOLUTION        = 0x011b,
+    EXIF_OFFSET         = 0x8769,
+    INTEROP_OFFSET      = 0xa005
 };
 
 class Exif
@@ -50,8 +50,10 @@ class Exif
 private:
     Orientation maOrientation;
     sal_Int32  mnStreamPosition;
+    bool mbExifPresent;
 
-    bool processJpegStream(SvStream& rStream, bool bSetValue);
+    bool processJpeg(SvStream& rStream, bool bSetValue);
+    bool processExif(SvStream& rStream, sal_uInt16 aLength, bool bSetValue);
 
     struct ExifIFD {
         sal_uInt16 tag;
@@ -60,12 +62,20 @@ private:
         sal_uInt32 offset;
     };
 
+    struct TiffHeader {
+        sal_uInt16 byteOrder;
+        sal_uInt16 tagAlign;
+        sal_uInt32 offset;
+    };
+
     Orientation convertToOrientation(sal_Int32 value);
 
 public :
     Exif();
     virtual ~Exif();
 
+    bool hasExif();
+
     Orientation getOrientation();
     sal_Int32 getRotation();
 
commit df155415d8f46d884ba18e370e8028d020ba6f3b
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:07:20 2013 +0200

    Menu "Manage Graphic" and Rotate 90 degree menu items added to Writer.
    
    Change-Id: Ic5ced4a743c6d5465462a7d88e63150741d1f920

diff --git a/svx/inc/svx/svxids.hrc b/svx/inc/svx/svxids.hrc
index da669b8..5454042 100644
--- a/svx/inc/svx/svxids.hrc
+++ b/svx/inc/svx/svxids.hrc
@@ -931,10 +931,10 @@
 #define SID_CHANGE_PICTURE                              (SID_SVX_START+1125)
 #define SID_ROTATE_GRAPHIC_LEFT                         (SID_SVX_START+1126)
 #define SID_ROTATE_GRAPHIC_RIGHT                        (SID_SVX_START+1127)
-
+#define SID_MENU_MANAGE_GRAPHIC                         (SID_SVX_START+1128)
 
 // IMPORTANT NOTE: adjust SID_SVX_FIRSTFREE, when adding new slot id
-#define SID_SVX_FIRSTFREE                               (SID_ROTATE_GRAPHIC_RIGHT + 1)
+#define SID_SVX_FIRSTFREE                               (SID_MENU_MANAGE_GRAPHIC + 1)
 
 // --------------------------------------------------------------------------
 // Overflow check for slot IDs
diff --git a/sw/sdi/_grfsh.sdi b/sw/sdi/_grfsh.sdi
index f91eba9..491d01a 100644
--- a/sw/sdi/_grfsh.sdi
+++ b/sw/sdi/_grfsh.sdi
@@ -62,13 +62,13 @@ interface BaseTextGraphic
 
     SID_ROTATE_GRAPHIC_LEFT
     [
-        ExecMethod = Execute ;
+        ExecMethod = ExecuteRotation ;
         StateMethod = GetAttrState ;
     ]
 
     SID_ROTATE_GRAPHIC_RIGHT
     [
-        ExecMethod = Execute ;
+        ExecMethod = ExecuteRotation ;
         StateMethod = GetAttrState ;
     ]
 
diff --git a/sw/source/ui/app/mn.src b/sw/source/ui/app/mn.src
index a9871d4..3c230f9 100644
--- a/sw/source/ui/app/mn.src
+++ b/sw/source/ui/app/mn.src
@@ -1292,15 +1292,27 @@ Menu MN_GRF_POPUPMENU
 
         MenuItem
         {
-            Identifier = SID_ROTATE_GRAPHIC_LEFT ;
-            Command = ".uno:RotateGraphicLeft" ;
-            Text [ en-US ] = "Rotate Graphic Left" ;
-        };
-        MenuItem
-        {
-            Identifier = SID_ROTATE_GRAPHIC_RIGHT ;
-            Command = ".uno:RotateGraphicRight" ;
-            Text [ en-US ] = "Rotate Graphic Right" ;
+            Identifier = SID_MENU_MANAGE_GRAPHIC ;
+            Command = ".uno:ManageGraphicMenu" ;
+            Text [ en-US ] = "~Manage Graphic" ;
+            SubMenu = Menu
+            {
+                ItemList =
+                {
+                    MenuItem
+                    {
+                        Identifier = SID_ROTATE_GRAPHIC_LEFT ;
+                        Command = ".uno:RotateGraphicLeft" ;
+                        Text [ en-US ] = "Rotate 90° Left" ;
+                    };
+                    MenuItem
+                    {
+                        Identifier = SID_ROTATE_GRAPHIC_RIGHT ;
+                        Command = ".uno:RotateGraphicRight" ;
+                        Text [ en-US ] = "Rotate 90° Right" ;
+                    };
+                };
+            };
         };
 
         SEPARATOR;
diff --git a/sw/source/ui/inc/grfsh.hxx b/sw/source/ui/inc/grfsh.hxx
index a066514..b956786 100644
--- a/sw/source/ui/inc/grfsh.hxx
+++ b/sw/source/ui/inc/grfsh.hxx
@@ -26,11 +26,13 @@ class SwGrfShell: public SwBaseShell
 public:
     SFX_DECL_INTERFACE(SW_GRFSHELL)
 
-    void    Execute(SfxRequest &);
-    void    ExecAttr(SfxRequest &);
-    void    GetAttrState(SfxItemSet &);
+    void Execute(SfxRequest& rRequest);
+    void ExecuteRotation(SfxRequest &rRequest);
+    void ExecAttr(SfxRequest& rRequest);
 
-            SwGrfShell(SwView &rView);
+    void GetAttrState(SfxItemSet& rRequest);
+
+    SwGrfShell(SwView &rView);
 };
 
 #endif
diff --git a/sw/source/ui/shells/grfsh.cxx b/sw/source/ui/shells/grfsh.cxx
index ea88327..17c441c 100644
--- a/sw/source/ui/shells/grfsh.cxx
+++ b/sw/source/ui/shells/grfsh.cxx
@@ -42,6 +42,7 @@
 #include <editeng/brushitem.hxx>
 #include <svx/grfflt.hxx>
 #include <svx/compressgraphicdialog.hxx>
+#include <vcl/GraphicNativeTransform.hxx>
 #include <svx/tbxcolor.hxx>
 #include <fmturl.hxx>
 #include <view.hxx>
@@ -72,20 +73,24 @@
 
 #define TOOLBOX_NAME "colorbar"
 
-class SwExternalToolEdit : public ExternalToolEdit
+namespace
 {
-    SwWrtShell*  m_pShell;
+    class SwExternalToolEdit : public ExternalToolEdit
+    {
+        SwWrtShell*  m_pShell;
 
-public:
-    SwExternalToolEdit ( SwWrtShell* pShell ) :
-        m_pShell  (pShell)
-    {}
+    public:
+        SwExternalToolEdit ( SwWrtShell* pShell ) :
+            m_pShell  (pShell)
+        {}
+
+        virtual void Update( Graphic& aGraphic )
+        {
+            m_pShell->ReRead(aEmptyStr, aEmptyStr, (const Graphic*) &aGraphic);
+        }
+    };
+}
 
-    virtual void Update( Graphic& aGraphic )
-    {
-        m_pShell->ReRead(aEmptyStr, aEmptyStr, (const Graphic*) &aGraphic);
-    }
-};
 
 SFX_IMPL_INTERFACE(SwGrfShell, SwBaseShell, SW_RES(STR_SHELLNAME_GRAPHIC))
 {
@@ -162,9 +167,8 @@ void SwGrfShell::Execute(SfxRequest &rReq)
         break;
         case SID_EXTERNAL_EDIT:
         {
-            /* When the graphic is selected to be opened via some external tool
-             * for advanced editing
-             */
+            // When the graphic is selected to be opened via some external tool
+            // for advanced editing
             GraphicObject *pGraphicObject = (GraphicObject *) rSh.GetGraphicObj();
             if(0 != pGraphicObject)
             {
@@ -173,7 +177,6 @@ void SwGrfShell::Execute(SfxRequest &rReq)
             }
         }
         break;
-
         case SID_INSERT_GRAPHIC:
         case FN_FORMAT_GRAFIC_DLG:
         {
@@ -592,6 +595,22 @@ void SwGrfShell::GetAttrState(SfxItemSet &rSet)
             if( rSh.GetGraphicType() == GRAPHIC_NONE )
                 bDisable = true;
             break;
+        case SID_ROTATE_GRAPHIC_LEFT:
+        case SID_ROTATE_GRAPHIC_RIGHT:
+            if( rSh.GetGraphicType() == GRAPHIC_NONE )
+            {
+                bDisable = true;
+            }
+            else
+            {
+                Graphic aGraphic = *rSh.GetGraphic();
+                GraphicNativeTransform aTransform(aGraphic);
+                if (!aTransform.canBeRotated())
+                {
+                    bDisable = true;
+                }
+            }
+            break;
         case SID_COLOR_SETTINGS:
         {
             if ( bParentCntProt || !bIsGrfCntnt )
@@ -732,6 +751,42 @@ void SwGrfShell::GetAttrState(SfxItemSet &rSet)
     SetGetStateSet( 0 );
 }
 
+void SwGrfShell::ExecuteRotation(SfxRequest &rReq)
+{
+    sal_uInt16 aRotation;
+
+    SwWrtShell& rShell = GetShell();
+
+    if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_LEFT)
+    {
+        aRotation = 900;
+    }
+    else if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_RIGHT)
+    {
+        aRotation = 2700;
+    }
+    else
+    {
+        return;
+    }
+
+    rShell.StartAllAction();
+    rShell.StartUndo(UNDO_START);
+
+    Graphic aGraphic = *rShell.GetGraphic();
+    GraphicNativeTransform aTransform(aGraphic);
+    aTransform.rotate(aRotation);
+    rShell.ReRead(aEmptyStr, aEmptyStr, (const Graphic*) &aGraphic);
+
+    SwFlyFrmAttrMgr aManager( false, &rShell, rShell.IsFrmSelected() ? FRMMGR_TYPE_NONE : FRMMGR_TYPE_GRF);
+    Size aSize(aManager.GetSize().Height(), aManager.GetSize().Width());
+    aManager.SetSize(aSize);
+    aManager.UpdateFlyFrm();
+
+    rShell.EndUndo(UNDO_END);
+    rShell.EndAllAction();
+}
+
 
 SwGrfShell::SwGrfShell(SwView &_rView) :
     SwBaseShell(_rView)
commit 06c25631e316fb3eebf88c2e8396ddb5b9aa9b21
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:06:16 2013 +0200

    Remove rotation for SVG for now.
    
    Change-Id: I6f9b9cc510778ea561ebbb9ac215db615ea34a8e

diff --git a/vcl/source/filter/GraphicNativeTransform.cxx b/vcl/source/filter/GraphicNativeTransform.cxx
index cf24d6a..11f3840 100644
--- a/vcl/source/filter/GraphicNativeTransform.cxx
+++ b/vcl/source/filter/GraphicNativeTransform.cxx
@@ -74,10 +74,6 @@ bool GraphicNativeTransform::rotate(sal_uInt16 aInputRotation)
     {
         return rotateJPEG(aRotation);
     }
-    else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_SVG )
-    {
-        return rotateSVG(aRotation);
-    }
     else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_PNG )
     {
         return rotateGeneric(aRotation, OUString("png"));
commit 8ae05bf7a04c961d82c6436f9d299ff22e2cc05a
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:05:01 2013 +0200

    canBeRotated added to ask if native rotation can be performed.
    
    The canBeRotated method was added to determine if a native rotation
    can be performed for a graphics or not.
    
    Change-Id: I026cf6fe4baa4d964d0a2c2b6e36c3b15aa91549

diff --git a/vcl/inc/vcl/GraphicNativeTransform.hxx b/vcl/inc/vcl/GraphicNativeTransform.hxx
index 6bf83fe..db727a2 100644
--- a/vcl/inc/vcl/GraphicNativeTransform.hxx
+++ b/vcl/inc/vcl/GraphicNativeTransform.hxx
@@ -27,13 +27,13 @@ class VCL_DLLPUBLIC GraphicNativeTransform
     Graphic& mrGraphic;
 
     bool rotateJPEG     (sal_uInt16 aRotation);
-    bool rotateSVG      (sal_uInt16 aRotation);
     bool rotateGeneric  (sal_uInt16 aRotation, OUString aType);
 
 public:
     GraphicNativeTransform(Graphic& rGraphic);
     virtual ~GraphicNativeTransform();
 
+    bool canBeRotated();
     bool rotate(sal_uInt16 aRotation);
 };
 
diff --git a/vcl/source/filter/GraphicNativeTransform.cxx b/vcl/source/filter/GraphicNativeTransform.cxx
index d679003..cf24d6a 100644
--- a/vcl/source/filter/GraphicNativeTransform.cxx
+++ b/vcl/source/filter/GraphicNativeTransform.cxx
@@ -35,6 +35,26 @@ GraphicNativeTransform::GraphicNativeTransform(Graphic& rGraphic) :
 GraphicNativeTransform::~GraphicNativeTransform()
 {}
 
+bool GraphicNativeTransform::canBeRotated()
+{
+    GfxLink aLink = mrGraphic.GetLink();
+
+    // Don't allow rotation on animations for now
+    if (mrGraphic.IsAnimated())
+    {
+        return false;
+    }
+
+    if (   aLink.GetType() == GFX_LINK_TYPE_NATIVE_JPG
+        || aLink.GetType() == GFX_LINK_TYPE_NATIVE_PNG
+        || aLink.GetType() == GFX_LINK_TYPE_NATIVE_GIF)
+    {
+        return true;
+    }
+
+    return false;
+}
+
 bool GraphicNativeTransform::rotate(sal_uInt16 aInputRotation)
 {
     // Rotation can be between 0 and 3600
commit 29545247e4bab9f0e0acd7043bfc52880409a310
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:04:05 2013 +0200

    Use GraphicFilter directly in GraphicNativeTransform.
    
    Change-Id: Ib7c028ae32783f112507fb848398b389ed7a484f

diff --git a/vcl/inc/vcl/GraphicNativeTransform.hxx b/vcl/inc/vcl/GraphicNativeTransform.hxx
index 40b661b..6bf83fe 100644
--- a/vcl/inc/vcl/GraphicNativeTransform.hxx
+++ b/vcl/inc/vcl/GraphicNativeTransform.hxx
@@ -28,7 +28,7 @@ class VCL_DLLPUBLIC GraphicNativeTransform
 
     bool rotateJPEG     (sal_uInt16 aRotation);
     bool rotateSVG      (sal_uInt16 aRotation);
-    bool rotateGeneric  (sal_uInt16 aRotation, sal_uInt32 aType);
+    bool rotateGeneric  (sal_uInt16 aRotation, OUString aType);
 
 public:
     GraphicNativeTransform(Graphic& rGraphic);
diff --git a/vcl/source/filter/GraphicNativeTransform.cxx b/vcl/source/filter/GraphicNativeTransform.cxx
index 9759592..d679003 100644
--- a/vcl/source/filter/GraphicNativeTransform.cxx
+++ b/vcl/source/filter/GraphicNativeTransform.cxx
@@ -20,7 +20,9 @@
 #include <vcl/GraphicNativeTransform.hxx>
 
 #include <vcl/gfxlink.hxx>
-#include <vcl/cvtgrf.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
 
 
 #include "jpeg/Exif.hxx"
@@ -33,13 +35,19 @@ GraphicNativeTransform::GraphicNativeTransform(Graphic& rGraphic) :
 GraphicNativeTransform::~GraphicNativeTransform()
 {}
 
-bool GraphicNativeTransform::rotate(sal_uInt16 aRotation)
+bool GraphicNativeTransform::rotate(sal_uInt16 aInputRotation)
 {
-    if (aRotation == 0)
-        return true;
+    // Rotation can be between 0 and 3600
+    sal_uInt16 aRotation = aInputRotation % 3600;
 
-    if (aRotation != 900 && aRotation != 1800 && aRotation != 2700)
+    if (aRotation == 0)
+    {
+        return true; // No rotation is needed
+    }
+    else if (aRotation != 900 && aRotation != 1800 && aRotation != 2700)
+    {
         return false;
+    }
 
     GfxLink aLink = mrGraphic.GetLink();
     if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_JPG )
@@ -52,44 +60,47 @@ bool GraphicNativeTransform::rotate(sal_uInt16 aRotation)
     }
     else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_PNG )
     {
-        return rotateGeneric(aRotation, CVT_PNG);
+        return rotateGeneric(aRotation, OUString("png"));
     }
     else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_GIF )
     {
-        return rotateGeneric(aRotation, CVT_PNG);
+        return rotateGeneric(aRotation, OUString("gif"));
     }
     return false;
 }
 
-bool GraphicNativeTransform::rotateGeneric(sal_uInt16 aRotation, sal_uInt32 aType)
+bool GraphicNativeTransform::rotateGeneric(sal_uInt16 aRotation, OUString aType)
 {
-    BitmapEx aBitmap = mrGraphic.GetBitmapEx();
-    aBitmap.Rotate(aRotation, COL_BLACK);
+    // Can't rotate animations yet
+    if (mrGraphic.IsAnimated())
+    {
+        return false;
+    }
 
     SvMemoryStream aStream;
-    GraphicConverter::Export(aStream, aBitmap, aType);
-    aStream.Seek( STREAM_SEEK_TO_BEGIN );
 
-    Graphic aNewGraphic;
-    GraphicConverter::Import(aStream, aNewGraphic, aType);
+    GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
 
-    mrGraphic = aNewGraphic;
-    return true;
-}
+    css::uno::Sequence< css::beans::PropertyValue > aFilterData( 3 );
+    aFilterData[ 0 ].Name = "Interlaced";
+    aFilterData[ 0 ].Value <<= (sal_Int32) 0;
+    aFilterData[ 1 ].Name = "Compression";
+    aFilterData[ 1 ].Value <<= (sal_Int32) 9;
+    aFilterData[ 2 ].Name = "Quality";
+    aFilterData[ 2 ].Value <<= (sal_Int32) 90;
 
-bool GraphicNativeTransform::rotateSVG(sal_uInt16 aRotation)
-{
-    GDIMetaFile aGDIMetafile = mrGraphic.GetGDIMetaFile();
-    //aGDIMetafile.Rotate(aRotation);
+    sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( aType );
+
+    BitmapEx aBitmap = mrGraphic.GetBitmapEx();
+    aBitmap.Rotate(aRotation, COL_BLACK);
+    rFilter.ExportGraphic( aBitmap, OUString( "none" ), aStream, nFilterFormat, &aFilterData );
 
-    SvMemoryStream aStream;
-    GraphicConverter::Export(aStream, aGDIMetafile, CVT_SVG);
     aStream.Seek( STREAM_SEEK_TO_BEGIN );
 
-    Graphic aNewGraphic;
-    GraphicConverter::Import(aStream, aNewGraphic, CVT_SVG);
+    Graphic aGraphic;
+    rFilter.ImportGraphic( aGraphic, OUString("import"), aStream );
 
-    mrGraphic = aNewGraphic;
+    mrGraphic = aGraphic;
     return true;
 }
 
commit 75f60bff0811b521b39c3d5cddc35e06556ab25e
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:02:49 2013 +0200

    Add rotation for PNG and GIF to GraphicNativeRotation.
    
    Rotation for PNG and GIF format perform by exporting and importing
    of the Graphic. This is a "fallback" way to perform graphic rotation
    and the easiest to do for lossless raster formats.
    
    Change-Id: I31efad9106b5cfbd1d7c6c5063726c455d05f934

diff --git a/sw/source/ui/uiview/view2.cxx b/sw/source/ui/uiview/view2.cxx
index 3cf7c4a..b48e403 100644
--- a/sw/source/ui/uiview/view2.cxx
+++ b/sw/source/ui/uiview/view2.cxx
@@ -177,9 +177,7 @@ static void lcl_SetAllTextToDefaultLanguage( SwWrtShell &rWrtSh, sal_uInt16 nWhi
     }
 }
 
-/*---------------------------------------------------------------------------
-    Beschreibung:   String fuer die Seitenanzeige in der Statusbar basteln.
- ----------------------------------------------------------------------------*/
+/* Create string for showing of page in statusbar */
 String SwView::GetPageStr( sal_uInt16 nPg, sal_uInt16 nLogPg,
                             const String& rDisplay )
 {
@@ -220,16 +218,17 @@ int SwView::InsertGraphic( const String &rPath, const String &rFilter,
     if( GRFILTER_OK == nRes )
     {
         GraphicNativeMetadata aMetadata;
-        if (aMetadata.Read(aGrf))
+        if (aMetadata.read(aGrf))
         {
-            if (aMetadata.GetRotation() != 0)
+            sal_uInt16 aRotation = aMetadata.getRotation();
+            if (aRotation != 0)
             {
                 OUString aMessage("This image is rotated. Would you like LibreOffice to rotate it into standard orientation?");
                 QueryBox aQueryBox(GetWindow(), WB_YES_NO | WB_DEF_YES, aMessage);
                 if (aQueryBox.Execute() == RET_YES)
                 {
                     GraphicNativeTransform aTransform(aGrf);
-                    aTransform.Rotate(aMetadata.GetRotation());
+                    aTransform.rotate( aRotation );
                 }
             }
         }
diff --git a/vcl/inc/vcl/GraphicNativeMetadata.hxx b/vcl/inc/vcl/GraphicNativeMetadata.hxx
index 711f81a..ab5b767 100644
--- a/vcl/inc/vcl/GraphicNativeMetadata.hxx
+++ b/vcl/inc/vcl/GraphicNativeMetadata.hxx
@@ -30,8 +30,8 @@ public:
     GraphicNativeMetadata();
     virtual ~GraphicNativeMetadata();
 
-    bool Read(Graphic& rGraphic);
-    sal_uInt16 GetRotation();
+    bool read(Graphic& rGraphic);
+    sal_uInt16 getRotation();
 };
 
 #endif  //_GRAPHICNATIVEMETADATA_HXX
diff --git a/vcl/inc/vcl/GraphicNativeTransform.hxx b/vcl/inc/vcl/GraphicNativeTransform.hxx
index ed6b702..40b661b 100644
--- a/vcl/inc/vcl/GraphicNativeTransform.hxx
+++ b/vcl/inc/vcl/GraphicNativeTransform.hxx
@@ -25,11 +25,16 @@
 class VCL_DLLPUBLIC GraphicNativeTransform
 {
     Graphic& mrGraphic;
+
+    bool rotateJPEG     (sal_uInt16 aRotation);
+    bool rotateSVG      (sal_uInt16 aRotation);
+    bool rotateGeneric  (sal_uInt16 aRotation, sal_uInt32 aType);
+
 public:
     GraphicNativeTransform(Graphic& rGraphic);
     virtual ~GraphicNativeTransform();
 
-    bool Rotate(sal_uInt16 aRotation);
+    bool rotate(sal_uInt16 aRotation);
 };
 
 #endif  //_GRAPHICNATIVETRANSFORM_HXX
diff --git a/vcl/source/filter/GraphicNativeMetadata.cxx b/vcl/source/filter/GraphicNativeMetadata.cxx
index c147f54..1339ec8 100644
--- a/vcl/source/filter/GraphicNativeMetadata.cxx
+++ b/vcl/source/filter/GraphicNativeMetadata.cxx
@@ -30,12 +30,12 @@ GraphicNativeMetadata::GraphicNativeMetadata() :
 GraphicNativeMetadata::~GraphicNativeMetadata()
 {}
 
-sal_uInt16 GraphicNativeMetadata::GetRotation()
+sal_uInt16 GraphicNativeMetadata::getRotation()
 {
     return mRotation;
 }
 
-bool GraphicNativeMetadata::Read(Graphic& rGraphic)
+bool GraphicNativeMetadata::read(Graphic& rGraphic)
 {
     GfxLink aLink = rGraphic.GetLink();
     if ( aLink.GetType() != GFX_LINK_TYPE_NATIVE_JPG )
diff --git a/vcl/source/filter/GraphicNativeTransform.cxx b/vcl/source/filter/GraphicNativeTransform.cxx
index 6115e93..9759592 100644
--- a/vcl/source/filter/GraphicNativeTransform.cxx
+++ b/vcl/source/filter/GraphicNativeTransform.cxx
@@ -20,6 +20,8 @@
 #include <vcl/GraphicNativeTransform.hxx>
 
 #include <vcl/gfxlink.hxx>
+#include <vcl/cvtgrf.hxx>
+
 
 #include "jpeg/Exif.hxx"
 #include "jpeg/JpegTransform.hxx"
@@ -31,7 +33,7 @@ GraphicNativeTransform::GraphicNativeTransform(Graphic& rGraphic) :
 GraphicNativeTransform::~GraphicNativeTransform()
 {}
 
-bool GraphicNativeTransform::Rotate(sal_uInt16 aRotation)
+bool GraphicNativeTransform::rotate(sal_uInt16 aRotation)
 {
     if (aRotation == 0)
         return true;
@@ -40,8 +42,60 @@ bool GraphicNativeTransform::Rotate(sal_uInt16 aRotation)
         return false;
 
     GfxLink aLink = mrGraphic.GetLink();
-    if ( aLink.GetType() != GFX_LINK_TYPE_NATIVE_JPG )
-        return false;
+    if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_JPG )
+    {
+        return rotateJPEG(aRotation);
+    }
+    else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_SVG )
+    {
+        return rotateSVG(aRotation);
+    }
+    else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_PNG )
+    {
+        return rotateGeneric(aRotation, CVT_PNG);
+    }
+    else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_GIF )
+    {
+        return rotateGeneric(aRotation, CVT_PNG);
+    }
+    return false;
+}
+
+bool GraphicNativeTransform::rotateGeneric(sal_uInt16 aRotation, sal_uInt32 aType)
+{
+    BitmapEx aBitmap = mrGraphic.GetBitmapEx();
+    aBitmap.Rotate(aRotation, COL_BLACK);
+
+    SvMemoryStream aStream;
+    GraphicConverter::Export(aStream, aBitmap, aType);
+    aStream.Seek( STREAM_SEEK_TO_BEGIN );
+
+    Graphic aNewGraphic;
+    GraphicConverter::Import(aStream, aNewGraphic, aType);
+
+    mrGraphic = aNewGraphic;
+    return true;
+}
+
+bool GraphicNativeTransform::rotateSVG(sal_uInt16 aRotation)
+{
+    GDIMetaFile aGDIMetafile = mrGraphic.GetGDIMetaFile();
+    //aGDIMetafile.Rotate(aRotation);
+
+    SvMemoryStream aStream;
+    GraphicConverter::Export(aStream, aGDIMetafile, CVT_SVG);
+    aStream.Seek( STREAM_SEEK_TO_BEGIN );
+
+    Graphic aNewGraphic;
+    GraphicConverter::Import(aStream, aNewGraphic, CVT_SVG);
+
+    mrGraphic = aNewGraphic;
+    return true;
+}
+
+bool GraphicNativeTransform::rotateJPEG(sal_uInt16 aRotation)
+{
+    GfxLink aLink = mrGraphic.GetLink();
 
     sal_uInt32 aDataSize = aLink.GetDataSize();
     sal_uInt8* aInputBuffer = new sal_uInt8[aDataSize];
commit 6c7e476ae6b6ff56b81ff19ef7dd0e8a9083a257
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:01:40 2013 +0200

    Regster rotate left, right menu items.
    
    Change-Id: I64340da256a9ee66b13870854ccdccacaaf4f0d2

diff --git a/svx/inc/svx/svxids.hrc b/svx/inc/svx/svxids.hrc
index a343df4..da669b8 100644
--- a/svx/inc/svx/svxids.hrc
+++ b/svx/inc/svx/svxids.hrc
@@ -923,15 +923,18 @@
 #define SID_INSERT_FORM_HSCROLL                         (SID_SVX_START+1112)
 #define SID_EXTERNAL_EDIT                               (SID_SVX_START+1113)
 #define SID_ATTR_PAGE_SHARED_FIRST                      (SID_SVX_START+1114)
-#define SID_CHANGE_PICTURE                              (SID_SVX_START+1125)
 #define SID_SAVE_GRAPHIC                                (SID_SVX_START+1116)
 #define SID_COMPRESS_GRAPHIC                            (SID_SVX_START+1117)
 #define SID_FRAME_UP                                    (SID_SVX_START+1118)
 #define SID_FRAME_DOWN                                  (SID_SVX_START+1119)
 #define SID_ATTR_SPECIALCHAR                            (SID_SVX_START+1120)
+#define SID_CHANGE_PICTURE                              (SID_SVX_START+1125)
+#define SID_ROTATE_GRAPHIC_LEFT                         (SID_SVX_START+1126)
+#define SID_ROTATE_GRAPHIC_RIGHT                        (SID_SVX_START+1127)
+
 
 // IMPORTANT NOTE: adjust SID_SVX_FIRSTFREE, when adding new slot id
-#define SID_SVX_FIRSTFREE                               (SID_COMPRESS_GRAPHIC + 1)
+#define SID_SVX_FIRSTFREE                               (SID_ROTATE_GRAPHIC_RIGHT + 1)
 
 // --------------------------------------------------------------------------
 // Overflow check for slot IDs
diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi
index 279954b..0778bb4 100644
--- a/svx/sdi/svx.sdi
+++ b/svx/sdi/svx.sdi
@@ -5942,6 +5942,53 @@ SfxBoolItem ImageMapExecute SID_IMAP_EXEC
 ]
 
 SfxVoidItem ExternalEdit SID_EXTERNAL_EDIT
+[
+    /* flags: */
+    AutoUpdate = FALSE,
+    Cachable = Cachable,
+    FastCall = FALSE,
+    HasCoreId = FALSE,
+    HasDialog = FALSE,
+    ReadOnlyDoc = TRUE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+    Synchron;
+
+    /* config: */
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    StatusBarConfig = FALSE,
+    ToolBoxConfig = TRUE,
+    GroupId = GID_GRAPHIC;
+]
+
+SfxVoidItem RotateGraphicLeft SID_ROTATE_GRAPHIC_LEFT
+
+[
+    /* flags: */
+    AutoUpdate = FALSE,
+    Cachable = Cachable,
+    FastCall = FALSE,
+    HasCoreId = FALSE,
+    HasDialog = FALSE,
+    ReadOnlyDoc = TRUE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+    Synchron;
+
+    /* config: */
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    StatusBarConfig = FALSE,
+    ToolBoxConfig = TRUE,
+    GroupId = GID_GRAPHIC;
+]
+
+SfxVoidItem RotateGraphicRight SID_ROTATE_GRAPHIC_RIGHT
 
 [
     /* flags: */
diff --git a/sw/sdi/_grfsh.sdi b/sw/sdi/_grfsh.sdi
index a767184..f91eba9 100644
--- a/sw/sdi/_grfsh.sdi
+++ b/sw/sdi/_grfsh.sdi
@@ -60,6 +60,18 @@ interface BaseTextGraphic
         StateMethod = GetAttrState ;
     ]
 
+    SID_ROTATE_GRAPHIC_LEFT
+    [
+        ExecMethod = Execute ;
+        StateMethod = GetAttrState ;
+    ]
+
+    SID_ROTATE_GRAPHIC_RIGHT
+    [
+        ExecMethod = Execute ;
+        StateMethod = GetAttrState ;
+    ]
+
     SID_INSERT_GRAPHIC // zeigt auf FN_FORMAT_GRAFIC_DLG
     [
         ExecMethod = Execute ;
diff --git a/sw/source/ui/app/mn.src b/sw/source/ui/app/mn.src
index 15f275b..a9871d4 100644
--- a/sw/source/ui/app/mn.src
+++ b/sw/source/ui/app/mn.src
@@ -1289,6 +1289,20 @@ Menu MN_GRF_POPUPMENU
         MenuItem { ITEM_SAVE_GRAPHIC };
         MenuItem { ITEM_COMPRESS_GRAPHIC };
         MenuItem { ITEM_EXTERNAL_EDIT };
+
+        MenuItem
+        {
+            Identifier = SID_ROTATE_GRAPHIC_LEFT ;
+            Command = ".uno:RotateGraphicLeft" ;
+            Text [ en-US ] = "Rotate Graphic Left" ;
+        };
+        MenuItem
+        {
+            Identifier = SID_ROTATE_GRAPHIC_RIGHT ;
+            Command = ".uno:RotateGraphicRight" ;
+            Text [ en-US ] = "Rotate Graphic Right" ;
+        };
+
         SEPARATOR;
         MenuItem
         {
diff --git a/vcl/source/filter/jpeg/transupp.c b/vcl/source/filter/jpeg/transupp.c
index 24b7667..fd2ff37 100644
--- a/vcl/source/filter/jpeg/transupp.c
+++ b/vcl/source/filter/jpeg/transupp.c
@@ -1593,6 +1593,8 @@ jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
    * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
    * if the encoder library already wrote one.
    */
+   if (option) {}
+
   for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
     if (dstinfo->write_JFIF_header &&
     marker->marker == JPEG_APP0 &&
commit 56b61a3a92e91d5814076ea66bd16fca98ecbd9b
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 14:00:26 2013 +0200

    Detect image rotation when inserting images and perform lossless rotation.
    
    If Exif in an Jpeg image indicates that the image is rotated, ask
    the user if rotate the image to standard orientation. If yes, perform
    lossless rotation of the image.
    
    Change-Id: I164da2b06b7fd114f4d2a5a352719c47497daeae

diff --git a/sw/source/ui/uiview/view2.cxx b/sw/source/ui/uiview/view2.cxx
index dbc1dae..3cf7c4a 100644
--- a/sw/source/ui/uiview/view2.cxx
+++ b/sw/source/ui/uiview/view2.cxx
@@ -134,6 +134,9 @@
 #include <docstat.hxx>
 #include <wordcountdialog.hxx>
 
+#include <vcl/GraphicNativeTransform.hxx>
+#include <vcl/GraphicNativeMetadata.hxx>
+
 const char sStatusDelim[] = " : ";
 const char sStatusComma[] = " , ";//#outlinelevel, define a Variable for "," add by zhaojianwei
 
@@ -216,6 +219,21 @@ int SwView::InsertGraphic( const String &rPath, const String &rFilter,
 
     if( GRFILTER_OK == nRes )
     {
+        GraphicNativeMetadata aMetadata;
+        if (aMetadata.Read(aGrf))
+        {
+            if (aMetadata.GetRotation() != 0)
+            {
+                OUString aMessage("This image is rotated. Would you like LibreOffice to rotate it into standard orientation?");
+                QueryBox aQueryBox(GetWindow(), WB_YES_NO | WB_DEF_YES, aMessage);
+                if (aQueryBox.Execute() == RET_YES)
+                {
+                    GraphicNativeTransform aTransform(aGrf);
+                    aTransform.Rotate(aMetadata.GetRotation());
+                }
+            }
+        }
+
         SwFlyFrmAttrMgr aFrmMgr( sal_True, GetWrtShellPtr(), FRMMGR_TYPE_GRF );
 
         SwWrtShell &rSh = GetWrtShell();
commit b5a9cc71d246c26da8aca4203da84c10c104c222
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sun Apr 21 13:58:37 2013 +0200

    Exif reading/writing and Jpeg lossless transformations support.
    
    Support for reading/writing of Exif image metadata. Currently only
    orientation is implemented, but support for other tags can be added.
    
    Jpeg lossless transformations - currently only lossless rotation is
    supported, but others can be added when needed.
    
    Additionally GraphicNativeTransform and GraphicNativeMetadata has
    been added. The responsibillity of GraphicNativeTransform is to
    provide graphic transformations (like rotation) on native data and
    the purpose is to be as lossless as possible in transformations.
    GraphicNativeMetadata is a class for reading metadata which is
    contained in a native data graphic stream. For now both support
    only Jpeg.
    
    Change-Id: I3e67cd3e7f5386746bcd1f0bfd2b90f5fe834b92

diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 057e508..ab66d47 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -169,6 +169,8 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/filter/FilterConfigItem \
     vcl/source/filter/graphicfilter \
     vcl/source/filter/graphicfilter2 \
+    vcl/source/filter/GraphicNativeTransform \
+    vcl/source/filter/GraphicNativeMetadata \
     vcl/source/filter/sgfbram \
     vcl/source/filter/sgvmain \
     vcl/source/filter/sgvspln \
@@ -177,9 +179,11 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/filter/igif/gifread \
     vcl/source/filter/ixbm/xbmread \
     vcl/source/filter/ixpm/xpmread \
+    vcl/source/filter/jpeg/Exif \
     vcl/source/filter/jpeg/jpeg \
     vcl/source/filter/jpeg/JpegReader \
     vcl/source/filter/jpeg/JpegWriter \
+    vcl/source/filter/jpeg/JpegTransform \
     vcl/source/filter/wmf/emfwr \
     vcl/source/filter/wmf/enhwmf \
     vcl/source/filter/wmf/winmtf \
@@ -317,6 +321,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
 
 $(eval $(call gb_Library_add_cobjects,vcl,\
     vcl/source/filter/jpeg/jpegc \
+    vcl/source/filter/jpeg/transupp \
 ))
 
 # optional parts
diff --git a/vcl/Package_inc.mk b/vcl/Package_inc.mk
index 69fff7d..0fc6bb8 100644
--- a/vcl/Package_inc.mk
+++ b/vcl/Package_inc.mk
@@ -66,6 +66,8 @@ $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/gradient.hxx,vcl/gradient.hxx)
 $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/graph.h,vcl/graph.h))
 $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/graph.hxx,vcl/graph.hxx))
 $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/graphicfilter.hxx,vcl/graphicfilter.hxx))
+$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/GraphicNativeTransform.hxx,vcl/GraphicNativeTransform.hxx))
+$(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/GraphicNativeMetadata.hxx,vcl/GraphicNativeMetadata.hxx))
 $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/graphictools.hxx,vcl/graphictools.hxx))
 $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/group.hxx,vcl/group.hxx))
 $(eval $(call gb_Package_add_file,vcl_inc,inc/vcl/hatch.hxx,vcl/hatch.hxx))
diff --git a/vcl/inc/vcl/GraphicNativeMetadata.hxx b/vcl/inc/vcl/GraphicNativeMetadata.hxx
new file mode 100644
index 0000000..711f81a
--- /dev/null
+++ b/vcl/inc/vcl/GraphicNativeMetadata.hxx
@@ -0,0 +1,39 @@
+/* -*- 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 .
+ */
+
+#ifndef _GRAPHICNATIVEMETADATA_HXX
+#define _GRAPHICNATIVEMETADATA_HXX
+
+#include <vcl/graph.hxx>
+
+class VCL_DLLPUBLIC GraphicNativeMetadata
+{
+    sal_uInt16 mRotation;
+
+public:
+    GraphicNativeMetadata();
+    virtual ~GraphicNativeMetadata();
+
+    bool Read(Graphic& rGraphic);
+    sal_uInt16 GetRotation();
+};
+
+#endif  //_GRAPHICNATIVEMETADATA_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/vcl/GraphicNativeTransform.hxx b/vcl/inc/vcl/GraphicNativeTransform.hxx
new file mode 100644
index 0000000..ed6b702
--- /dev/null
+++ b/vcl/inc/vcl/GraphicNativeTransform.hxx
@@ -0,0 +1,37 @@
+/* -*- 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 .
+ */
+
+#ifndef _GRAPHICNATIVETRANSFORM_HXX
+#define _GRAPHICNATIVETRANSFORM_HXX
+
+#include <vcl/graph.hxx>
+
+class VCL_DLLPUBLIC GraphicNativeTransform
+{
+    Graphic& mrGraphic;
+public:
+    GraphicNativeTransform(Graphic& rGraphic);
+    virtual ~GraphicNativeTransform();
+
+    bool Rotate(sal_uInt16 aRotation);
+};
+
+#endif  //_GRAPHICNATIVETRANSFORM_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/GraphicNativeMetadata.cxx b/vcl/source/filter/GraphicNativeMetadata.cxx
new file mode 100644
index 0000000..c147f54
--- /dev/null
+++ b/vcl/source/filter/GraphicNativeMetadata.cxx
@@ -0,0 +1,58 @@
+/* -*- 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 <vcl/GraphicNativeMetadata.hxx>
+
+#include <vcl/gfxlink.hxx>
+
+#include "jpeg/Exif.hxx"
+
+GraphicNativeMetadata::GraphicNativeMetadata() :
+    mRotation(0)
+{}
+
+GraphicNativeMetadata::~GraphicNativeMetadata()
+{}
+
+sal_uInt16 GraphicNativeMetadata::GetRotation()
+{
+    return mRotation;
+}
+
+bool GraphicNativeMetadata::Read(Graphic& rGraphic)
+{
+    GfxLink aLink = rGraphic.GetLink();
+    if ( aLink.GetType() != GFX_LINK_TYPE_NATIVE_JPG )
+        return false;
+    sal_uInt32 aDataSize = aLink.GetDataSize();
+    sal_uInt8* aBuffer = new sal_uInt8[aDataSize];
+
+    memcpy(aBuffer, aLink.GetData(), aDataSize);
+    SvMemoryStream aMemoryStream(aBuffer, aDataSize, STREAM_READ);
+
+    Exif aExif;
+    aExif.read(aMemoryStream);
+    mRotation = aExif.getRotation();
+
+    delete[] aBuffer;
+    return true;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/GraphicNativeTransform.cxx b/vcl/source/filter/GraphicNativeTransform.cxx
new file mode 100644
index 0000000..6115e93
--- /dev/null
+++ b/vcl/source/filter/GraphicNativeTransform.cxx
@@ -0,0 +1,78 @@
+/* -*- 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 <vcl/GraphicNativeTransform.hxx>
+
+#include <vcl/gfxlink.hxx>
+
+#include "jpeg/Exif.hxx"
+#include "jpeg/JpegTransform.hxx"
+
+GraphicNativeTransform::GraphicNativeTransform(Graphic& rGraphic) :
+    mrGraphic(rGraphic)
+{}
+
+GraphicNativeTransform::~GraphicNativeTransform()
+{}
+
+bool GraphicNativeTransform::Rotate(sal_uInt16 aRotation)
+{
+    if (aRotation == 0)
+        return true;
+
+    if (aRotation != 900 && aRotation != 1800 && aRotation != 2700)
+        return false;
+
+    GfxLink aLink = mrGraphic.GetLink();
+    if ( aLink.GetType() != GFX_LINK_TYPE_NATIVE_JPG )
+        return false;
+
+    sal_uInt32 aDataSize = aLink.GetDataSize();
+    sal_uInt8* aInputBuffer = new sal_uInt8[aDataSize];
+
+    memcpy(aInputBuffer, aLink.GetData(), aDataSize);
+    SvMemoryStream aSourceStream(aInputBuffer, aDataSize, STREAM_READ);
+
+    SvMemoryStream aTargetStream;
+    JpegTransform tranform(aSourceStream, aTargetStream);
+    tranform.setRotate(aRotation);
+    tranform.perform();
+
+    aTargetStream.Seek( STREAM_SEEK_TO_BEGIN );
+
+    Exif exif;
+    exif.setOrientation(Orientation::TOP_LEFT);
+    exif.write(aTargetStream);
+
+    aTargetStream.Seek( STREAM_SEEK_TO_END );
+    sal_uInt32 aBufferSize = aTargetStream.Tell();
+    sal_uInt8* pBuffer = new sal_uInt8[ aBufferSize ];
+
+    aTargetStream.Seek( STREAM_SEEK_TO_BEGIN );
+    aTargetStream.Read( pBuffer, aBufferSize );
+
+    BitmapEx aBitmap = mrGraphic.GetBitmapEx();
+    aBitmap.Rotate(aRotation, COL_BLACK);
+    mrGraphic = aBitmap;
+    mrGraphic.SetLink( GfxLink( pBuffer, aBufferSize, aLink.GetType(), sal_True ) );
+    return true;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/jpeg/Exif.cxx b/vcl/source/filter/jpeg/Exif.cxx
new file mode 100644
index 0000000..f0b1970
--- /dev/null
+++ b/vcl/source/filter/jpeg/Exif.cxx
@@ -0,0 +1,167 @@
+/* -*- 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 "Exif.hxx"
+
+Exif::Exif() :
+    maOrientation(TOP_LEFT)
+{}
+
+Exif::~Exif()
+{}
+
+Orientation Exif::getOrientation() {
+    return maOrientation;
+}
+
+void Exif::setOrientation(Orientation aOrientation) {
+    maOrientation = aOrientation;
+}
+
+Orientation Exif::convertToOrientation(sal_Int32 value)
+{
+    switch(value) {
+        case 1: return TOP_LEFT;
+        case 2: return TOP_RIGHT;
+        case 3: return BOTTOM_RIGHT;
+        case 4: return BOTTOM_LEFT;
+        case 5: return LEFT_TOP;
+        case 6: return RIGHT_TOP;
+        case 7: return RIGHT_BOTTOM;
+        case 8: return LEFT_BOTTOM;
+    }
+    return TOP_LEFT;
+}
+
+sal_Int32 Exif::getRotation()
+{
+    switch(maOrientation) {
+        case TOP_LEFT:
+            return 0;
+        case BOTTOM_RIGHT:
+            return 1800;
+        case RIGHT_TOP:
+            return 2700;
+        case LEFT_BOTTOM:
+            return 900;
+        default:
+            return 0;
+    }
+    return 0;
+}
+
+bool Exif::read(SvStream& rStream)
+{
+    sal_Int32 nStreamPosition = rStream.Tell();
+    bool result = processJpegStream(rStream, false);
+    rStream.Seek( nStreamPosition );
+
+    return result;
+}
+
+bool Exif::write(SvStream& rStream)
+{
+    sal_Int32 nStreamPosition = rStream.Tell();
+    bool result = processJpegStream(rStream, true);
+    rStream.Seek( nStreamPosition );
+
+    return result;
+}
+
+bool Exif::processJpegStream(SvStream& rStream, bool bSetValue)
+{
+    sal_uInt32  aMagic32;
+    sal_uInt16  aMagic16;
+    sal_uInt16  aLength;
+
+    rStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
+    rStream >> aMagic32;
+
+    // Compare JPEG magic bytes
+    if( 0xffd8ff00 != ( aMagic32 & 0xffffff00 ) )
+    {
+        return false;
+    }
+
+    rStream >> aLength;
+    if (aLength < 8)
+    {
+        return false;
+    }
+    aLength -= 8;
+
+    rStream >> aMagic32;
+    rStream >> aMagic16;
+
+    // Compare EXIF magic bytes
+    if( 0x45786966 != aMagic32 || 0x0000 != aMagic16)
+    {
+        return false;
+    }
+
+    sal_uInt8* exifData = new sal_uInt8[aLength];
+    sal_uInt32 aExifDataBeginPosition = rStream.Tell();
+    rStream.Read(exifData, aLength);
+
+    sal_uInt16 offset;
+    offset = exifData[5];
+    offset <<= 8;
+    offset += exifData[4];
+
+    sal_uInt16 numberOfTags;
+    numberOfTags = exifData[offset+1];
+    numberOfTags <<= 8;
+    numberOfTags += exifData[offset];
+
+    offset += 2;
+
+    ExifIFD* ifd = NULL;
+
+    while (offset <= aLength - 12 && numberOfTags > 0) {
+        ifd = (ExifIFD*) &exifData[offset];
+
+        if (ifd->tag == Tag::ORIENTATION)
+        {
+            if(bSetValue)
+            {
+                ifd->tag = Tag::ORIENTATION;
+                ifd->type = 3;
+                ifd->count = 1;
+                ifd->offset = maOrientation;
+            }
+            else
+            {
+                maOrientation = convertToOrientation(ifd->offset);
+            }
+        }
+
+        numberOfTags--;
+        offset += 12;
+    }
+
+    if (bSetValue)
+    {
+        rStream.Seek(aExifDataBeginPosition);
+        rStream.Write(exifData, aLength);
+    }
+
+    return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/jpeg/Exif.hxx b/vcl/source/filter/jpeg/Exif.hxx
new file mode 100644
index 0000000..cce6a63
--- /dev/null
+++ b/vcl/source/filter/jpeg/Exif.hxx
@@ -0,0 +1,82 @@
+/* -*- 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 .
+ */
+
+#ifndef _EXIF_HXX
+#define _EXIF_HXX
+
+#include <vcl/graph.hxx>
+#include <vcl/fltcall.hxx>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+
+enum Orientation {
+    TOP_LEFT        = 1,
+    TOP_RIGHT       = 2,
+    BOTTOM_RIGHT    = 3,
+    BOTTOM_LEFT     = 4,
+    LEFT_TOP        = 5,
+    RIGHT_TOP       = 6,
+    RIGHT_BOTTOM    = 7,
+    LEFT_BOTTOM     = 8
+};
+
+enum Tag {
+    IMAGE_WIDTH     = 0x0100,
+    IMAGE_HEIGHT    = 0x0101,
+    BITS_PER_SAMPLE = 0x0102,
+    COMPRESSION     = 0x0103,
+    ORIENTATION     = 0x0112
+};
+
+class Exif
+{
+private:
+    Orientation maOrientation;
+    sal_Int32  mnStreamPosition;
+
+    bool processJpegStream(SvStream& rStream, bool bSetValue);
+
+    struct ExifIFD {
+        sal_uInt16 tag;
+        sal_uInt16 type;
+        sal_uInt32 count;
+        sal_uInt32 offset;
+    };
+
+    Orientation convertToOrientation(sal_Int32 value);
+
+public :
+    Exif();
+    virtual ~Exif();
+
+    Orientation getOrientation();
+    sal_Int32 getRotation();
+
+    void setOrientation(Orientation orientation);
+
+    bool read(SvStream& rStream);
+    bool write(SvStream& rStream);
+
+};
+
+
+#endif // _EXIF_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/jpeg/JpegTransform.cxx b/vcl/source/filter/jpeg/JpegTransform.cxx
new file mode 100644
index 0000000..789d303
--- /dev/null
+++ b/vcl/source/filter/jpeg/JpegTransform.cxx
@@ -0,0 +1,49 @@
+/* -*- 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 .
+ */
+
+
+extern "C"
+{
+    #include "jpeg.h"
+}
+
+#include "JpegTransform.hxx"
+
+JpegTransform::JpegTransform(SvStream& rInputStream, SvStream& rOutputStream) :
+    maRotate       ( 0 ),
+    mrInputStream  ( rInputStream ),
+    mrOutputStream ( rOutputStream )
+{}
+
+JpegTransform::~JpegTransform()
+{}
+
+bool JpegTransform::perform()
+{
+    long result = Transform( &mrInputStream, &mrOutputStream, maRotate );
+    return result;
+}
+
+void JpegTransform::setRotate(sal_uInt16 aRotate)
+{
+    maRotate = aRotate;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/jpeg/JpegTransform.hxx b/vcl/source/filter/jpeg/JpegTransform.hxx
new file mode 100644
index 0000000..dc71c05
--- /dev/null
+++ b/vcl/source/filter/jpeg/JpegTransform.hxx
@@ -0,0 +1,43 @@
+/* -*- 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 .
+ */
+
+#ifndef _JPEG_TRANSFROM_HXX
+#define _JPEG_TRANSFORM_HXX
+
+#include <tools/solar.h>
+#include <vcl/graph.hxx>
+
+class JpegTransform
+{
+    sal_uInt16 maRotate;
+    SvStream&  mrInputStream;
+    SvStream&  mrOutputStream;
+
+public:
+
+    JpegTransform(SvStream& rInputStream, SvStream& rOutputStream);
+    virtual ~JpegTransform();
+
+    void setRotate(sal_uInt16 aRotate);
+    bool perform();
+};
+
+#endif // _JPEG_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/jpeg/jinclude.h b/vcl/source/filter/jpeg/jinclude.h
new file mode 100644
index 0000000..121fbec
--- /dev/null
+++ b/vcl/source/filter/jpeg/jinclude.h
@@ -0,0 +1,91 @@
+/*
+ * jinclude.h
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file exists to provide a single place to fix any problems with
+ * including the wrong system include files.  (Common problems are taken
+ * care of by the standard jconfig symbols, but on really weird systems
+ * you may have to edit this file.)
+ *
+ * NOTE: this file is NOT intended to be included by applications using the
+ * JPEG library.  Most applications need only include jpeglib.h.
+ */
+
+
+/* Include auto-config file to find out which system include files we need. */
+
+#include "jconfig.h"        /* auto configuration options */
+#define JCONFIG_INCLUDED    /* so that jpeglib.h doesn't do it again */
+
+/*
+ * We need the NULL macro and size_t typedef.
+ * On an ANSI-conforming system it is sufficient to include <stddef.h>.
+ * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
+ * pull in <sys/types.h> as well.
+ * Note that the core JPEG library does not require <stdio.h>;
+ * only the default error handler and data source/destination modules do.
+ * But we must pull it in because of the references to FILE in jpeglib.h.
+ * You can remove those references if you want to compile without <stdio.h>.
+ */
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef NEED_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+
+/*
+ * We need memory copying and zeroing functions, plus strncpy().
+ * ANSI and System V implementations declare these in <string.h>.
+ * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
+ * Some systems may declare memset and memcpy in <memory.h>.
+ *
+ * NOTE: we assume the size parameters to these functions are of type size_t.
+ * Change the casts in these macros if not!
+ */
+
+#ifdef NEED_BSD_STRINGS
+
+#include <strings.h>
+#define MEMZERO(target,size)    bzero((void *)(target), (size_t)(size))
+#define MEMCOPY(dest,src,size)  bcopy((const void *)(src), (void *)(dest), (size_t)(size))
+
+#else /* not BSD, assume ANSI/SysV string lib */
+
+#include <string.h>
+#define MEMZERO(target,size)    memset((void *)(target), 0, (size_t)(size))
+#define MEMCOPY(dest,src,size)  memcpy((void *)(dest), (const void *)(src), (size_t)(size))
+
+#endif
+
+/*
+ * In ANSI C, and indeed any rational implementation, size_t is also the
+ * type returned by sizeof().  However, it seems there are some irrational
+ * implementations out there, in which sizeof() returns an int even though
+ * size_t is defined as long or unsigned long.  To ensure consistent results
+ * we always use this SIZEOF() macro in place of using sizeof() directly.
+ */
+
+#define SIZEOF(object)  ((size_t) sizeof(object))
+
+/*
+ * The modules that use fread() and fwrite() always invoke them through
+ * these macros.  On some systems you may need to twiddle the argument casts.
+ * CAUTION: argument order is different from underlying functions!
+ */
+
+#define JFREAD(file,buf,sizeofbuf)  \
+  ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
+#define JFWRITE(file,buf,sizeofbuf)  \
+  ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
diff --git a/vcl/source/filter/jpeg/jpeg.h b/vcl/source/filter/jpeg/jpeg.h
index ffb47e7..13ccf4e 100644
--- a/vcl/source/filter/jpeg/jpeg.h
+++ b/vcl/source/filter/jpeg/jpeg.h
@@ -59,6 +59,8 @@ void*   CreateBitmapFromJPEGReader( void* pJPEGReader, void* pJPEGCreateBitmapPa
    the preview size hint should be redone */
 void    SetJpegPreviewSizeHint( int nWidth, int nHeight );
 
+long    Transform( void* pInputStream, void* pOutputStream, long nAngle );
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/jpeg/jpegc.c b/vcl/source/filter/jpeg/jpegc.c
index 4803984..c05a219 100644
--- a/vcl/source/filter/jpeg/jpegc.c
+++ b/vcl/source/filter/jpeg/jpegc.c
@@ -22,9 +22,11 @@
 #include <setjmp.h>
 #include <jpeglib.h>
 #include <jerror.h>
+
 #include <rtl/alloc.h>
 #include <osl/diagnose.h>
 
+#include "transupp.h"
 #include "jpeg.h"
 
 struct ErrorManagerStruct
@@ -43,7 +45,6 @@ METHODDEF( void ) errorExit (j_common_ptr cinfo)
     longjmp(error->setjmp_buffer, 1);
 }
 
-
 METHODDEF( void ) outputMessage (j_common_ptr cinfo)
 {
     char buffer[JMSG_LENGTH_MAX];
@@ -86,13 +87,13 @@ void ReadJPEG( void* pJPEGReader, void* pInputStream, long* pLines )
 
     jpeg_create_decompress( &cinfo );
     jpeg_svstream_src( &cinfo, pInputStream );
-    jpeg_read_header( &cinfo, sal_True );
+    jpeg_read_header( &cinfo, TRUE );
 
     cinfo.scale_num = 1;
     cinfo.scale_denom = 1;
     cinfo.output_gamma = 1.0;
-    cinfo.raw_data_out = sal_False;
-    cinfo.quantize_colors = sal_False;
+    cinfo.raw_data_out = FALSE;
+    cinfo.quantize_colors = FALSE;
     if ( cinfo.jpeg_color_space == JCS_YCbCr )
         cinfo.out_color_space = JCS_RGB;
     else if ( cinfo.jpeg_color_space == JCS_YCCK )
@@ -131,8 +132,8 @@ void ReadJPEG( void* pJPEGReader, void* pInputStream, long* pLines )
         if( cinfo.scale_denom > 1 )
         {
             cinfo.dct_method            = JDCT_FASTEST;
-            cinfo.do_fancy_upsampling   = sal_False;
-            cinfo.do_block_smoothing    = sal_False;
+            cinfo.do_fancy_upsampling   = FALSE;
+            cinfo.do_block_smoothing    = FALSE;
         }
     }
 
@@ -221,7 +222,8 @@ void ReadJPEG( void* pJPEGReader, void* pInputStream, long* pLines )
 
 long WriteJPEG( void* pJPEGWriter, void* pOutputStream,
                 long nWidth, long nHeight, long bGreys,
-                long nQualityPercent, long aChromaSubsampling, void* pCallbackData )
+                long nQualityPercent, long aChromaSubsampling,
+                void* pCallbackData )
 {
     struct jpeg_compress_struct cinfo;
     struct ErrorManagerStruct   jerr;
@@ -255,7 +257,7 @@ long WriteJPEG( void* pJPEGWriter, void* pOutputStream,
     }
 
     jpeg_set_defaults( &cinfo );
-    jpeg_set_quality( &cinfo, (int) nQualityPercent, sal_False );
+    jpeg_set_quality( &cinfo, (int) nQualityPercent, FALSE );
 
     if ( ( nWidth > 128 ) || ( nHeight > 128 ) )
         jpeg_simple_progression( &cinfo );
@@ -276,7 +278,7 @@ long WriteJPEG( void* pJPEGWriter, void* pOutputStream,
         cinfo.comp_info[0].v_samp_factor = 2;
     }
 
-    jpeg_start_compress( &cinfo, sal_True );
+    jpeg_start_compress( &cinfo, TRUE );
 
     for( nY = 0; nY < nHeight; nY++ )
     {
@@ -300,4 +302,88 @@ long WriteJPEG( void* pJPEGWriter, void* pOutputStream,
     return 1;
 }
 
+long Transform(void* pInputStream, void* pOutputStream, long nAngle)
+{
+    jpeg_transform_info aTransformOption;
+    JCOPY_OPTION        aCopyOption = JCOPYOPT_ALL;
+
+    struct jpeg_decompress_struct   aSourceInfo;
+    struct jpeg_compress_struct     aDestinationInfo;
+    struct ErrorManagerStruct       aSourceError;
+    struct ErrorManagerStruct       aDestinationError;
+
+    jvirt_barray_ptr* aSourceCoefArrays      = 0;
+    jvirt_barray_ptr* aDestinationCoefArrays = 0;
+
+    aTransformOption.force_grayscale = FALSE;
+    aTransformOption.trim            = FALSE;
+    aTransformOption.perfect         = FALSE;
+    aTransformOption.crop            = FALSE;
+
+    // Angle to transform option
+    // 90 Clockwise = 270 Counterclockwise
+    switch (nAngle)
+    {
+        case 2700:
+            aTransformOption.transform  = JXFORM_ROT_90;
+            break;
+        case 1800:
+            aTransformOption.transform  = JXFORM_ROT_180;
+            break;
+        case 900:
+            aTransformOption.transform  = JXFORM_ROT_270;
+            break;
+        default:
+            aTransformOption.transform  = JXFORM_NONE;
+    }
+
+    // Decompression
+    aSourceInfo.err                 = jpeg_std_error(&aSourceError.pub);
+    aSourceInfo.err->error_exit     = errorExit;
+    aSourceInfo.err->output_message = outputMessage;
+
+    // Compression
+    aDestinationInfo.err                 = jpeg_std_error(&aDestinationError.pub);
+    aDestinationInfo.err->error_exit     = errorExit;
+    aDestinationInfo.err->output_message = outputMessage;
+
+    aDestinationInfo.optimize_coding = TRUE;
+
+    if (setjmp(aSourceError.setjmp_buffer) || setjmp(aDestinationError.setjmp_buffer))
+    {
+        jpeg_destroy_decompress(&aSourceInfo);
+        jpeg_destroy_compress(&aDestinationInfo);
+        return 0;
+    }
+
+    jpeg_create_decompress(&aSourceInfo);
+    jpeg_create_compress(&aDestinationInfo);
+
+    jpeg_svstream_src (&aSourceInfo, pInputStream);
+
+    jcopy_markers_setup(&aSourceInfo, aCopyOption);
+    jpeg_read_header(&aSourceInfo, 1);
+    jtransform_request_workspace(&aSourceInfo, &aTransformOption);
+
+    aSourceCoefArrays = jpeg_read_coefficients(&aSourceInfo);
+    jpeg_copy_critical_parameters(&aSourceInfo, &aDestinationInfo);
+
+    aDestinationCoefArrays = jtransform_adjust_parameters(&aSourceInfo, &aDestinationInfo, aSourceCoefArrays, &aTransformOption);
+    jpeg_svstream_dest (&aDestinationInfo, pOutputStream);
+
+    // Compute optimal Huffman coding tables instead of precomuted tables
+    aDestinationInfo.optimize_coding = 1;
+    jpeg_write_coefficients(&aDestinationInfo, aDestinationCoefArrays);
+    jcopy_markers_execute(&aSourceInfo, &aDestinationInfo, aCopyOption);
+    jtransform_execute_transformation(&aSourceInfo, &aDestinationInfo, aSourceCoefArrays, &aTransformOption);
+
+    jpeg_finish_compress(&aDestinationInfo);
+    jpeg_destroy_compress(&aDestinationInfo);
+
+    jpeg_finish_decompress(&aSourceInfo);
+    jpeg_destroy_decompress(&aSourceInfo);
+
+    return 1;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/jpeg/jpegcomp.h b/vcl/source/filter/jpeg/jpegcomp.h
new file mode 100644
index 0000000..ed9eeab
--- /dev/null
+++ b/vcl/source/filter/jpeg/jpegcomp.h
@@ -0,0 +1,30 @@
+/*
+ * jpegcomp.h
+ *
+ * Copyright (C) 2010, D. R. Commander
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * JPEG compatibility macros
+ * These declarations are considered internal to the JPEG library; most
+ * applications using the library shouldn't need to include this file.
+ */
+
+#if JPEG_LIB_VERSION >= 70
+#define _DCT_scaled_size DCT_h_scaled_size
+#define _DCT_h_scaled_size DCT_h_scaled_size
+#define _DCT_v_scaled_size DCT_v_scaled_size
+#define _min_DCT_scaled_size min_DCT_h_scaled_size
+#define _min_DCT_h_scaled_size min_DCT_h_scaled_size
+#define _min_DCT_v_scaled_size min_DCT_v_scaled_size
+#define _jpeg_width jpeg_width
+#define _jpeg_height jpeg_height
+#else
+#define _DCT_scaled_size DCT_scaled_size
+#define _DCT_h_scaled_size DCT_scaled_size
+#define _DCT_v_scaled_size DCT_scaled_size
+#define _min_DCT_scaled_size min_DCT_scaled_size
+#define _min_DCT_h_scaled_size min_DCT_scaled_size
+#define _min_DCT_v_scaled_size min_DCT_scaled_size
+#define _jpeg_width image_width
+#define _jpeg_height image_height
+#endif
diff --git a/vcl/source/filter/jpeg/transupp.c b/vcl/source/filter/jpeg/transupp.c
new file mode 100644
index 0000000..24b7667
--- /dev/null
+++ b/vcl/source/filter/jpeg/transupp.c
@@ -0,0 +1,1628 @@
+/*
+ * transupp.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
+ * Modifications:
+ * Copyright (C) 2010, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains image transformation routines and other utility code
+ * used by the jpegtran sample application.  These are NOT part of the core
+ * JPEG library.  But we keep these routines separate from jpegtran.c to
+ * ease the task of maintaining jpegtran-like programs that have other user
+ * interfaces.
+ */
+
+/* Although this file really shouldn't have access to the library internals,
+ * it's helpful to let it call jround_up() and jcopy_block_row().
+ */
+#define JPEG_INTERNALS
+
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "transupp.h"       /* My own external interface */
+#include "jpegcomp.h"
+#include <ctype.h>      /* to declare isdigit() */
+
+
+#if JPEG_LIB_VERSION >= 70
+#define dstinfo_min_DCT_h_scaled_size dstinfo->min_DCT_h_scaled_size
+#define dstinfo_min_DCT_v_scaled_size dstinfo->min_DCT_v_scaled_size
+#else
+#define dstinfo_min_DCT_h_scaled_size DCTSIZE
+#define dstinfo_min_DCT_v_scaled_size DCTSIZE
+#endif
+
+
+#if TRANSFORMS_SUPPORTED
+
+/*
+ * Lossless image transformation routines.  These routines work on DCT
+ * coefficient arrays and thus do not require any lossy decompression
+ * or recompression of the image.
+ * Thanks to Guido Vollbeding for the initial design and code of this feature,
+ * and to Ben Jackson for introducing the cropping feature.
+ *
+ * Horizontal flipping is done in-place, using a single top-to-bottom
+ * pass through the virtual source array.  It will thus be much the
+ * fastest option for images larger than main memory.
+ *
+ * The other routines require a set of destination virtual arrays, so they
+ * need twice as much memory as jpegtran normally does.  The destination
+ * arrays are always written in normal scan order (top to bottom) because
+ * the virtual array manager expects this.  The source arrays will be scanned
+ * in the corresponding order, which means multiple passes through the source
+ * arrays for most of the transforms.  That could result in much thrashing
+ * if the image is larger than main memory.
+ *
+ * If cropping or trimming is involved, the destination arrays may be smaller
+ * than the source arrays.  Note it is not possible to do horizontal flip
+ * in-place when a nonzero Y crop offset is specified, since we'd have to move
+ * data from one block row to another but the virtual array manager doesn't
+ * guarantee we can touch more than one row at a time.  So in that case,
+ * we have to use a separate destination array.
+ *
+ * Some notes about the operating environment of the individual transform
+ * routines:
+ * 1. Both the source and destination virtual arrays are allocated from the
+ *    source JPEG object, and therefore should be manipulated by calling the
+ *    source's memory manager.
+ * 2. The destination's component count should be used.  It may be smaller
+ *    than the source's when forcing to grayscale.
+ * 3. Likewise the destination's sampling factors should be used.  When
+ *    forcing to grayscale the destination's sampling factors will be all 1,
+ *    and we may as well take that as the effective iMCU size.
+ * 4. When "trim" is in effect, the destination's dimensions will be the
+ *    trimmed values but the source's will be untrimmed.
+ * 5. When "crop" is in effect, the destination's dimensions will be the
+ *    cropped values but the source's will be uncropped.  Each transform
+ *    routine is responsible for picking up source data starting at the
+ *    correct X and Y offset for the crop region.  (The X and Y offsets
+ *    passed to the transform routines are measured in iMCU blocks of the
+ *    destination.)
+ * 6. All the routines assume that the source and destination buffers are
+ *    padded out to a full iMCU boundary.  This is true, although for the
+ *    source buffer it is an undocumented property of jdcoefct.c.
+ */
+
+
+LOCAL(void)
+do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+     JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+     jvirt_barray_ptr *src_coef_arrays,
+     jvirt_barray_ptr *dst_coef_arrays)
+/* Crop.  This is only used when no rotate/flip is requested with the crop. */
+{
+  JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
+  int ci, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  jpeg_component_info *compptr;
+
+  /* We simply have to copy the right amount of data (the destination's
+   * image size) starting at the given X and Y offsets in the source.
+   */
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+     dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+     (JDIMENSION) compptr->v_samp_factor, TRUE);
+      src_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+     dst_blk_y + y_crop_blocks,
+     (JDIMENSION) compptr->v_samp_factor, FALSE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+    jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
+            dst_buffer[offset_y],
+            compptr->width_in_blocks);
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+           JDIMENSION x_crop_offset,
+           jvirt_barray_ptr *src_coef_arrays)
+/* Horizontal flip; done in-place, so no separate dest array is required.
+ * NB: this only works when y_crop_offset is zero.
+ */
+{
+  JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
+  int ci, k, offset_y;
+  JBLOCKARRAY buffer;
+  JCOEFPTR ptr1, ptr2;
+  JCOEF temp1, temp2;
+  jpeg_component_info *compptr;
+
+  /* Horizontal mirroring of DCT blocks is accomplished by swapping
+   * pairs of blocks in-place.  Within a DCT block, we perform horizontal
+   * mirroring by changing the signs of odd-numbered columns.
+   * Partial iMCUs at the right edge are left untouched.
+   */
+  MCU_cols = srcinfo->output_width /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    for (blk_y = 0; blk_y < compptr->height_in_blocks;
+     blk_y += compptr->v_samp_factor) {
+      buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
+     (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+    /* Do the mirroring */
+    for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
+      ptr1 = buffer[offset_y][blk_x];
+      ptr2 = buffer[offset_y][comp_width - blk_x - 1];
+      /* this unrolled loop doesn't need to know which row it's on... */
+      for (k = 0; k < DCTSIZE2; k += 2) {
+        temp1 = *ptr1;  /* swap even column */
+        temp2 = *ptr2;
+        *ptr1++ = temp2;
+        *ptr2++ = temp1;
+        temp1 = *ptr1;  /* swap odd column with sign change */
+        temp2 = *ptr2;
+        *ptr1++ = -temp2;
+        *ptr2++ = -temp1;
+      }
+    }
+    if (x_crop_blocks > 0) {
+      /* Now left-justify the portion of the data to be kept.
+       * We can't use a single jcopy_block_row() call because that routine
+       * depends on memcpy(), whose behavior is unspecified for overlapping
+       * source and destination areas.  Sigh.
+       */
+      for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
+        jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
+                buffer[offset_y] + blk_x,
+                (JDIMENSION) 1);
+      }
+    }
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+       JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+       jvirt_barray_ptr *src_coef_arrays,
+       jvirt_barray_ptr *dst_coef_arrays)
+/* Horizontal flip in general cropping case */
+{
+  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
+  int ci, k, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JBLOCKROW src_row_ptr, dst_row_ptr;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Here we must output into a separate array because we can't touch
+   * different rows of a single virtual array simultaneously.  Otherwise,
+   * this is essentially the same as the routine above.
+   */
+  MCU_cols = srcinfo->output_width /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+     dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+     (JDIMENSION) compptr->v_samp_factor, TRUE);
+      src_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+     dst_blk_y + y_crop_blocks,
+     (JDIMENSION) compptr->v_samp_factor, FALSE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+    dst_row_ptr = dst_buffer[offset_y];
+    src_row_ptr = src_buffer[offset_y];
+    for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+      if (x_crop_blocks + dst_blk_x < comp_width) {
+        /* Do the mirrorable blocks */
+        dst_ptr = dst_row_ptr[dst_blk_x];
+        src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+        /* this unrolled loop doesn't need to know which row it's on... */
+        for (k = 0; k < DCTSIZE2; k += 2) {
+          *dst_ptr++ = *src_ptr++;   /* copy even column */
+          *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
+        }
+      } else {
+        /* Copy last partial block(s) verbatim */
+        jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
+                dst_row_ptr + dst_blk_x,
+                (JDIMENSION) 1);
+      }
+    }
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+       JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+       jvirt_barray_ptr *src_coef_arrays,
+       jvirt_barray_ptr *dst_coef_arrays)
+/* Vertical flip */
+{
+  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
+  int ci, i, j, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JBLOCKROW src_row_ptr, dst_row_ptr;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* We output into a separate array because we can't touch different
+   * rows of the source virtual array simultaneously.  Otherwise, this
+   * is a pretty straightforward analog of horizontal flip.
+   * Within a DCT block, vertical mirroring is done by changing the signs
+   * of odd-numbered rows.
+   * Partial iMCUs at the bottom edge are copied verbatim.
+   */
+  MCU_rows = srcinfo->output_height /
+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_height = MCU_rows * compptr->v_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+     dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+     (JDIMENSION) compptr->v_samp_factor, TRUE);
+      if (y_crop_blocks + dst_blk_y < comp_height) {
+    /* Row is within the mirrorable area. */
+    src_buffer = (*srcinfo->mem->access_virt_barray)
+      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+       comp_height - y_crop_blocks - dst_blk_y -
+       (JDIMENSION) compptr->v_samp_factor,
+       (JDIMENSION) compptr->v_samp_factor, FALSE);
+      } else {
+    /* Bottom-edge blocks will be copied verbatim. */
+    src_buffer = (*srcinfo->mem->access_virt_barray)
+      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+       dst_blk_y + y_crop_blocks,
+       (JDIMENSION) compptr->v_samp_factor, FALSE);
+      }
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+    if (y_crop_blocks + dst_blk_y < comp_height) {
+      /* Row is within the mirrorable area. */
+      dst_row_ptr = dst_buffer[offset_y];
+      src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
+      src_row_ptr += x_crop_blocks;
+      for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+           dst_blk_x++) {
+        dst_ptr = dst_row_ptr[dst_blk_x];
+        src_ptr = src_row_ptr[dst_blk_x];
+        for (i = 0; i < DCTSIZE; i += 2) {
+          /* copy even row */
+          for (j = 0; j < DCTSIZE; j++)
+        *dst_ptr++ = *src_ptr++;
+          /* copy odd row with sign change */
+          for (j = 0; j < DCTSIZE; j++)
+        *dst_ptr++ = - *src_ptr++;
+        }
+      }
+    } else {
+      /* Just copy row verbatim. */
+      jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
+              dst_buffer[offset_y],
+              compptr->width_in_blocks);
+    }
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+          JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+          jvirt_barray_ptr *src_coef_arrays,
+          jvirt_barray_ptr *dst_coef_arrays)
+/* Transpose source into destination */
+{
+  JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
+  int ci, i, j, offset_x, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Transposing pixels within a block just requires transposing the
+   * DCT coefficients.
+   * Partial iMCUs at the edges require no special treatment; we simply
+   * process all the available DCT blocks for every component.
+   */
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+     dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+     (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+    for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+         dst_blk_x += compptr->h_samp_factor) {
+      src_buffer = (*srcinfo->mem->access_virt_barray)
+        ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+         dst_blk_x + x_crop_blocks,
+         (JDIMENSION) compptr->h_samp_factor, FALSE);
+      for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+        dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+        src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
+        for (i = 0; i < DCTSIZE; i++)
+          for (j = 0; j < DCTSIZE; j++)
+        dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+      }
+    }
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+       JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+       jvirt_barray_ptr *src_coef_arrays,
+       jvirt_barray_ptr *dst_coef_arrays)
+/* 90 degree rotation is equivalent to
+ *   1. Transposing the image;
+ *   2. Horizontal mirroring.
+ * These two steps are merged into a single processing routine.
+ */
+{
+  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
+  int ci, i, j, offset_x, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Because of the horizontal mirror step, we can't process partial iMCUs
+   * at the (output) right edge properly.  They just get transposed and
+   * not mirrored.
+   */
+  MCU_cols = srcinfo->output_height /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+     dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+     (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+    for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+         dst_blk_x += compptr->h_samp_factor) {
+      if (x_crop_blocks + dst_blk_x < comp_width) {
+        /* Block is within the mirrorable area. */
+        src_buffer = (*srcinfo->mem->access_virt_barray)
+          ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+           comp_width - x_crop_blocks - dst_blk_x -
+           (JDIMENSION) compptr->h_samp_factor,
+           (JDIMENSION) compptr->h_samp_factor, FALSE);
+      } else {
+        /* Edge blocks are transposed but not mirrored. */
+        src_buffer = (*srcinfo->mem->access_virt_barray)
+          ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+           dst_blk_x + x_crop_blocks,
+           (JDIMENSION) compptr->h_samp_factor, FALSE);
+      }
+      for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+        dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+        if (x_crop_blocks + dst_blk_x < comp_width) {
+          /* Block is within the mirrorable area. */
+          src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
+        [dst_blk_y + offset_y + y_crop_blocks];
+          for (i = 0; i < DCTSIZE; i++) {
+        for (j = 0; j < DCTSIZE; j++)
+          dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+        i++;
+        for (j = 0; j < DCTSIZE; j++)
+          dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+          }
+        } else {
+          /* Edge blocks are transposed but not mirrored. */
+          src_ptr = src_buffer[offset_x]
+        [dst_blk_y + offset_y + y_crop_blocks];
+          for (i = 0; i < DCTSIZE; i++)
+        for (j = 0; j < DCTSIZE; j++)
+          dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+        }
+      }
+    }
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+        JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+        jvirt_barray_ptr *src_coef_arrays,
+        jvirt_barray_ptr *dst_coef_arrays)
+/* 270 degree rotation is equivalent to
+ *   1. Horizontal mirroring;
+ *   2. Transposing the image.
+ * These two steps are merged into a single processing routine.
+ */
+{
+  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
+  int ci, i, j, offset_x, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Because of the horizontal mirror step, we can't process partial iMCUs
+   * at the (output) bottom edge properly.  They just get transposed and
+   * not mirrored.
+   */
+  MCU_rows = srcinfo->output_width /
+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_height = MCU_rows * compptr->v_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+     dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+    ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+     (JDIMENSION) compptr->v_samp_factor, TRUE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+    for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+         dst_blk_x += compptr->h_samp_factor) {
+      src_buffer = (*srcinfo->mem->access_virt_barray)
+        ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+         dst_blk_x + x_crop_blocks,
+         (JDIMENSION) compptr->h_samp_factor, FALSE);
+      for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+        dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+        if (y_crop_blocks + dst_blk_y < comp_height) {
+          /* Block is within the mirrorable area. */
+          src_ptr = src_buffer[offset_x]
+        [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
+          for (i = 0; i < DCTSIZE; i++) {
+        for (j = 0; j < DCTSIZE; j++) {
+          dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+          j++;
+          dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+        }
+          }
+        } else {
+          /* Edge blocks are transposed but not mirrored. */
+          src_ptr = src_buffer[offset_x]
+        [dst_blk_y + offset_y + y_crop_blocks];
+          for (i = 0; i < DCTSIZE; i++)
+        for (j = 0; j < DCTSIZE; j++)
+          dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+        }
+      }
+    }
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+        JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+        jvirt_barray_ptr *src_coef_arrays,
+        jvirt_barray_ptr *dst_coef_arrays)
+/* 180 degree rotation is equivalent to
+ *   1. Vertical mirroring;
+ *   2. Horizontal mirroring.
+ * These two steps are merged into a single processing routine.
+ */
+{
+  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
+  int ci, i, j, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list