1 : /* vim:set sw=4 sts=4 et cin: */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org widget code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Christian Biesinger <cbiesinger@web.de>.
19 : * Portions created by the Initial Developer are Copyright (C) 2006
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include <gdk-pixbuf/gdk-pixbuf.h>
39 :
40 : #include "gfxASurface.h"
41 : #include "gfxImageSurface.h"
42 : #include "gfxContext.h"
43 :
44 : #include "imgIContainer.h"
45 :
46 : #include "nsAutoPtr.h"
47 :
48 : #include "nsImageToPixbuf.h"
49 :
50 0 : NS_IMPL_ISUPPORTS1(nsImageToPixbuf, nsIImageToPixbuf)
51 :
52 : inline unsigned char
53 0 : unpremultiply (unsigned char color,
54 : unsigned char alpha)
55 : {
56 0 : if (alpha == 0)
57 0 : return 0;
58 : // plus alpha/2 to round instead of truncate
59 0 : return (color * 255 + alpha / 2) / alpha;
60 : }
61 :
62 : NS_IMETHODIMP_(GdkPixbuf*)
63 0 : nsImageToPixbuf::ConvertImageToPixbuf(imgIContainer* aImage)
64 : {
65 0 : return ImageToPixbuf(aImage);
66 : }
67 :
68 : GdkPixbuf*
69 0 : nsImageToPixbuf::ImageToPixbuf(imgIContainer* aImage)
70 : {
71 0 : nsRefPtr<gfxImageSurface> frame;
72 : nsresult rv = aImage->CopyFrame(imgIContainer::FRAME_CURRENT,
73 : imgIContainer::FLAG_SYNC_DECODE,
74 0 : getter_AddRefs(frame));
75 :
76 : // If the last call failed, it was probably because our call stack originates
77 : // in an imgIDecoderObserver event, meaning that we're not allowed request
78 : // a sync decode. Presumably the originating event is something sensible like
79 : // OnStopFrame(), so we can just retry the call without a sync decode.
80 0 : if (NS_FAILED(rv))
81 : aImage->CopyFrame(imgIContainer::FRAME_CURRENT,
82 : imgIContainer::FLAG_NONE,
83 0 : getter_AddRefs(frame));
84 :
85 0 : if (!frame)
86 0 : return nsnull;
87 :
88 0 : return ImgSurfaceToPixbuf(frame, frame->Width(), frame->Height());
89 : }
90 :
91 : GdkPixbuf*
92 0 : nsImageToPixbuf::ImgSurfaceToPixbuf(gfxImageSurface* aImgSurface, PRInt32 aWidth, PRInt32 aHeight)
93 : {
94 : GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
95 0 : aWidth, aHeight);
96 0 : if (!pixbuf)
97 0 : return nsnull;
98 :
99 0 : PRUint32 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
100 0 : guchar* pixels = gdk_pixbuf_get_pixels (pixbuf);
101 :
102 0 : long cairoStride = aImgSurface->Stride();
103 0 : unsigned char* cairoData = aImgSurface->Data();
104 :
105 0 : gfxASurface::gfxImageFormat format = aImgSurface->Format();
106 :
107 0 : for (PRInt32 row = 0; row < aHeight; ++row) {
108 0 : for (PRInt32 col = 0; col < aWidth; ++col) {
109 0 : guchar* pixel = pixels + row * rowstride + 4 * col;
110 :
111 : PRUint32* cairoPixel = reinterpret_cast<PRUint32*>
112 0 : ((cairoData + row * cairoStride + 4 * col));
113 :
114 0 : if (format == gfxASurface::ImageFormatARGB32) {
115 0 : const PRUint8 a = (*cairoPixel >> 24) & 0xFF;
116 0 : const PRUint8 r = unpremultiply((*cairoPixel >> 16) & 0xFF, a);
117 0 : const PRUint8 g = unpremultiply((*cairoPixel >> 8) & 0xFF, a);
118 0 : const PRUint8 b = unpremultiply((*cairoPixel >> 0) & 0xFF, a);
119 :
120 0 : *pixel++ = r;
121 0 : *pixel++ = g;
122 0 : *pixel++ = b;
123 0 : *pixel++ = a;
124 : } else {
125 0 : NS_ASSERTION(format == gfxASurface::ImageFormatRGB24,
126 : "unexpected format");
127 0 : const PRUint8 r = (*cairoPixel >> 16) & 0xFF;
128 0 : const PRUint8 g = (*cairoPixel >> 8) & 0xFF;
129 0 : const PRUint8 b = (*cairoPixel >> 0) & 0xFF;
130 :
131 0 : *pixel++ = r;
132 0 : *pixel++ = g;
133 0 : *pixel++ = b;
134 0 : *pixel++ = 0xFF; // A
135 : }
136 : }
137 : }
138 :
139 0 : return pixbuf;
140 : }
141 :
142 : GdkPixbuf*
143 0 : nsImageToPixbuf::SurfaceToPixbuf(gfxASurface* aSurface, PRInt32 aWidth, PRInt32 aHeight)
144 : {
145 0 : if (aSurface->CairoStatus()) {
146 0 : NS_ERROR("invalid surface");
147 0 : return nsnull;
148 : }
149 :
150 0 : nsRefPtr<gfxImageSurface> imgSurface;
151 0 : if (aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
152 : imgSurface = static_cast<gfxImageSurface*>
153 0 : (static_cast<gfxASurface*>(aSurface));
154 : } else {
155 : imgSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
156 0 : gfxImageSurface::ImageFormatARGB32);
157 :
158 0 : if (!imgSurface)
159 0 : return nsnull;
160 :
161 0 : nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
162 0 : if (!context)
163 0 : return nsnull;
164 :
165 0 : context->SetOperator(gfxContext::OPERATOR_SOURCE);
166 0 : context->SetSource(aSurface);
167 0 : context->Paint();
168 : }
169 :
170 0 : return ImgSurfaceToPixbuf(imgSurface, aWidth, aHeight);
171 : }
|