Enable PPAPI tests for non-SFI mode.
[chromium-blink-merge.git] / chrome / utility / cloud_print / pwg_encoder.cc
blobc4aeded2e34f72d833e949217099478af4e28dfe
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/utility/cloud_print/pwg_encoder.h"
7 #include <algorithm>
9 #include "base/big_endian.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "chrome/utility/cloud_print/bitmap_image.h"
14 namespace cloud_print {
16 namespace {
18 const uint32 kBitsPerColor = 8;
19 const uint32 kColorSpace = 19; // sRGB.
20 const uint32 kColorOrder = 0; // chunky.
21 const uint32 kNumColors = 3;
22 const uint32 kBitsPerPixel = kNumColors * kBitsPerColor;
24 const char kPwgKeyword[] = "RaS2";
26 const uint32 kHeaderSize = 1796;
27 const uint32 kHeaderHwResolutionHorizontal = 276;
28 const uint32 kHeaderHwResolutionVertical = 280;
29 const uint32 kHeaderCupsWidth = 372;
30 const uint32 kHeaderCupsHeight = 376;
31 const uint32 kHeaderCupsBitsPerColor = 384;
32 const uint32 kHeaderCupsBitsPerPixel = 388;
33 const uint32 kHeaderCupsBytesPerLine = 392;
34 const uint32 kHeaderCupsColorOrder = 396;
35 const uint32 kHeaderCupsColorSpace = 400;
36 const uint32 kHeaderCupsNumColors = 420;
37 const uint32 kHeaderPwgTotalPageCount = 452;
39 const int kPwgMaxPackedRows = 256;
41 const int kPwgMaxPackedPixels = 128;
43 inline int FlipIfNeeded(bool flip, int current, int total) {
44 return flip ? total - current : current;
47 } // namespace
49 PwgEncoder::PwgEncoder() {}
51 inline void encodePixelFromRGBA(const uint8* pixel, std::string* output) {
52 output->push_back(static_cast<char>(pixel[0]));
53 output->push_back(static_cast<char>(pixel[1]));
54 output->push_back(static_cast<char>(pixel[2]));
57 inline void encodePixelFromBGRA(const uint8* pixel, std::string* output) {
58 output->push_back(static_cast<char>(pixel[2]));
59 output->push_back(static_cast<char>(pixel[1]));
60 output->push_back(static_cast<char>(pixel[0]));
63 void PwgEncoder::EncodeDocumentHeader(std::string* output) const {
64 output->clear();
65 output->append(kPwgKeyword, 4);
68 void PwgEncoder::EncodePageHeader(const BitmapImage& image, const uint32 dpi,
69 const uint32 total_pages,
70 std::string* output) const {
71 char header[kHeaderSize];
72 memset(header, 0, kHeaderSize);
73 base::WriteBigEndian<uint32>(header + kHeaderHwResolutionHorizontal, dpi);
74 base::WriteBigEndian<uint32>(header + kHeaderHwResolutionVertical, dpi);
75 base::WriteBigEndian<uint32>(header + kHeaderCupsWidth, image.size().width());
76 base::WriteBigEndian<uint32>(header + kHeaderCupsHeight,
77 image.size().height());
78 base::WriteBigEndian<uint32>(header + kHeaderCupsBitsPerColor, kBitsPerColor);
79 base::WriteBigEndian<uint32>(header + kHeaderCupsBitsPerPixel, kBitsPerPixel);
80 base::WriteBigEndian<uint32>(header + kHeaderCupsBytesPerLine,
81 (kBitsPerPixel * image.size().width() + 7) / 8);
82 base::WriteBigEndian<uint32>(header + kHeaderCupsColorOrder, kColorOrder);
83 base::WriteBigEndian<uint32>(header + kHeaderCupsColorSpace, kColorSpace);
84 base::WriteBigEndian<uint32>(header + kHeaderCupsNumColors, kNumColors);
85 base::WriteBigEndian<uint32>(header + kHeaderPwgTotalPageCount, total_pages);
86 output->append(header, kHeaderSize);
89 bool PwgEncoder::EncodeRowFrom32Bit(const uint8* row, const int width,
90 const int color_space,
91 std::string* output) const {
92 void (*pixel_encoder)(const uint8*, std::string*);
93 switch (color_space) {
94 case BitmapImage::RGBA:
95 pixel_encoder = &encodePixelFromRGBA;
96 break;
97 case BitmapImage::BGRA:
98 pixel_encoder = &encodePixelFromBGRA;
99 break;
100 default:
101 LOG(ERROR) << "Unsupported colorspace.";
102 return false;
105 // Converts the list of uint8 to uint32 as every pixels contains 4 bytes
106 // of information and comparison of elements is easier. The actual management
107 // of the bytes of the pixel is done by template function P on the original
108 // array to avoid endian problems.
109 const uint32* pos = reinterpret_cast<const uint32*>(row);
110 const uint32* row_end = pos + width;
111 // According to PWG-raster, a sequence of N identical pixels (up to 128)
112 // can be encoded by a byte N-1, followed by the information on
113 // that pixel. Any generic sequence of N pixels (up to 128) can be encoded
114 // with (signed) byte 1-N, followed by the information on the N pixels.
115 // Notice that for sequences of 1 pixel there is no difference between
116 // the two encodings.
118 // It is usually better to encode every largest sequence of > 2 identical
119 // pixels together because it saves the most space. Every other pixel should
120 // be encoded in the smallest number of generic sequences.
121 while (pos != row_end) {
122 const uint32* it = pos + 1;
123 const uint32* end = std::min(pos + kPwgMaxPackedPixels, row_end);
125 // Counts how many identical pixels (up to 128).
126 while (it != end && *pos == *it) {
127 it++;
129 if (it != pos + 1) { // More than one pixel
130 output->push_back(static_cast<char>((it - pos) - 1));
131 pixel_encoder(reinterpret_cast<const uint8*>(pos), output);
132 pos = it;
133 } else {
134 // Finds how many pixels each different from the previous one (up to 128).
135 while (it != end && *it != *(it - 1)) {
136 it++;
138 // Optimization: ignores the last pixel of the sequence if it is followed
139 // by an identical pixel, as it is more convenient for it to be the start
140 // of a new sequence of identical pixels. Notice that we don't compare
141 // to end, but row_end.
142 if (it != row_end && *it == *(it - 1)) {
143 it--;
145 output->push_back(static_cast<char>(1 - (it - pos)));
146 while (pos != it) {
147 pixel_encoder(reinterpret_cast<const uint8*>(pos++), output);
151 return true;
154 inline const uint8* PwgEncoder::GetRow(const BitmapImage& image,
155 int row) const {
156 return image.pixel_data() + row * image.size().width() * image.channels();
159 // Given a pointer to a struct Image, create a PWG of the image and
160 // put the compressed image data in the std::string. Returns true on success.
161 // The content of the std::string is undefined on failure.
162 bool PwgEncoder::EncodePage(const BitmapImage& image,
163 const uint32 dpi,
164 const uint32 total_pages,
165 std::string* output,
166 bool rotate) const {
167 // For now only some 4-channel colorspaces are supported.
168 if (image.channels() != 4) {
169 LOG(ERROR) << "Unsupported colorspace.";
170 return false;
173 EncodePageHeader(image, dpi, total_pages, output);
175 int row_size = image.size().width() * image.channels();
176 scoped_ptr<uint8[]> current_row_cpy(new uint8[row_size]);
178 int row_number = 0;
179 int total_rows = image.size().height();
180 while (row_number < total_rows) {
181 const uint8* current_row =
182 GetRow(image, FlipIfNeeded(rotate, row_number++, total_rows));
183 int num_identical_rows = 1;
184 // We count how many times the current row is repeated.
185 while (num_identical_rows < kPwgMaxPackedRows &&
186 row_number < image.size().height() &&
187 !memcmp(current_row,
188 GetRow(image, FlipIfNeeded(rotate, row_number, total_rows)),
189 row_size)) {
190 num_identical_rows++;
191 row_number++;
193 output->push_back(static_cast<char>(num_identical_rows - 1));
195 if (rotate) {
196 memcpy(current_row_cpy.get(), current_row, row_size);
197 std::reverse(reinterpret_cast<uint32*>(current_row_cpy.get()),
198 reinterpret_cast<uint32*>(current_row_cpy.get() + row_size));
199 current_row = current_row_cpy.get();
202 // Both supported colorspaces have a 32-bit pixels information.
203 if (!EncodeRowFrom32Bit(
204 current_row, image.size().width(), image.colorspace(), output)) {
205 return false;
208 return true;
211 } // namespace cloud_print