1967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall/* 2967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Copyright (C) 2014 The Android Open Source Project 3967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 4967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Licensed under the Apache License, Version 2.0 (the "License"); 5967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * you may not use this file except in compliance with the License. 6967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * You may obtain a copy of the License at 7967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 8967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * http://www.apache.org/licenses/LICENSE-2.0 9967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * 10967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * Unless required by applicable law or agreed to in writing, software 11967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * distributed under the License is distributed on an "AS IS" BASIS, 12967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * See the License for the specific language governing permissions and 14967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall * limitations under the License. 15967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall */ 16967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include "jpegutil.h" 17967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include <memory.h> 18967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include <array> 19967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include <vector> 20967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include <cstring> 21967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include <cstdio> 22967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 23967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include <setjmp.h> 24967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 25967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallextern "C" { 26967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall#include "jpeglib.h" 27967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall} 28967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 29967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallusing namespace std; 307e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lallusing namespace jpegutil; 31967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 32967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lalltemplate <typename T> 33967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallvoid safeDelete(T& t) { 34967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall if (t != nullptr) { 35967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall delete t; 36967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall t = nullptr; 37967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 38967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall} 39967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 40967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lalltemplate <typename T> 41967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallvoid safeDeleteArray(T& t) { 42967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall if (t != nullptr) { 43967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall delete[] t; 44967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall t = nullptr; 45967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 46967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall} 47967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 487e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lalljpegutil::Transform::Transform(int orig_x, int orig_y, int one_x, int one_y) 497e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall : orig_x_(orig_x), orig_y_(orig_y), one_x_(one_x), one_y_(one_y) { 507e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall if (orig_x == one_x || orig_y == one_y) { 517e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // Handle the degenerate case of cropping to a 0x0 rectangle. 527e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat00_ = 0; 537e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat01_ = 0; 547e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat10_ = 0; 557e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat11_ = 0; 567e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return; 577e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } 58967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 597e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall if (one_x > orig_x && one_y > orig_y) { 607e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // 0-degree rotation 617e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat00_ = 1; 627e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat01_ = 0; 637e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat10_ = 0; 647e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat11_ = 1; 657e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_width_ = abs(one_x - orig_x); 667e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_height_ = abs(one_y - orig_y); 677e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } else if (one_x < orig_x && one_y > orig_y) { 687e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // 90-degree CCW rotation 697e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat00_ = 0; 707e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat01_ = -1; 717e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat10_ = 1; 727e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat11_ = 0; 737e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_width_ = abs(one_y - orig_y); 747e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_height_ = abs(one_x - orig_x); 757e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } else if (one_x > orig_x && one_y < orig_y) { 767e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // 270-degree CCW rotation 777e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat00_ = 0; 787e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat01_ = 1; 797e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat10_ = -1; 807e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat11_ = 0; 817e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_width_ = abs(one_y - orig_y); 827e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_height_ = abs(one_x - orig_x); 837e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } else if (one_x < orig_x && one_y < orig_y) { 847e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // 180-degree CCW rotation 857e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat00_ = -1; 867e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat01_ = 0; 877e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat10_ = 0; 887e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall mat11_ = -1; 897e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_width_ = abs(one_x - orig_x); 907e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall output_height_ = abs(one_y - orig_y); 917e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } 92967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall} 93967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 947e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lalljpegutil::Transform jpegutil::Transform::ForCropFollowedByRotation( 957e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cropLeft, int cropTop, int cropRight, int cropBottom, int rot90) { 967e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // The input crop-region excludes cropRight and cropBottom, so transform the 977e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // crop rect such that it defines the entire valid region of pixels 987e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // inclusively. 997e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cropRight -= 1; 1007e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cropBottom -= 1; 1017e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 1027e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cropXLow = min(cropLeft, cropRight); 1037e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cropYLow = min(cropTop, cropBottom); 1047e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cropXHigh = max(cropLeft, cropRight); 1057e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cropYHigh = max(cropTop, cropBottom); 1067e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall rot90 %= 4; 1077e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall if (rot90 == 0) { 1087e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1); 1097e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } else if (rot90 == 1) { 1107e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return Transform(cropXHigh, cropYLow, cropXLow - 1, cropYHigh + 1); 1117e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } else if (rot90 == 2) { 1127e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return Transform(cropXHigh, cropYHigh, cropXLow - 1, cropYLow - 1); 1137e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } else if (rot90 == 3) { 1147e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return Transform(cropXLow, cropYHigh, cropXHigh + 1, cropYLow - 1); 115967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 1167e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // Impossible case. 1177e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return Transform(cropXLow, cropYLow, cropXHigh + 1, cropYHigh + 1); 1187e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall} 119967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 1207e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lallbool jpegutil::Transform::operator==(const Transform& other) const { 1217e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return other.orig_x_ == orig_x_ && // 1227e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall other.orig_y_ == orig_y_ && // 1237e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall other.one_x_ == one_x_ && // 1247e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall other.one_y_ == one_y_; 125967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall} 126967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 1277e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall/** 1287e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall * Transforms the input coordinates. Coordinates outside the cropped region 1297e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall * are clamped to valid values. 1307e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall */ 1317e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lallvoid jpegutil::Transform::Map(int x, int y, int* x_out, int* y_out) const { 1327e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall x = max(x, 0); 1337e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall y = max(y, 0); 1347e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall x = min(x, output_width() - 1); 1357e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall y = min(y, output_height() - 1); 1367e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall *x_out = x * mat00_ + y * mat01_ + orig_x_; 1377e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall *y_out = x * mat10_ + y * mat11_ + orig_y_; 1387e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall} 139967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 1407e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lallint jpegutil::Compress(int img_width, int img_height, 1417e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall jpegutil::RowIterator<16>& y_row_generator, 1427e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall jpegutil::RowIterator<8>& cb_row_generator, 1437e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall jpegutil::RowIterator<8>& cr_row_generator, 1447e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall unsigned char* out_buf, size_t out_buf_capacity, 1457e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall std::function<void(size_t)> flush, int quality) { 146967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // libjpeg requires the use of setjmp/longjmp to recover from errors. Since 147967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // this doesn't play well with RAII, we must use pointers and manually call 148967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // delete. See POSIX documentation for longjmp() for details on why the 149967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // volatile keyword is necessary. 150967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall volatile jpeg_compress_struct cinfov; 151967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 152967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_compress_struct& cinfo = 153967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall *const_cast<struct jpeg_compress_struct*>(&cinfov); 154967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 155967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall JSAMPROW* volatile yArr = nullptr; 156967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall JSAMPROW* volatile cbArr = nullptr; 157967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall JSAMPROW* volatile crArr = nullptr; 158967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 159967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall JSAMPARRAY imgArr[3]; 160967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 161967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Error handling 162967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 163967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall struct my_error_mgr { 164967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall struct jpeg_error_mgr pub; 165967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jmp_buf setjmp_buffer; 166967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } err; 167967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 168967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.err = jpeg_std_error(&err.pub); 169967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 170967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Default error_exit will call exit(), so override 171967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // to return control via setjmp/longjmp. 172967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall err.pub.error_exit = [](j_common_ptr cinfo) { 173967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall my_error_mgr* myerr = reinterpret_cast<my_error_mgr*>(cinfo->err); 174967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 175967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall (*cinfo->err->output_message)(cinfo); 176967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 177967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Return control to the setjmp point (see call to setjmp()). 178967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall longjmp(myerr->setjmp_buffer, 1); 179967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall }; 180967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 181967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.err = (struct jpeg_error_mgr*)&err; 182967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 183967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Set the setjmp point to return to in case of error. 184967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall if (setjmp(err.setjmp_buffer)) { 185967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // If libjpeg hits an error, control will jump to this point (see call to 186967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // longjmp()). 187967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_destroy_compress(&cinfo); 188967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 189967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall safeDeleteArray(yArr); 190967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall safeDeleteArray(cbArr); 191967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall safeDeleteArray(crArr); 192967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 193967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall return -1; 194967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 195967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 196967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Create jpeg compression context 197967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_create_compress(&cinfo); 198967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 199967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Stores data needed by our c-style callbacks into libjpeg 200967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall struct ClientData { 2017e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall unsigned char* out_buf; 2027e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall size_t out_buf_capacity; 203967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall std::function<void(size_t)> flush; 204967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall int totalOutputBytes; 2057e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } clientData{out_buf, out_buf_capacity, flush, 0}; 206967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 207967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.client_data = &clientData; 208967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 209967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Initialize destination manager 210967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_destination_mgr dest; 211967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 212967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall dest.init_destination = [](j_compress_ptr cinfo) { 213967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data); 214967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 2157e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cinfo->dest->next_output_byte = cdata.out_buf; 2167e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cinfo->dest->free_in_buffer = cdata.out_buf_capacity; 217967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall }; 218967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 219967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall dest.empty_output_buffer = [](j_compress_ptr cinfo) -> boolean { 220967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall ClientData& cdata = *reinterpret_cast<ClientData*>(cinfo->client_data); 221967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 2227e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall size_t numBytesInBuffer = cdata.out_buf_capacity; 223967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cdata.flush(numBytesInBuffer); 224967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cdata.totalOutputBytes += numBytesInBuffer; 225967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 226967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Reset the buffer 2277e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cinfo->dest->next_output_byte = cdata.out_buf; 2287e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cinfo->dest->free_in_buffer = cdata.out_buf_capacity; 229967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 230967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall return true; 231967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall }; 232967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 233a5aa01058465e55324dacaa3915b5d8f5cd66e78Tomasz Wasilczyk dest.term_destination = [](j_compress_ptr cinfo __unused) { 234967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // do nothing to terminate the output buffer 235967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall }; 236967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 237967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.dest = &dest; 238967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 239967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Set jpeg parameters 2407e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cinfo.image_width = img_width; 2417e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cinfo.image_height = img_height; 242967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.input_components = 3; 243967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 244967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall // Set defaults based on the above values 245967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_set_defaults(&cinfo); 246967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 247967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_set_quality(&cinfo, quality, true); 248967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 249967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.dct_method = JDCT_IFAST; 250967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 251967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.raw_data_in = true; 252967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 253967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_set_colorspace(&cinfo, JCS_YCbCr); 254967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 255967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.comp_info[0].h_samp_factor = 2; 256967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.comp_info[0].v_samp_factor = 2; 257967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.comp_info[1].h_samp_factor = 1; 258967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.comp_info[1].v_samp_factor = 1; 259967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.comp_info[2].h_samp_factor = 1; 260967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cinfo.comp_info[2].v_samp_factor = 1; 261967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 262967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_start_compress(&cinfo, true); 263967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 264967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall yArr = new JSAMPROW[cinfo.comp_info[0].v_samp_factor * DCTSIZE]; 265967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall cbArr = new JSAMPROW[cinfo.comp_info[1].v_samp_factor * DCTSIZE]; 266967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall crArr = new JSAMPROW[cinfo.comp_info[2].v_samp_factor * DCTSIZE]; 267967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 268967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall imgArr[0] = const_cast<JSAMPARRAY>(yArr); 269967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall imgArr[1] = const_cast<JSAMPARRAY>(cbArr); 270967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall imgArr[2] = const_cast<JSAMPARRAY>(crArr); 271967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 2727e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall for (int y = 0; y < img_height; y += DCTSIZE * 2) { 2737e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall std::array<unsigned char*, 16> yData = y_row_generator.LoadAt(y); 2747e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall std::array<unsigned char*, 8> cbData = cb_row_generator.LoadAt(y / 2); 2757e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall std::array<unsigned char*, 8> crData = cr_row_generator.LoadAt(y / 2); 276967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 277967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall for (int row = 0; row < DCTSIZE * 2; row++) { 2787e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall yArr[row] = yData[row]; 279967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 280967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall for (int row = 0; row < DCTSIZE; row++) { 2817e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cbArr[row] = cbData[row]; 2827e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall crArr[row] = crData[row]; 283967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 284967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 285967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_write_raw_data(&cinfo, imgArr, DCTSIZE * 2); 286967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall } 287967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 288967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall jpeg_finish_compress(&cinfo); 289967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 2907e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int numBytesInBuffer = cinfo.dest->next_output_byte - out_buf; 291967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 292967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall flush(numBytesInBuffer); 293967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 294967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall clientData.totalOutputBytes += numBytesInBuffer; 295967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 296967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall safeDeleteArray(yArr); 297967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall safeDeleteArray(cbArr); 298967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall safeDeleteArray(crArr); 2997e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3007e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall jpeg_destroy_compress(&cinfo); 301967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall 302967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall return clientData.totalOutputBytes; 303967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall} 3047e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3057e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lallint jpegutil::Compress( 3067e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Input image dimensions */ 3077e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int width, int height, 3087e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Y Plane */ 3097e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall unsigned char* yBuf, int yPStride, int yRStride, 3107e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Cb Plane */ 3117e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall unsigned char* cbBuf, int cbPStride, int cbRStride, 3127e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Cr Plane */ 3137e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall unsigned char* crBuf, int crPStride, int crRStride, 3147e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Output */ 3157e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall unsigned char* outBuf, size_t outBufCapacity, 3167e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Jpeg compression parameters */ 3177e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int quality, 3187e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Crop */ 3197e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cropLeft, int cropTop, int cropRight, int cropBottom, 3207e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall /** Rotation (multiple of 90). For example, rot90 = 1 implies a 90 degree 3217e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall * rotation. */ 3227e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int rot90) { 3237e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int finalWidth; 3247e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int finalHeight; 3257e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall finalWidth = cropRight - cropLeft; 3267e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall finalHeight = cropBottom - cropTop; 3277e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3287e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall rot90 %= 4; 3297e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // for 90 and 270-degree rotations, flip the final width and height 3307e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall if (rot90 == 1) { 3317e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall finalWidth = cropBottom - cropTop; 3327e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall finalHeight = cropRight - cropLeft; 3337e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } else if (rot90 == 3) { 3347e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall finalWidth = cropBottom - cropTop; 3357e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall finalHeight = cropRight - cropLeft; 3367e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall } 3377e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3387e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall const Plane yP = {width, height, yBuf, yPStride, yRStride}; 3397e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall const Plane cbP = {width / 2, height / 2, cbBuf, cbPStride, cbRStride}; 3407e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall const Plane crP = {width / 2, height / 2, crBuf, crPStride, crRStride}; 3417e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 342a5aa01058465e55324dacaa3915b5d8f5cd66e78Tomasz Wasilczyk auto flush = [](size_t numBytes __unused) { 3437e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // do nothing 3447e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall }; 3457e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3467e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall // Round up to the nearest multiple of 64. 3477e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int y_row_length = (finalWidth + 16 + 63) & ~63; 3487e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cb_row_length = (finalWidth / 2 + 16 + 63) & ~63; 3497e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall int cr_row_length = (finalWidth / 2 + 16 + 63) & ~63; 3507e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3517e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall Transform yTrans = Transform::ForCropFollowedByRotation( 3527e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cropLeft, cropTop, cropRight, cropBottom, rot90); 3537e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3547e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall Transform chromaTrans = Transform::ForCropFollowedByRotation( 3557e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall cropLeft / 2, cropTop / 2, cropRight / 2, cropBottom / 2, rot90); 3567e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3577e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall RowIterator<16> yIter(yP, yTrans, y_row_length); 3587e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall RowIterator<8> cbIter(cbP, chromaTrans, cb_row_length); 3597e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall RowIterator<8> crIter(crP, chromaTrans, cr_row_length); 3607e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall 3617e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall return Compress(finalWidth, finalHeight, yIter, cbIter, crIter, outBuf, 3627e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall outBufCapacity, flush, quality); 3637e744b14ab0657d5e766d6313255eed6dd6eab2aPuneet Lall} 364