• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "basic_transformer.h"
17 #include <iostream>
18 #include <new>
19 #include <unistd.h>
20 #include "image_utils.h"
21 #include "pixel_convert.h"
22 #include "pixel_map.h"
23 #ifndef _WIN32
24 #include "securec.h"
25 #else
26 #include "memory.h"
27 #endif
28 
29 #if !defined(_WIN32) && !defined(_APPLE) &&!defined(_IOS) &&!defined(_ANDROID)
30 #include "ashmem.h"
31 #include <sys/mman.h>
32 #endif
33 
34 namespace {
35     constexpr uint32_t RGB24_R_MASK = 0x00ff0000;
36     constexpr uint32_t RGB24_G_MASK = 0x0000ff00;
37     constexpr uint32_t RGB24_B_MASK = 0x000000ff;
38     constexpr uint16_t RGB16_R_MASK = 0xf800;
39     constexpr uint16_t RGB16_G_MASK = 0x07e0;
40     constexpr uint16_t RGB16_B_MASK = 0x001f;
41 
42     constexpr uint32_t RGB32_RGB16_R_SHIFT = 0x13;
43     constexpr uint32_t RGB32_RGB16_G_SHIFT = 0xA;
44     constexpr uint32_t RGB32_RGB16_B_SHIFT = 0x3;
45 
46     constexpr uint32_t RGB16_RGB32_R_SHIFT = 0x8;
47     constexpr uint32_t RGB16_RGB32_G_SHIFT = 0x3;
48     constexpr uint32_t RGB16_RGB32_B_SHIFT = 0x3;
49 
50     constexpr uint32_t RGB24_R_SHIFT = 0x10;
51     constexpr uint32_t RGB24_G_SHIFT = 0x8;
52     constexpr uint32_t OFFSET_0 = 0;
53     constexpr uint32_t OFFSET_1 = 1;
54     constexpr uint32_t OFFSET_2 = 2;
55 }
56 namespace OHOS {
57 namespace Media {
58 using namespace std;
ResetParam()59 void BasicTransformer::ResetParam()
60 {
61     matrix_ = Matrix();
62     minX_ = 0.0f;
63     minY_ = 0.0f;
64 }
65 
SetScaleParam(const float sx,const float sy)66 void BasicTransformer::SetScaleParam(const float sx, const float sy)
67 {
68     Matrix m;
69     m.SetScale(sx, sy);
70     matrix_.SetConcat(m);
71 }
72 
SetTranslateParam(const float tx,const float ty)73 void BasicTransformer::SetTranslateParam(const float tx, const float ty)
74 {
75     Matrix m;
76     m.SetTranslate(tx, ty);
77     matrix_.SetConcat(m);
78 }
79 
SetRotateParam(const float degrees,const float px,const float py)80 void BasicTransformer::SetRotateParam(const float degrees, const float px, const float py)
81 {
82     Matrix m;
83     m.SetRotate(degrees, px, py);
84     matrix_.SetConcat(m);
85 }
86 
GetDstDimension(const Size & srcSize,Size & dstSize)87 void BasicTransformer::GetDstDimension(const Size &srcSize, Size &dstSize)
88 {
89     Matrix::OperType operType = matrix_.GetOperType();
90     if ((static_cast<uint8_t>(operType) & Matrix::SCALE) == Matrix::SCALE) {
91         dstSize.width = static_cast<int32_t>(srcSize.width * fabs(matrix_.GetScaleX()) + FHALF);
92         dstSize.height = static_cast<int32_t>(srcSize.height * fabs(matrix_.GetScaleY()) + FHALF);
93     }
94 
95     if ((static_cast<uint8_t>(operType) & Matrix::ROTATEORSKEW) == Matrix::ROTATEORSKEW) {
96         Matrix::CalcXYProc fInvProc = Matrix::GetXYProc(operType);
97         GetRotateDimension(fInvProc, srcSize, dstSize);
98     }
99 
100     if ((static_cast<uint8_t>(operType) & Matrix::TRANSLATE) == Matrix::TRANSLATE) {
101         if (matrix_.GetTransX() > 0) {
102             dstSize.width = static_cast<int32_t>(srcSize.width + matrix_.GetTransX() + FHALF);
103         }
104         if (matrix_.GetTranY() > 0) {
105             dstSize.height = static_cast<int32_t>(srcSize.height + matrix_.GetTranY() + FHALF);
106         }
107     }
108 }
109 
CheckAllocateBuffer(PixmapInfo & outPixmap,AllocateMem allocate,int & fd,uint64_t & bufferSize,Size & dstSize)110 bool BasicTransformer::CheckAllocateBuffer(PixmapInfo &outPixmap, AllocateMem allocate,
111                                            int &fd, uint64_t &bufferSize, Size &dstSize)
112 {
113     if (bufferSize == 0 || bufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
114         IMAGE_LOGE("[BasicTransformer]Invalid value of bufferSize");
115         return false;
116     }
117     if (allocate == nullptr) {
118         outPixmap.data = static_cast<uint8_t *>(malloc(bufferSize));
119     } else {
120         outPixmap.data = allocate(dstSize, bufferSize, fd);
121         auto tmp = std::make_unique<int32_t>();
122         *tmp = fd;
123         outPixmap.context = tmp.release();
124     }
125     if (outPixmap.data == nullptr) {
126         IMAGE_LOGE("[BasicTransformer]apply heap memory failed");
127         return false;
128     }
129     return true;
130 }
131 
ReleaseBuffer(AllocatorType allocatorType,int fd,int dataSize,uint8_t * buffer)132 void BasicTransformer::ReleaseBuffer(AllocatorType allocatorType, int fd, int dataSize, uint8_t *buffer)
133 {
134 #if !defined(_WIN32) && !defined(_APPLE) &&!defined(_IOS) &&!defined(_ANDROID)
135     if (allocatorType == AllocatorType::SHARE_MEM_ALLOC) {
136         if (buffer != nullptr) {
137             ::munmap(buffer, dataSize);
138             ::close(fd);
139         }
140         return;
141     }
142 #endif
143 
144     if (allocatorType == AllocatorType::HEAP_ALLOC) {
145         if (buffer != nullptr) {
146             free(buffer);
147         }
148         return;
149     }
150 }
151 
TransformPixmap(const PixmapInfo & inPixmap,PixmapInfo & outPixmap,AllocateMem allocate)152 uint32_t BasicTransformer::TransformPixmap(const PixmapInfo &inPixmap, PixmapInfo &outPixmap, AllocateMem allocate)
153 {
154     if (inPixmap.data == nullptr) {
155         IMAGE_LOGE("[BasicTransformer]input data is null.");
156         return ERR_IMAGE_GENERAL_ERROR;
157     }
158     int32_t pixelBytes = ImageUtils::GetPixelBytes(inPixmap.imageInfo.pixelFormat);
159     if (pixelBytes == 0) {
160         IMAGE_LOGE("[BasicTransformer]input pixel is invalid.");
161         return ERR_IMAGE_INVALID_PIXEL;
162     }
163 
164     Size dstSize = inPixmap.imageInfo.size;
165     GetDstDimension(inPixmap.imageInfo.size, dstSize);
166     outPixmap.imageInfo.size = dstSize;
167     if (dstSize.width <= 0 || dstSize.height <= 0) {
168         IMAGE_LOGE("[BasicTransformer]buffer size is invalid.");
169         return ERR_IMAGE_ALLOC_MEMORY_FAILED;
170     }
171 
172     uint64_t bufferSize = static_cast<uint64_t>(dstSize.width) * dstSize.height * pixelBytes;
173     if (bufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
174         IMAGE_LOGE("[BasicTransformer] buffer size:%{public}llu out of range.",
175                    static_cast<unsigned long long>(bufferSize));
176         return ERR_IMAGE_ALLOC_MEMORY_FAILED;
177     }
178     int fd = 0;
179     if (!(CheckAllocateBuffer(outPixmap, allocate, fd, bufferSize, dstSize))) {
180         return ERR_IMAGE_ALLOC_MEMORY_FAILED;
181     }
182     outPixmap.bufferSize = bufferSize;
183     outPixmap.imageInfo.pixelFormat = inPixmap.imageInfo.pixelFormat;
184     outPixmap.imageInfo.colorSpace = inPixmap.imageInfo.colorSpace;
185     outPixmap.imageInfo.alphaType = inPixmap.imageInfo.alphaType;
186     outPixmap.imageInfo.baseDensity = inPixmap.imageInfo.baseDensity;
187 
188     if (memset_s(outPixmap.data, bufferSize * sizeof(uint8_t), COLOR_DEFAULT, bufferSize * sizeof(uint8_t)) != EOK) {
189         IMAGE_LOGE("[BasicTransformer]apply heap memory failed.");
190         ReleaseBuffer((allocate == nullptr) ? AllocatorType::HEAP_ALLOC : AllocatorType::SHARE_MEM_ALLOC,
191             fd, bufferSize, outPixmap.data);
192         return ERR_IMAGE_GENERAL_ERROR;
193     }
194 
195     if (!DrawPixelmap(inPixmap, pixelBytes, dstSize, outPixmap.data)) {
196         IMAGE_LOGE("[BasicTransformer] the matrix can not invert.");
197         ReleaseBuffer((allocate == nullptr) ? AllocatorType::HEAP_ALLOC : AllocatorType::SHARE_MEM_ALLOC,
198             fd, bufferSize, outPixmap.data);
199         return ERR_IMAGE_MATRIX_NOT_INVERT;
200     }
201     return IMAGE_SUCCESS;
202 }
203 
pointLoop(Point & pt,const Size & size)204 static inline void pointLoop(Point &pt, const Size &size)
205 {
206     if (pt.x < 0) {
207         pt.x = size.width + pt.x;
208     }
209     if (pt.y < 0) {
210         pt.y = size.height + pt.y;
211     }
212 }
213 
DrawPixelmap(const PixmapInfo & pixmapInfo,const int32_t pixelBytes,const Size & size,uint8_t * data)214 bool BasicTransformer::DrawPixelmap(const PixmapInfo &pixmapInfo, const int32_t pixelBytes, const Size &size,
215                                     uint8_t *data)
216 {
217     Matrix invertMatrix;
218     if (!(matrix_.Invert(invertMatrix))) {
219         return false;
220     }
221 
222     uint32_t rb = pixmapInfo.imageInfo.size.width * pixelBytes;
223     Matrix::OperType operType = matrix_.GetOperType();
224     Matrix::CalcXYProc fInvProc = Matrix::GetXYProc(operType);
225 
226     for (int32_t y = 0; y < size.height; ++y) {
227         for (int32_t x = 0; x < size.width; ++x) {
228             Point srcPoint;
229             // Center coordinate alignment, need to add 0.5, so the boundary can also be considered
230             fInvProc(invertMatrix, static_cast<float>(x) + minX_ + FHALF, static_cast<float>(y) + minY_ + FHALF,
231                      srcPoint);
232             if ((static_cast<uint8_t>(operType) & Matrix::OperType::SCALE) == Matrix::OperType::SCALE) {
233                 pointLoop(srcPoint, pixmapInfo.imageInfo.size);
234             }
235             if (CheckOutOfRange(srcPoint, pixmapInfo.imageInfo.size)) {
236                 continue;
237             }
238             uint32_t shiftBytes = (y * size.width + x) * pixelBytes;
239             BilinearProc(srcPoint, pixmapInfo, rb, shiftBytes, data);
240         }
241     }
242 
243     return true;
244 }
245 
GetRotateDimension(Matrix::CalcXYProc fInvProc,const Size & srcSize,Size & dstSize)246 void BasicTransformer::GetRotateDimension(Matrix::CalcXYProc fInvProc, const Size &srcSize, Size &dstSize)
247 {
248     Point dstP1;
249     Point dstP2;
250     Point dstP3;
251     Point dstP4;
252 
253     float fx = static_cast<float>(srcSize.width);
254     float fy = static_cast<float>(srcSize.height);
255     fInvProc(matrix_, 0.0f, 0.0f, dstP1);
256     fInvProc(matrix_, fx, 0.0f, dstP2);
257     fInvProc(matrix_, 0.0f, fy, dstP3);
258     fInvProc(matrix_, fx, fy, dstP4);
259 
260     // For rotation, the width and height will change, so you need to take the maximum of the two diagonals.
261     dstSize.width = static_cast<int32_t>(fmaxf(fabsf(dstP4.x - dstP1.x), fabsf(dstP3.x - dstP2.x)) + FHALF);
262     dstSize.height = static_cast<int32_t>(fmaxf(fabsf(dstP4.y - dstP1.y), fabsf(dstP3.y - dstP2.y)) + FHALF);
263 
264     float min14X = std::min(dstP1.x, dstP4.x);
265     float min23X = std::min(dstP2.x, dstP3.x);
266     minX_ = std::min(min14X, min23X);
267 
268     float min14Y = std::min(dstP1.y, dstP4.y);
269     float min23Y = std::min(dstP2.y, dstP3.y);
270     minY_ = std::min(min14Y, min23Y);
271 }
272 
RGB565to32(uint16_t c)273 static uint32_t RGB565to32(uint16_t c)
274 {
275     uint32_t color = c;
276     uint32_t r = (color & RGB16_R_MASK) >> RGB16_RGB32_R_SHIFT;
277     uint32_t g = (color & RGB16_G_MASK) >> RGB16_RGB32_G_SHIFT;
278     uint32_t b = (color & RGB16_B_MASK) << RGB16_RGB32_B_SHIFT;
279     return (r << SHIFT_16_BIT) | (g << SHIFT_8_BIT) | b;
280 }
281 
Color32toRGB565(uint32_t c)282 static uint16_t Color32toRGB565(uint32_t c)
283 {
284     uint16_t r = (c & RGB24_R_MASK) >> RGB32_RGB16_R_SHIFT;
285     uint16_t g = (c & RGB24_G_MASK) >> RGB32_RGB16_G_SHIFT;
286     uint16_t b = (c & RGB24_B_MASK) >> RGB32_RGB16_B_SHIFT;
287     return (r << SHIFT_11_BIT) | (g << SHIFT_5_BIT) | b;
288 }
289 
290 struct BilinearPixelProcArgs {
291     PixelFormat format;
292     uint8_t* in;
293     uint8_t* out;
294     uint32_t rowBytes;
295     uint32_t subx;
296     uint32_t suby;
297 };
298 
BilinearPixelProc(const AroundPos aroundPos,struct BilinearPixelProcArgs & args)299 void BasicTransformer::BilinearPixelProc(const AroundPos aroundPos, struct BilinearPixelProcArgs &args)
300 {
301     AroundPixels aroundPixels;
302     uint32_t filterColor = OFFSET_0;
303 
304     switch (args.format) {
305         case PixelFormat::RGBA_8888:
306         case PixelFormat::ARGB_8888:
307         case PixelFormat::BGRA_8888:
308             {
309                 GetAroundPixelRGBA(aroundPos, args.in, args.rowBytes, aroundPixels);
310                 uint32_t *tmp32 = reinterpret_cast<uint32_t *>(args.out);
311                 *tmp32 = FilterProc(args.subx, args.suby, aroundPixels);
312                 break;
313             }
314         case PixelFormat::RGB_565:
315             {    GetAroundPixelRGB565(aroundPos, args.in, args.rowBytes, aroundPixels);
316                 filterColor = FilterProc(args.subx, args.suby, aroundPixels);
317                 uint16_t *tmp16 = reinterpret_cast<uint16_t *>(args.out);
318                 *tmp16 = Color32toRGB565(filterColor);
319                 break;
320             }
321         case PixelFormat::RGB_888:
322             {
323                 GetAroundPixelRGB888(aroundPos, args.in, args.rowBytes, aroundPixels);
324                 filterColor = FilterProc(args.subx, args.suby, aroundPixels);
325                 *(args.out) = static_cast<uint8_t>((filterColor & RGB24_R_MASK) >> RGB24_R_SHIFT);
326                 *((args.out) + OFFSET_1) =
327                     static_cast<uint8_t>((filterColor & RGB24_G_MASK) >> RGB24_G_SHIFT);
328                 *((args.out) + OFFSET_2) = static_cast<uint8_t>(filterColor & RGB24_B_MASK);
329                 break;
330             }
331         case PixelFormat::ALPHA_8:
332             {
333                 GetAroundPixelALPHA8(aroundPos, args.in, args.rowBytes, aroundPixels);
334                 filterColor = FilterProc(args.subx, args.suby, aroundPixels);
335                 *(args.out) = static_cast<uint8_t>(filterColor & RGB24_B_MASK);
336                 break;
337             }
338         default:
339             IMAGE_LOGE("[BasicTransformer] pixel format not supported, format:%{public}d", args.format);
340     }
341 }
342 
BilinearProc(const Point & pt,const PixmapInfo & pixmapInfo,const uint32_t rb,const int32_t shiftBytes,uint8_t * data)343 void BasicTransformer::BilinearProc(const Point &pt, const PixmapInfo &pixmapInfo, const uint32_t rb,
344                                     const int32_t shiftBytes, uint8_t *data)
345 {
346     uint32_t srcX = (pt.x * MULTI_65536) - HALF_BASIC < 0 ? 0 : (pt.x * MULTI_65536) - HALF_BASIC;
347     uint32_t srcY = (pt.y * MULTI_65536) - HALF_BASIC < 0 ? 0 : (pt.y * MULTI_65536) - HALF_BASIC;
348 
349     struct BilinearPixelProcArgs procArgs;
350     procArgs.format = pixmapInfo.imageInfo.pixelFormat;
351     procArgs.in = pixmapInfo.data;
352     procArgs.out = data + shiftBytes;
353     procArgs.rowBytes = rb;
354     procArgs.subx = GetSubValue(srcX);
355     procArgs.suby = GetSubValue(srcY);
356 
357     AroundPos aroundPos;
358     aroundPos.x0 = RightShift16Bit(srcX, pixmapInfo.imageInfo.size.width - 1);
359     aroundPos.x1 = RightShift16Bit(srcX + BASIC, pixmapInfo.imageInfo.size.width - 1);
360     aroundPos.y0 = RightShift16Bit(srcY, pixmapInfo.imageInfo.size.height - 1);
361     aroundPos.y1 = RightShift16Bit(srcY + BASIC, pixmapInfo.imageInfo.size.height - 1);
362 
363     BilinearPixelProc(aroundPos, procArgs);
364 }
365 
GetAroundPixelRGB565(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)366 void BasicTransformer::GetAroundPixelRGB565(const AroundPos aroundPos, uint8_t *data, uint32_t rb,
367                                             AroundPixels &aroundPixels)
368 {
369     const uint16_t *row0 = reinterpret_cast<uint16_t *>(data + aroundPos.y0 * rb);
370     const uint16_t *row1 = reinterpret_cast<uint16_t *>(data + aroundPos.y1 * rb);
371 
372     aroundPixels.color00 = RGB565to32(row0[aroundPos.x0]);
373     aroundPixels.color01 = RGB565to32(row0[aroundPos.x1]);
374     aroundPixels.color10 = RGB565to32(row1[aroundPos.x0]);
375     aroundPixels.color11 = RGB565to32(row1[aroundPos.x1]);
376 }
377 
GetAroundPixelRGB888(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)378 void BasicTransformer::GetAroundPixelRGB888(const AroundPos aroundPos, uint8_t *data, uint32_t rb,
379                                             AroundPixels &aroundPixels)
380 {
381     const uint8_t *row0 = data + aroundPos.y0 * rb;
382     const uint8_t *row1 = data + aroundPos.y1 * rb;
383     uint32_t current0 = aroundPos.x0 * RGB888_BYTE;
384     uint32_t current1 = aroundPos.x1 * RGB888_BYTE;
385     // The RGB888 format occupies 3 bytes, and an int integer is formed by OR operation.
386     aroundPixels.color00 =
387         (row0[current0] << SHIFT_16_BIT) | (row0[current0 + 1] << SHIFT_8_BIT) | (row0[current0 + 2]);
388     aroundPixels.color01 =
389         (row0[current1] << SHIFT_16_BIT) | (row0[current1 + 1] << SHIFT_8_BIT) | (row0[current1 + 2]);
390     aroundPixels.color10 =
391         (row1[current0] << SHIFT_16_BIT) | (row1[current0 + 1] << SHIFT_8_BIT) | (row1[current0 + 2]);
392     aroundPixels.color11 =
393         (row1[current1] << SHIFT_16_BIT) | (row1[current1 + 1] << SHIFT_8_BIT) | (row1[current1 + 2]);
394 }
395 
GetAroundPixelRGBA(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)396 void BasicTransformer::GetAroundPixelRGBA(const AroundPos aroundPos, uint8_t *data,
397                                           uint32_t rb, AroundPixels &aroundPixels)
398 {
399     const uint32_t *row0 = reinterpret_cast<uint32_t *>(data + aroundPos.y0 * rb);
400     const uint32_t *row1 = reinterpret_cast<uint32_t *>(data + aroundPos.y1 * rb);
401     aroundPixels.color00 = row0[aroundPos.x0];
402     aroundPixels.color01 = row0[aroundPos.x1];
403     aroundPixels.color10 = row1[aroundPos.x0];
404     aroundPixels.color11 = row1[aroundPos.x1];
405 }
406 
GetAroundPixelALPHA8(const AroundPos aroundPos,uint8_t * data,uint32_t rb,AroundPixels & aroundPixels)407 void BasicTransformer::GetAroundPixelALPHA8(const AroundPos aroundPos, uint8_t *data, uint32_t rb,
408                                             AroundPixels &aroundPixels)
409 {
410     const uint8_t *row0 = data + aroundPos.y0 * rb;
411     const uint8_t *row1 = data + aroundPos.y1 * rb;
412     aroundPixels.color00 = row0[aroundPos.x0];
413     aroundPixels.color01 = row0[aroundPos.x1];
414     aroundPixels.color10 = row1[aroundPos.x0];
415     aroundPixels.color11 = row1[aroundPos.x1];
416 }
417 
RightShift16Bit(uint32_t num,int32_t maxNum)418 uint32_t BasicTransformer::RightShift16Bit(uint32_t num, int32_t maxNum)
419 {
420     /*
421      * When the original image coordinates are obtained,
422      * the first 16 bits are shifted to the left, so the right shift is 16 bits here.
423      */
424     return ClampMax(num >> 16, maxNum);
425 }
426 
FilterProc(const uint32_t subx,const uint32_t suby,const AroundPixels & aroundPixels)427 uint32_t BasicTransformer::FilterProc(const uint32_t subx, const uint32_t suby, const AroundPixels &aroundPixels)
428 {
429     int32_t xy = subx * suby;
430     // Mask 0xFF00FF ensures that high and low 16 bits can be calculated simultaneously
431     const uint32_t mask = 0xFF00FF;
432 
433     /* All values are first magnified 16 times (left shift 4bit) and then divide 256 (right shift 8bit).
434      * Reference formula f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1),
435      * The subx is u, the suby is y,
436      * color00 is f(i,j), color 01 is f(i,j+1), color 10 is f(i+1,j), color11 is f(i+1,j+1).
437      */
438     int32_t scale = 256 - 16 * suby - 16 * subx + xy;
439     uint32_t lo = (aroundPixels.color00 & mask) * scale;
440     uint32_t hi = ((aroundPixels.color00 >> 8) & mask) * scale;
441 
442     scale = 16 * subx - xy;
443     lo += (aroundPixels.color01 & mask) * scale;
444     hi += ((aroundPixels.color01 >> 8) & mask) * scale;
445 
446     scale = 16 * suby - xy;
447     lo += (aroundPixels.color10 & mask) * scale;
448     hi += ((aroundPixels.color10 >> 8) & mask) * scale;
449 
450     lo += (aroundPixels.color11 & mask) * xy;
451     hi += ((aroundPixels.color11 >> 8) & mask) * xy;
452 
453     return ((lo >> 8) & mask) | (hi & ~mask);
454 }
455 } // namespace Media
456 } // namespace OHOS
457