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