2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FMedia_ImageImpl.cpp
20 * @brief This file contains the implementation of subsystem's Image.
23 #include <unique_ptr.h>
25 #include <FMediaImage.h>
26 #include <FMediaImageUtil.h>
27 #include <FMediaIImageEventListener.h>
28 #include <FBaseSysLog.h>
29 #include "FMedia_MediaUtil.h"
30 #include "FMedia_ImageImpl.h"
31 #include "FMedia_ImageUtilImpl.h"
32 #include "FMedia_ImageDecoder.h"
33 #include "FMedia_ImageEncoder.h"
34 #include "FMedia_ImageUriDataFactory.h"
36 using namespace Tizen::Graphics;
37 using namespace Tizen::Base;
38 using namespace Tizen::Io;
40 namespace Tizen { namespace Media
43 static const float _SCALE_DOWN_RATIO = 0.5;
44 static const int _RGB565_PIXEL_DEPTH = 2;
45 static const int _MIN_ENCODE_QUALITY = 20; // Changed from 50 to 20 to allow greater compression.
46 static const int _MAX_ENCODE_QUALITY = 99;
47 static const int _DEFAULT_ENCODE_QUALITY = 50;
48 static const int _MAX_ENCODE_LOOP = 2;
49 static const int _MAX_ENCODE_RESIZE_LOOP = 2;
50 //static const int MAX_IMGFILE_SIZE = 4096000;
52 _ImageImpl::_ImageImpl(void)
56 _ImageImpl::~_ImageImpl(void)
61 _ImageImpl::GetInstance(Image* pImage)
65 return pImage->__pImageImpl;
72 _ImageImpl::GetInstance(const Image* pImage)
76 return pImage->__pImageImpl;
83 _ImageImpl::Construct(void)
89 _ImageImpl::DecodeToBitmapN(const String& srcImgPath, BitmapPixelFormat pixelFormat,
90 const Tizen::Graphics::Dimension &dstDim,
91 Tizen::Graphics::BufferScaling bufferScaling,
92 ImageFormat imgFormat, bool keepAspectRatio)
94 std::unique_ptr<ByteBuffer> pBuf;
97 pBuf.reset(_MediaUtil::FileToBufferN(srcImgPath));
98 SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
99 "[%s] FileToBufferN %S", GetErrorMessage(GetLastResult()), srcImgPath.GetPointer());
101 pBmp = DecodeToBitmapN(*pBuf.get(), pixelFormat, dstDim, bufferScaling, imgFormat, keepAspectRatio);
105 Tizen::Graphics::Bitmap*
106 _ImageImpl::DecodeToBitmapN(const Tizen::Base::ByteBuffer& srcImageBuf,
107 Tizen::Graphics::BitmapPixelFormat pixelFormat,
108 const Tizen::Graphics::Dimension &dstDim,
109 Tizen::Graphics::BufferScaling bufferScaling,
110 ImageFormat imgFormat, bool keepAspectRatio)
112 result r = E_SUCCESS;
113 std::unique_ptr<ByteBuffer> pBuf;
114 std::unique_ptr<Bitmap> pBmp;
117 //SysTryCatch(NID_MEDIA, IS_VALID_BITMAP_PIXEL(pixelFormat), , E_INVALID_ARG,
118 // "[E_INVALID_ARG] pixelFormat:%d", pixelFormat);
119 //SysTryCatch(NID_MEDIA, IS_VALID_DIMENSION(dstDim), , E_OUT_OF_RANGE,
120 // "[E_OUT_OF_RANGE] dest dimension:%d,%d", dstDim.width, dstDim.height);
122 pBuf.reset(DecodeToBufferN(srcImageBuf, outDim, dstDim, pixelFormat, imgFormat, keepAspectRatio));
123 SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
124 "[%s] Propagated", GetErrorMessage(GetLastResult()));
126 pBmp.reset(new (std::nothrow) Bitmap);
127 SysTryReturn(NID_MEDIA, pBmp != null, null, E_OUT_OF_MEMORY,
128 "[%s] new Bitmap", GetErrorMessage(GetLastResult()));
129 r = pBmp->Construct(*pBuf.get(), outDim, pixelFormat, bufferScaling);
130 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
132 SetLastResult(E_SUCCESS);
133 return pBmp.release();
136 Tizen::Base::ByteBuffer*
137 _ImageImpl::DecodeToBufferN(const Tizen::Base::String& srcImagePath,
138 Tizen::Graphics::Dimension &restDim,
139 const Tizen::Graphics::Dimension &dstDim,
140 Tizen::Graphics::BitmapPixelFormat pixelFormat,
141 ImageFormat imgFormat, bool keepAspectRatio)
143 std::unique_ptr<ByteBuffer> pBuf;
144 ByteBuffer* pRetBuf = null;
146 //SysTryCatch(NID_MEDIA, IS_VALID_DIMENSION(dstDim), , E_OUT_OF_RANGE,
147 //"[E_OUT_OF_RANGE] dest dimension:%d,%d", dstDim.width, dstDim.height);
149 pBuf.reset(_MediaUtil::FileToBufferN(srcImagePath));
150 SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(),
151 "[%s] FileToBufferN %S", GetErrorMessage(GetLastResult()), srcImagePath.GetPointer());
153 pRetBuf = DecodeToBufferN(*pBuf.get(), restDim, dstDim, pixelFormat, imgFormat, keepAspectRatio);
157 Tizen::Base::ByteBuffer*
158 _ImageImpl::DecodeToBufferN(const Tizen::Base::ByteBuffer &srcImageBuf,
159 Tizen::Graphics::Dimension &retDim,
160 const Tizen::Graphics::Dimension &dstDim,
161 Tizen::Graphics::BitmapPixelFormat pixelFormat,
162 ImageFormat imgFormat, bool keepAspectRatio)
164 result r = E_SUCCESS;
165 std::unique_ptr<ByteBuffer> pBuf;
168 //SysTryCatch(NID_MEDIA, IS_VALID_BITMAP_PIXEL(pixelFormat), , E_INVALID_ARG,
169 //"[E_INVALID_ARG] pixelFormat:%d", pixelFormat);
171 r = dec.Construct(srcImageBuf, _ImageUtilImpl::ToMediaPixelFormat(pixelFormat), imgFormat);
172 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Decoder construct failed.", GetErrorMessage(r));
174 // Reset decoder output demension
175 dec.SetOutputDimension(dstDim.width, dstDim.height, keepAspectRatio);
177 pBuf.reset(dec.DecodeN());
179 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
181 r = dec.GetDimension(retDim.width, retDim.height);
182 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
184 SetLastResult(E_SUCCESS);
185 return pBuf.release();
188 Tizen::Base::ByteBuffer*
189 _ImageImpl::DecodeToBufferN(const Tizen::Base::String& srcImagePath,
190 Tizen::Graphics::BitmapPixelFormat pixelFormat,
191 int& imageWidth, int& imageHeight, bool keepAspectRatio)
193 ByteBuffer *pBuf = null;
196 pBuf = DecodeToBufferN(srcImagePath, dim, Dimension(0, 0), pixelFormat, IMG_FORMAT_NONE, keepAspectRatio);
197 imageWidth = dim.width;
198 imageHeight = dim.height;
203 Tizen::Base::ByteBuffer*
204 _ImageImpl::DecodeN(const Tizen::Base::String& srcImagePath,
205 Tizen::Graphics::BitmapPixelFormat pixelFormat,
206 int destWidth, int destHeight, bool keepAspectRatio)
210 return DecodeToBufferN(srcImagePath, dim, Dimension(destWidth, destHeight), pixelFormat, IMG_FORMAT_NONE, keepAspectRatio);
214 _ImageImpl::DecodeUrl(const Tizen::Base::Utility::Uri& srcImageUrl,
215 Tizen::Graphics::BitmapPixelFormat colorFormat,
216 int destWidth, int destHeight, RequestId& reqId,
217 const IImageDecodeUrlEventListener& listener, long timeout)
219 result r = E_SUCCESS;
221 _ImageUriDataFactory *pFactory = null;
223 SysTryCatch(NID_MEDIA, (colorFormat > Tizen::Graphics::BITMAP_PIXEL_FORMAT_MIN)
224 && colorFormat < Tizen::Graphics::BITMAP_PIXEL_FORMAT_MAX, , E_INVALID_ARG,
225 "[E_INVALID_ARG] Wrong color format.");
227 SysTryCatch(NID_MEDIA, destWidth > 0 && destHeight > 0, , E_OUT_OF_RANGE,
228 "[E_OUT_OF_RANGE] The designated width and height SHOUL be greater than 0.");
230 SysTryCatch(NID_MEDIA, timeout == _TIMEOUT_INFINITE || timeout > 0 ,
231 r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
232 "[E_OUT_OF_RANGE] The designated timeout SHOUL be greater than 0");
234 pFactory = _ImageUriDataFactory::GetInstance();
235 SysTryCatch(NID_MEDIA, pFactory != null, r = GetLastResult(), r,
236 "[%s] Failed to GetInstance().", GetErrorMessage(r));
238 r = pFactory->DecodeUrl(srcImageUrl, colorFormat, destWidth,destHeight, reqId, listener, timeout);
239 SysTryCatch(NID_MEDIA, r == E_SUCCESS , , r,"[%s] Propagated.", GetErrorMessage(r));
248 _ImageImpl::EncodeToBufferN(const Bitmap& srcBmp, ImageFormat dstFormat)
250 std::unique_ptr<ByteBuffer> pBuf;
254 // ClearLastResult();
256 Tizen::Graphics::Bitmap& tmpBmp = const_cast<Tizen::Graphics::Bitmap&>(srcBmp);
259 tmpBmp.Lock(bmpInfo);
261 dim.SetSize(bmpInfo.width, bmpInfo.height);
263 // TODO: handle case that pitch != width * bpp/8
264 SysTryReturn(NID_MEDIA, bmpInfo.pitch == bmpInfo.width*bmpInfo.bitsPerPixel/8, null, E_SYSTEM,
265 "[E_SYSTEM] pitch=%d bpp=%d", bmpInfo.pitch, bmpInfo.bitsPerPixel);
267 pBuf.reset(_ImageEncoder::EncodeN(dstFormat, (const byte*)bmpInfo.pPixels, bmpInfo.pitch * bmpInfo.height,
268 dim.width, dim.height,
269 _ImageUtilImpl::ToMediaPixelFormat(srcBmp.GetPixelColorFormat()),
270 _DEFAULT_ENCODE_QUALITY));
271 SysTryReturn(NID_MEDIA, pBuf.get() != null, null, GetLastResult(), "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
273 return pBuf.release();
277 _ImageImpl::EncodeToFile(const Bitmap& srcBmp, ImageFormat dstFormat,
278 const String& dstPath, bool overwrite)
280 result r = E_SUCCESS;
281 std::unique_ptr<ByteBuffer> pBuf;
283 pBuf.reset(EncodeToBufferN(srcBmp, dstFormat));
284 SysTryReturn(NID_MEDIA, pBuf.get() != null, GetLastResult(), GetLastResult(),
285 "[%s] Propagated.", GetErrorMessage(GetLastResult()));
287 r = _MediaUtil::BufferToFile(*pBuf.get(), dstPath, overwrite);
288 SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated. ", GetErrorMessage(r));
294 Tizen::Base::ByteBuffer*
295 _ImageImpl::CompressJpegN(const Tizen::Base::ByteBuffer& srcImageBuf, int limitSize)
297 result r = E_SUCCESS;
298 std::unique_ptr<ByteBuffer> pDecBuf;
299 std::unique_ptr<ByteBuffer> pEncBuf;
302 volatile int limit = limitSize;
303 MediaPixelFormat pixelFormat = MEDIA_PIXEL_FORMAT_BGRA8888;
305 // TODO : use yuv pixel format
307 r = dec.Construct(srcImageBuf, pixelFormat);
308 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Decoder construct failed.", GetErrorMessage(r));
310 pDecBuf.reset(dec.DecodeN());
312 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
313 SysTryReturn(NID_MEDIA, pDecBuf.get() != null, null, E_SYSTEM, "[E_SYSTEM] Propagated.");
315 r = dec.GetDimension(srcDim.width, srcDim.height);
316 SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] Propagated. ", GetErrorMessage(r));
318 for (int i = 0; i < _MAX_ENCODE_RESIZE_LOOP; i++)
321 ByteBuffer *pTmpBuf = null;
323 pEncBuf.reset(EncodeToBufferLimitN(*pDecBuf.get(), srcDim, pixelFormat, IMG_FORMAT_JPG, limit));
325 if (pEncBuf.get() != null)
330 // halve and make even number
331 dstDim.width = srcDim.width >> 2;
332 dstDim.height = srcDim.height >> 2;
334 dstDim.width = dstDim.width << 1;
335 dstDim.height = dstDim.height << 1;
337 SysTryReturn(NID_MEDIA, srcDim != dstDim && dstDim.width > 0 && dstDim.height > 0, null, E_SYSTEM,
338 "[E_SYSTEM] Resize failed:src:%dx%d dst:%dx%d, %d %d, %d",
339 srcDim.width, srcDim.height, dstDim.width, dstDim.height, i, _SCALE_DOWN_RATIO,
342 pTmpBuf = _ImageUtilImpl::ResizeN(*pDecBuf.get(), srcDim, pixelFormat, dstDim);
343 SysTryReturn(NID_MEDIA, pTmpBuf != null, null, GetLastResult(),
344 "[%s] ResizeN: %dx%d->%dx%d", GetErrorMessage(GetLastResult()),
345 srcDim.width, srcDim.height, dstDim.width, dstDim.height);
348 pDecBuf.reset(pTmpBuf);
350 SysTryReturn(NID_MEDIA, pEncBuf.get() != null, null, E_SYSTEM, "[E_SYSTEM] Compress failed");
351 SetLastResult(E_SUCCESS);
352 return pEncBuf.release();
356 _ImageImpl::CompressJpeg(const Tizen::Base::String& srcImagePath,
357 const Tizen::Base::String& dstImagePath, int limitSize)
360 result r = E_SUCCESS;
361 std::unique_ptr<ByteBuffer> pSrcBuf;
362 std::unique_ptr<ByteBuffer> pEncBuf;
364 pSrcBuf.reset(_MediaUtil::FileToBufferN(srcImagePath));
365 SysTryReturn(NID_MEDIA, pSrcBuf.get() != null, GetLastResult(), GetLastResult(),
366 "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
368 // SysTryCatch(NID_MEDIA, pSrcBuf->GetCapacity() < MAX_IMGFILE_SIZE, r = E_OVERFLOW, E_OVERFLOW,
369 // "[E_OUT_OF_RANGE] Input file size is smaller than limitSize.");
371 SysTryReturn(NID_MEDIA, pSrcBuf.get()->GetCapacity() > limitSize, E_OUT_OF_RANGE, E_OUT_OF_RANGE,
372 "[E_OUT_OF_RANGE] Input file size is smaller than limitSize.");
374 pEncBuf.reset(CompressJpegN(*pSrcBuf, limitSize));
375 SysTryReturn(NID_MEDIA, pEncBuf != null, GetLastResult(), GetLastResult(),
376 "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
378 if (File::IsFileExist(dstImagePath))
380 File::Remove(dstImagePath);
383 r = file.Construct(dstImagePath, "wb", true);
384 SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated. ", GetErrorMessage(r));
385 r = file.Write(*pEncBuf);
386 SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Propagated. ", GetErrorMessage(r));
391 Tizen::Base::ByteBuffer*
392 _ImageImpl::ConvertToBufferN(const Tizen::Base::String& srcImagePath, ImageFormat destImageFormat)
394 std::unique_ptr<Bitmap> pBmp;
395 ByteBuffer* pBuf = null;
397 pBmp.reset(DecodeToBitmapN(srcImagePath, BITMAP_PIXEL_FORMAT_ARGB8888, Dimension(0, 0),
398 BUFFER_SCALING_NONE));
399 SysTryReturn(NID_MEDIA, pBmp.get(), null, GetLastResult(),
400 "[%s] Propagated. ", GetErrorMessage(GetLastResult()));
402 pBuf = EncodeToBufferN(*pBmp.get(), destImageFormat);
403 SysTryReturn(NID_MEDIA, pBuf != null, null, GetLastResult(),
404 "[%s] Propagated.", GetErrorMessage(GetLastResult()));
406 SetLastResult(E_SUCCESS);
410 Tizen::Base::ByteBuffer*
411 _ImageImpl::EncodeToBufferLimitN(const Tizen::Base::ByteBuffer &srcBuf,
412 const Tizen::Graphics::Dimension& dim,
413 MediaPixelFormat pixelFormat, ImageFormat imgFormat, int limit)
415 int minQuality = _MIN_ENCODE_QUALITY;
416 int maxQuality = _MAX_ENCODE_QUALITY;
421 std::unique_ptr<ByteBuffer> pMaxBuf;
422 std::unique_ptr<ByteBuffer> pMinBuf;
424 pMaxBuf.reset(EncodeToBufferQualityN(srcBuf, dim, pixelFormat, imgFormat, maxQuality));
425 SysTryReturn(NID_MEDIA, pMaxBuf.get() != null, pMinBuf.get(), E_SYSTEM, "[E_SYSTEM] maxBuf is null");
426 maxDiff = pMaxBuf->GetLimit() - limit;
427 SysLog(NID_MEDIA, "maxDiff:%d buf:%d limit:%d q:%d",
428 maxDiff, pMaxBuf->GetLimit(), limit, maxQuality);
431 SetLastResult(E_SUCCESS);
432 return pMaxBuf.release();
434 pMinBuf.reset(EncodeToBufferQualityN(srcBuf, dim, pixelFormat, imgFormat, minQuality));
435 SysTryReturn(NID_MEDIA, pMinBuf.get() != null, pMinBuf.release(), E_SYSTEM, "[E_SYSTEM] minBuf is null");
436 minDiff = pMinBuf->GetLimit() - limit;
437 SysLog(NID_MEDIA, "minDiff:%d buf:%d limit:%d q:%d",
438 minDiff, pMinBuf->GetLimit(), limit, minQuality);
441 SetLastResult(E_OVERFLOW);
446 SetLastResult(E_SUCCESS);
447 return pMinBuf.release();
450 for (int i = 0; i < _MAX_ENCODE_LOOP; i++)
452 int prevQuality = curQuality;
454 ByteBuffer *pCurBuf = null;
456 curQuality = (minQuality + maxQuality) / 2;
457 if (prevQuality == curQuality)
461 pCurBuf = EncodeToBufferQualityN(srcBuf, dim, pixelFormat, imgFormat, curQuality);
462 if (pCurBuf == null && pMinBuf.get() != null)
466 SysTryReturn(NID_MEDIA, pCurBuf != null, pMinBuf.release(), E_SYSTEM,
467 "[E_SYSTEM] curBuf is null : %d %d %d", dim.width, dim.height, curQuality);
468 curDiff = pCurBuf->GetLimit() - limit;
469 SysLog(NID_MEDIA, "curDiff:%d buf:%d limit:%d q:%d",
470 curDiff, pCurBuf->GetLimit(), limit, curQuality);
473 SetLastResult(E_SUCCESS);
476 else if (curDiff > 0)
479 maxQuality = curQuality;
480 pMaxBuf.reset(pCurBuf);
482 else if (curDiff < 0)
484 pMinBuf.reset(pCurBuf);
486 minQuality = curQuality;
491 SetLastResult(E_SUCCESS);
495 // should not come here.
496 SetLastResult(E_SYSTEM);
498 return pMinBuf.release();
501 Tizen::Base::ByteBuffer*
502 _ImageImpl::EncodeToBufferQualityN(const Tizen::Base::ByteBuffer &srcBuf,
503 const Tizen::Graphics::Dimension& dim,
504 MediaPixelFormat pixelFormat, ImageFormat imgFormat, int quality)
506 ByteBuffer* pBuf = null;
508 pBuf = _ImageEncoder::EncodeN(imgFormat, srcBuf.GetPointer(), srcBuf.GetLimit(),
509 dim.width, dim.height, pixelFormat, quality);
510 SysTryReturn(NID_MEDIA, pBuf != null, pBuf, GetLastResult(),
511 "[%s] enc.EncodeN. ", GetErrorMessage(GetLastResult()));
517 _ImageImpl::GetImageInfo(const Tizen::Base::String& path, ImageFormat &imgFormat,
518 Tizen::Graphics::Dimension &dim)
520 return _ImageDecoder::GetImageInfo(path, imgFormat, dim.width, dim.height);