Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <vcl/GraphicNativeTransform.hxx>
21 :
22 : #include <vcl/gfxlink.hxx>
23 : #include <vcl/graphicfilter.hxx>
24 : #include <com/sun/star/uno/Sequence.hxx>
25 : #include <com/sun/star/beans/XPropertySet.hpp>
26 :
27 :
28 : #include "jpeg/Exif.hxx"
29 : #include "jpeg/JpegTransform.hxx"
30 :
31 0 : GraphicNativeTransform::GraphicNativeTransform(Graphic& rGraphic) :
32 0 : mrGraphic(rGraphic)
33 0 : {}
34 :
35 0 : GraphicNativeTransform::~GraphicNativeTransform()
36 0 : {}
37 :
38 0 : bool GraphicNativeTransform::canBeRotated()
39 : {
40 0 : GfxLink aLink = mrGraphic.GetLink();
41 :
42 : // Don't allow rotation on animations for now
43 0 : if (mrGraphic.IsAnimated())
44 : {
45 0 : return false;
46 : }
47 :
48 0 : if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_JPG
49 0 : || aLink.GetType() == GFX_LINK_TYPE_NATIVE_PNG
50 0 : || aLink.GetType() == GFX_LINK_TYPE_NATIVE_GIF
51 0 : || aLink.GetType() == GFX_LINK_TYPE_NONE)
52 : {
53 0 : return true;
54 : }
55 :
56 0 : return false;
57 : }
58 :
59 0 : bool GraphicNativeTransform::rotate(sal_uInt16 aInputRotation)
60 : {
61 : // Rotation can be between 0 and 3600
62 0 : sal_uInt16 aRotation = aInputRotation % 3600;
63 :
64 0 : if (aRotation == 0)
65 : {
66 0 : return true; // No rotation is needed
67 : }
68 0 : else if (aRotation != 900 && aRotation != 1800 && aRotation != 2700)
69 : {
70 0 : return false;
71 : }
72 :
73 0 : GfxLink aLink = mrGraphic.GetLink();
74 0 : if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_JPG )
75 : {
76 0 : return rotateJPEG(aRotation);
77 : }
78 0 : else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_PNG )
79 : {
80 0 : return rotateGeneric(aRotation, OUString("png"));
81 : }
82 0 : else if ( aLink.GetType() == GFX_LINK_TYPE_NATIVE_GIF )
83 : {
84 0 : return rotateGeneric(aRotation, OUString("gif"));
85 : }
86 0 : else if ( aLink.GetType() == GFX_LINK_TYPE_NONE )
87 : {
88 0 : return rotateBitmapOnly(aRotation);
89 : }
90 0 : return false;
91 : }
92 :
93 0 : bool GraphicNativeTransform::rotateBitmapOnly(sal_uInt16 aRotation)
94 : {
95 0 : if (mrGraphic.IsAnimated())
96 : {
97 0 : return false;
98 : }
99 :
100 0 : BitmapEx aBitmap = mrGraphic.GetBitmapEx();
101 0 : aBitmap.Rotate(aRotation, COL_BLACK);
102 0 : mrGraphic = aBitmap;
103 :
104 0 : return true;
105 : }
106 :
107 0 : bool GraphicNativeTransform::rotateGeneric(sal_uInt16 aRotation, OUString aType)
108 : {
109 : // Can't rotate animations yet
110 0 : if (mrGraphic.IsAnimated())
111 : {
112 0 : return false;
113 : }
114 :
115 0 : SvMemoryStream aStream;
116 :
117 0 : GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
118 :
119 0 : css::uno::Sequence< css::beans::PropertyValue > aFilterData( 3 );
120 0 : aFilterData[ 0 ].Name = "Interlaced";
121 0 : aFilterData[ 0 ].Value <<= (sal_Int32) 0;
122 0 : aFilterData[ 1 ].Name = "Compression";
123 0 : aFilterData[ 1 ].Value <<= (sal_Int32) 9;
124 0 : aFilterData[ 2 ].Name = "Quality";
125 0 : aFilterData[ 2 ].Value <<= (sal_Int32) 90;
126 :
127 0 : sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( aType );
128 :
129 0 : BitmapEx aBitmap = mrGraphic.GetBitmapEx();
130 0 : aBitmap.Rotate(aRotation, COL_BLACK);
131 0 : rFilter.ExportGraphic( aBitmap, OUString( "none" ), aStream, nFilterFormat, &aFilterData );
132 :
133 0 : aStream.Seek( STREAM_SEEK_TO_BEGIN );
134 :
135 0 : Graphic aGraphic;
136 0 : rFilter.ImportGraphic( aGraphic, OUString("import"), aStream );
137 :
138 0 : mrGraphic = aGraphic;
139 0 : return true;
140 : }
141 :
142 0 : bool GraphicNativeTransform::rotateJPEG(sal_uInt16 aRotation)
143 : {
144 0 : GfxLink aLink = mrGraphic.GetLink();
145 :
146 0 : SvMemoryStream aSourceStream;
147 0 : aSourceStream.Write(aLink.GetData(), aLink.GetDataSize());
148 0 : aSourceStream.Seek( STREAM_SEEK_TO_BEGIN );
149 :
150 0 : Orientation aOrientation = TOP_LEFT;
151 :
152 0 : Exif exif;
153 0 : if ( exif.read(aSourceStream) )
154 : {
155 0 : aOrientation = exif.getOrientation();
156 : }
157 :
158 0 : SvMemoryStream aTargetStream;
159 0 : JpegTransform tranform(aSourceStream, aTargetStream);
160 0 : tranform.setRotate(aRotation);
161 0 : tranform.perform();
162 :
163 0 : aTargetStream.Seek( STREAM_SEEK_TO_BEGIN );
164 :
165 : // Reset orientation in exif if needed
166 0 : if ( exif.hasExif() && aOrientation != TOP_LEFT)
167 : {
168 0 : exif.setOrientation(TOP_LEFT);
169 0 : exif.write(aTargetStream);
170 : }
171 :
172 0 : aTargetStream.Seek( STREAM_SEEK_TO_END );
173 0 : sal_uInt32 aBufferSize = aTargetStream.Tell();
174 0 : sal_uInt8* pBuffer = new sal_uInt8[ aBufferSize ];
175 :
176 0 : aTargetStream.Seek( STREAM_SEEK_TO_BEGIN );
177 0 : aTargetStream.Read( pBuffer, aBufferSize );
178 :
179 0 : BitmapEx aBitmap = mrGraphic.GetBitmapEx();
180 0 : aBitmap.Rotate(aRotation, COL_BLACK);
181 0 : mrGraphic = aBitmap;
182 0 : mrGraphic.SetLink( GfxLink( pBuffer, aBufferSize, aLink.GetType(), sal_True ) );
183 :
184 0 : return true;
185 465 : }
186 :
187 :
188 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|