2 * Copyright (C) 2014 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
27 * Provides a wrapper around libjpeg.
34 inline int sgn(int val) { return (0 < val) - (val < 0); }
36 inline int min(int a, int b) { return a < b ? a : b; }
38 inline int max(int a, int b) { return a > b ? a : b; }
41 * Represents a combined cropping and rotation transformation.
43 * The transformation maps the coordinates (orig_x, orig_y) and (one_x, one_y)
44 * in the input image to the origin and (output_width, output_height)
49 Transform(int orig_x, int orig_y, int one_x, int one_y);
51 static Transform ForCropFollowedByRotation(int cropLeft, int cropTop,
52 int cropRight, int cropBottom,
55 inline int output_width() const { return output_width_; }
57 inline int output_height() const { return output_height_; }
59 bool operator==(const Transform& other) const;
62 * Transforms the input coordinates. Coordinates outside the cropped region
63 * are clamped to valid values.
65 void Map(int x, int y, int* x_out, int* y_out) const;
71 // The coordinates of the point to map the origin to.
72 const int orig_x_, orig_y_;
73 // The coordinates of the point to map the point (output_width(),
74 // output_height()) to.
75 const int one_x_, one_y_;
77 // A matrix for the rotational component.
83 * Represents a model for accessing pixel data for a single plane of an image.
84 * Note that the actual data is not owned by this class, and the underlying
85 * data does not need to be stored in separate planes.
88 // The dimensions of this plane of the image
92 // A pointer to raw pixel data
93 const unsigned char* data;
94 // The difference in address between consecutive pixels in the same row
96 // The difference in address between the start of consecutive rows
101 * Provides an interface for simultaneously reading a certain number of rows of
102 * an image plane as contiguous arrays, suitable for use with libjpeg.
104 template <unsigned int ROWS>
108 * Creates a new RowIterator which will crop and rotate with the given
111 * @param plane the plane to iterate over
112 * @param transform the transformation to map output values into the
113 * coordinate space of the plane
114 * @param row_length the length of the rows returned via LoadAt(). If this is
115 * longer than the width of the output (after applying the transform), then
116 * the right-most value is repeated.
118 inline RowIterator(Plane plane, Transform transform, int row_length);
121 * Returns an array of pointers into consecutive rows of contiguous image
122 * data starting at y. That is, samples within each row are contiguous.
123 * However, the individual arrays pointed-to may be separate.
124 * When the end of the image is reached, the last row of the image is
126 * The returned pointers are valid until the next call to LoadAt().
128 inline const std::array<unsigned char*, ROWS> LoadAt(int y_base);
132 Transform transform_;
133 // The length of a row, with padding to the next multiple of 64.
134 int padded_row_length_;
135 std::vector<unsigned char> buf_;
139 * Compresses an image from YUV 420p to JPEG. Output is buffered in outBuf until
140 * capacity is reached, at which point flush(size_t) is called to write
141 * out the specified number of bytes from outBuf. Returns the number of bytes
142 * written, or -1 in case of an error.
144 int Compress(int img_width, int img_height, RowIterator<16>& y_row_generator,
145 RowIterator<8>& cb_row_generator, RowIterator<8>& cr_row_generator,
146 unsigned char* out_buf, size_t out_buf_capacity,
147 std::function<void(size_t)> flush, int quality);
150 * Compresses an image from YUV 420p to JPEG. Output is written into outBuf.
151 * Returns the number of bytes written, or -1 in case of an error.
154 /** Input image dimensions */
155 int width, int height,
157 unsigned char* yBuf, int yPStride, int yRStride,
159 unsigned char* cbBuf, int cbPStride, int cbRStride,
161 unsigned char* crBuf, int crPStride, int crRStride,
163 unsigned char* outBuf, size_t outBufCapacity,
164 /** Jpeg compression parameters */
167 int cropLeft, int cropTop, int cropRight, int cropBottom,
172 template <unsigned int ROWS>
173 jpegutil::RowIterator<ROWS>::RowIterator(Plane plane, Transform transform,
175 : plane_(plane), transform_(transform) {
176 padded_row_length_ = row_length;
177 buf_ = std::vector<unsigned char>(row_length * ROWS);
180 template <unsigned int ROWS>
181 const std::array<unsigned char*, ROWS> jpegutil::RowIterator<ROWS>::LoadAt(
183 std::array<unsigned char*, ROWS> buf_ptrs;
184 for (int i = 0; i < ROWS; i++) {
185 buf_ptrs[i] = &buf_[padded_row_length_ * i];
188 if (plane_.width == 0 || plane_.height == 0) {
192 for (int i = 0; i < ROWS; i++) {
194 y = min(y, transform_.output_height() - 1);
196 int output_width = padded_row_length_;
197 output_width = min(output_width, transform_.output_width());
198 output_width = min(output_width, plane_.width);
200 // Each row in the output image will be copied into buf_ by gathering pixels
201 // along an axis-aligned line in the plane.
202 // The line is defined by (startX, startY) -> (endX, endY), computed via the
203 // current Transform.
206 transform_.Map(0, y, &startX, &startY);
210 transform_.Map(output_width - 1, y, &endX, &endY);
212 // Clamp (startX, startY) and (endX, endY) to the valid bounds of the plane.
213 startX = min(startX, plane_.width - 1);
214 startY = min(startY, plane_.height - 1);
215 endX = min(endX, plane_.width - 1);
216 endY = min(endY, plane_.height - 1);
217 startX = max(startX, 0);
218 startY = max(startY, 0);
222 // To reduce work inside the copy-loop, precompute the start, end, and
223 // stride relating the values to be gathered from plane_ into buf
224 // for this particular scan-line.
225 int dx = sgn(endX - startX);
226 int dy = sgn(endY - startY);
227 assert(dx == 0 || dy == 0);
228 // The index into plane_.data of (startX, startY)
229 int plane_start = startX * plane_.pixel_stride + startY * plane_.row_stride;
230 // The index into plane_.data of (endX, endY)
231 int plane_end = endX * plane_.pixel_stride + endY * plane_.row_stride;
232 // The stride, in terms of indices in plane_data, required to enumerate the
233 // samples between the start and end points.
234 int stride = dx * plane_.pixel_stride + dy * plane_.row_stride;
235 // In the degenerate-case of a 1x1 plane, startX and endX are equal, so
236 // stride would be 0, resulting in an infinite-loop. To avoid this case,
237 // use a stride of at-least 1.
243 for (int idx = plane_start; idx >= min(plane_start, plane_end) &&
244 idx <= max(plane_start, plane_end);
246 buf_ptrs[i][outX] = plane_.data[idx];
250 // Fill the remaining right-edge of the buffer by extending the last
252 unsigned char right_padding_value = buf_ptrs[i][outX - 1];
253 // TODO OPTIMIZE Use memset instead.
254 for (; outX < padded_row_length_; outX++) {
255 buf_ptrs[i][outX] = right_padding_value;