1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
23 * Justin Dolske <dolske@mozilla.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
42 #include "ImageErrors.h"
43 #include "imgIContainer.h"
45 #include "imgIDecoder.h"
46 #include "imgIEncoder.h"
47 #include "imgIDecoderObserver.h"
48 #include "imgIContainerObserver.h"
50 #include "gfxIImageFrame.h"
51 #include "gfxImageSurface.h"
52 #include "gfxContext.h"
53 #include "nsStringStream.h"
54 #include "nsComponentManagerUtils.h"
55 #include "nsWeakReference.h"
56 #include "nsIInterfaceRequestorUtils.h"
59 /* ========== Utility classes ========== */
62 class HelperLoader
: public imgILoad
,
63 public imgIDecoderObserver
,
64 public nsSupportsWeakReference
69 NS_DECL_IMGIDECODEROBSERVER
70 NS_DECL_IMGICONTAINEROBSERVER
74 nsCOMPtr
<imgIContainer
> mContainer
;
77 NS_IMPL_ISUPPORTS4 (HelperLoader
, imgILoad
, imgIDecoderObserver
, imgIContainerObserver
, nsISupportsWeakReference
)
79 HelperLoader::HelperLoader (void)
83 /* Implement imgILoad::image getter */
85 HelperLoader::GetImage(imgIContainer
**aImage
)
88 NS_IF_ADDREF (*aImage
);
92 /* Implement imgILoad::image setter */
94 HelperLoader::SetImage(imgIContainer
*aImage
)
100 /* Implement imgILoad::isMultiPartChannel getter */
102 HelperLoader::GetIsMultiPartChannel(PRBool
*aIsMultiPartChannel
)
104 *aIsMultiPartChannel
= PR_FALSE
;
108 /* Implement imgIDecoderObserver::onStartRequest() */
110 HelperLoader::OnStartRequest(imgIRequest
*aRequest
)
115 /* Implement imgIDecoderObserver::onStartDecode() */
117 HelperLoader::OnStartDecode(imgIRequest
*aRequest
)
122 /* Implement imgIDecoderObserver::onStartContainer() */
124 HelperLoader::OnStartContainer(imgIRequest
*aRequest
, imgIContainer
130 /* Implement imgIDecoderObserver::onStartFrame() */
132 HelperLoader::OnStartFrame(imgIRequest
*aRequest
, gfxIImageFrame
*aFrame
)
137 /* Implement imgIDecoderObserver::onDataAvailable() */
139 HelperLoader::OnDataAvailable(imgIRequest
*aRequest
, gfxIImageFrame
140 *aFrame
, const nsIntRect
* aRect
)
145 /* Implement imgIDecoderObserver::onStopFrame() */
147 HelperLoader::OnStopFrame(imgIRequest
*aRequest
, gfxIImageFrame
*aFrame
)
152 /* Implement imgIDecoderObserver::onStopContainer() */
154 HelperLoader::OnStopContainer(imgIRequest
*aRequest
, imgIContainer
160 /* Implement imgIDecoderObserver::onStopDecode() */
162 HelperLoader::OnStopDecode(imgIRequest
*aRequest
, nsresult status
, const
163 PRUnichar
*statusArg
)
168 /* Implement imgIDecoderObserver::onStopRequest() */
170 HelperLoader::OnStopRequest(imgIRequest
*aRequest
, PRBool aIsLastPart
)
175 /* implement imgIContainerObserver::frameChanged() */
177 HelperLoader::FrameChanged(imgIContainer
*aContainer
,
178 gfxIImageFrame
*aFrame
, nsIntRect
* aDirtyRect
)
185 /* ========== imgITools implementation ========== */
189 NS_IMPL_ISUPPORTS1(imgTools
, imgITools
)
193 /* member initializers and constructor code */
196 imgTools::~imgTools()
198 /* destructor code */
202 NS_IMETHODIMP
imgTools::DecodeImageData(nsIInputStream
* aInStr
,
203 const nsACString
& aMimeType
,
204 imgIContainer
**aContainer
)
208 // Get an image decoder for our media type
209 nsCAutoString
decoderCID(
210 NS_LITERAL_CSTRING("@mozilla.org/image/decoder;2?type=") + aMimeType
);
212 nsCOMPtr
<imgIDecoder
> decoder
= do_CreateInstance(decoderCID
.get());
214 return NS_IMAGELIB_ERROR_NO_DECODER
;
216 // Init the decoder, we use a small utility class here.
217 nsCOMPtr
<imgILoad
> loader
= new HelperLoader();
219 return NS_ERROR_OUT_OF_MEMORY
;
221 // If caller provided an existing container, use it.
223 loader
->SetImage(*aContainer
);
225 rv
= decoder
->Init(loader
);
226 NS_ENSURE_SUCCESS(rv
, rv
);
229 rv
= aInStr
->Available(&length
);
230 NS_ENSURE_SUCCESS(rv
, rv
);
233 NS_ENSURE_SUCCESS(rv
, rv
);
234 rv
= decoder
->WriteFrom(aInStr
, length
, &written
);
235 NS_ENSURE_SUCCESS(rv
, rv
);
236 if (written
!= length
)
237 NS_WARNING("decoder didn't eat all of its vegetables");
238 rv
= decoder
->Flush();
239 NS_ENSURE_SUCCESS(rv
, rv
);
240 rv
= decoder
->Close();
241 NS_ENSURE_SUCCESS(rv
, rv
);
243 // If caller didn't provide an existing container, return the new one.
245 loader
->GetImage(aContainer
);
251 NS_IMETHODIMP
imgTools::EncodeImage(imgIContainer
*aContainer
,
252 const nsACString
& aMimeType
,
253 nsIInputStream
**aStream
)
255 return EncodeScaledImage(aContainer
, aMimeType
, 0, 0, aStream
);
259 NS_IMETHODIMP
imgTools::EncodeScaledImage(imgIContainer
*aContainer
,
260 const nsACString
& aMimeType
,
261 PRInt32 aScaledWidth
,
262 PRInt32 aScaledHeight
,
263 nsIInputStream
**aStream
)
266 PRBool doScaling
= PR_TRUE
;
268 PRUint32 bitmapDataLength
, strideSize
;
270 // If no scaled size is specified, we'll just encode the image at its
271 // original size (no scaling).
272 if (aScaledWidth
== 0 && aScaledHeight
== 0) {
273 doScaling
= PR_FALSE
;
275 NS_ENSURE_ARG(aScaledWidth
> 0);
276 NS_ENSURE_ARG(aScaledHeight
> 0);
279 // Get an image encoder for the media type
280 nsCAutoString
encoderCID(
281 NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType
);
283 nsCOMPtr
<imgIEncoder
> encoder
= do_CreateInstance(encoderCID
.get());
285 return NS_IMAGELIB_ERROR_NO_ENCODER
;
287 // Use frame 0 from the image container.
288 nsCOMPtr
<gfxIImageFrame
> frame
;
289 rv
= aContainer
->GetFrameAt(0, getter_AddRefs(frame
));
290 NS_ENSURE_SUCCESS(rv
, rv
);
292 return NS_ERROR_NOT_AVAILABLE
;
296 frame
->GetHeight(&h
);
298 return NS_ERROR_FAILURE
;
300 nsCOMPtr
<nsIImage
> img(do_GetInterface(frame
));
301 nsRefPtr
<gfxImageSurface
> dest
;
304 // If we're not scaling the image, use the actual width/height.
308 img
->LockImagePixels(PR_FALSE
);
309 bitmapData
= img
->GetBits();
311 img
->UnlockImagePixels(PR_FALSE
);
312 return NS_ERROR_FAILURE
;
315 frame
->GetImageBytesPerRow(&strideSize
);
316 bitmapDataLength
= aScaledHeight
* strideSize
;
319 // Prepare to draw a scaled version of the image to a temporary surface...
321 // Get the source image surface
322 nsRefPtr
<gfxPattern
> gfxpat
;
323 img
->GetPattern(getter_AddRefs(gfxpat
));
325 // Create a temporary image surface
326 dest
= new gfxImageSurface(gfxIntSize(aScaledWidth
, aScaledHeight
),
327 gfxASurface::ImageFormatARGB32
);
329 return NS_ERROR_OUT_OF_MEMORY
;
331 gfxContext
ctx(dest
);
334 gfxFloat sw
= (double) aScaledWidth
/ w
;
335 gfxFloat sh
= (double) aScaledHeight
/ h
;
338 // Paint a scaled image
339 ctx
.SetOperator(gfxContext::OPERATOR_SOURCE
);
340 ctx
.SetPattern(gfxpat
);
343 bitmapData
= dest
->Data();
344 strideSize
= dest
->Stride();
345 bitmapDataLength
= aScaledHeight
* strideSize
;
349 rv
= encoder
->InitFromData(bitmapData
, bitmapDataLength
,
350 aScaledWidth
, aScaledHeight
, strideSize
,
351 imgIEncoder::INPUT_FORMAT_HOSTARGB
, EmptyString());
353 img
->UnlockImagePixels(PR_FALSE
);
355 NS_ENSURE_SUCCESS(rv
, rv
);
357 return CallQueryInterface(encoder
, aStream
);